Re: [bug] cbi optimization error for 8-bit AVRs

Szikra István <[email protected]>
Newsgroups gmane.comp.hardware.avr.gcc
Message-ID <[email protected]>
On 2014.11.08. 13:48, David Brown wrote:
> On 08/11/14 01:32, Szikra István wrote:
>> Hi everyone!
>>
>> My problem in sort: I’m getting
>>      in    r24, 0x18
>>      ldi    r25, 0x00
>>      andi    r24, 0xEF
>>      out    0x18, r24
>> instead of
>>      cbi    0x18, 4
>> .
>>
>> I’m trying to write efficient modern C/C++ code for multiple platforms
>> including AVR 8 bit controllers.
>>
>> Unfortunately GCC support for AVR (among other things) is not always
>> flawless. And it changes from versions to version (and not always for
>> the better).
>> Since I’m a long time AVR developer I have a lot of compiler versions
>> installed (WinAVR 2006-2010, and Atmel Studio 6.2 with GCC 4.8.1), but I
>> could test my code with only one (the latest).
>>
>> I run into some trouble with clearing port bits not translating from C
>> into cbi in assembler. It is caused by my bits template, but I do not
>> know why. It seems to me like a bug in GCC. Maybe someone here can shed
>> some light on the reason, or suggest a fix.
>>
>> Here is the code:
>>
>> #include <avr/io.h>
>> //#include <bits.hpp>
>>
>> template<typename T>
>> constexpr unsigned int bits(T idx1)
>> {
>>      return (1<<idx1);
>> }
>> template <typename T, typename... Rest>
>> constexpr unsigned int bits(T idx1, Rest... r)
>> {
>>      return (1<<idx1) | bits(r...);
>> }
>>
>
> Just an idea that might be worth trying - try replacing the "unsigned
> int" return type with "uint8_t" (/always/ use <stdint.h> types with
> defined bit sizes!).  AVR gcc has quite a number of optimisations and
> special case patterns for dealing with 8-bit types, especially uint8_t,
> and it often gives tighter code if you've used uint8_t even if uint16_t
> gives the same actual values.

Thanks, I have already tried using unsigned char return type, and also 
casting it. It did not help.
		PORTB &=~ (uint8_t)bits(4);
   28:	88 b3       	in	r24, 0x18	; 24
   2a:	90 e0       	ldi	r25, 0x00	; 0
   2c:	8f 7e       	andi	r24, 0xEF	; 239
   2e:	88 bb       	out	0x18, r24	; 24

But, what helped was casting the result of ~:
		PORTB &= (uint8_t)~bits(4);
   28:	c4 98       	cbi	0x18, 4	; 24


>
> Secondly, consider making your templates based on the value of idx1
> rather than the type - the type will always be an int (or promoted to an
> int in the shift expression).  Alternatively, drop the template entirely.

Yeah, I just replaced the bits(idx) with (1<<idx) in my code, till the 
bug is fixed. Now I'm changing it to casting...
_port &= (unsigned char)~bits(_index);

What do you mean by basing the template on the value of idx1?
I'm still new to templates. Actually I don't need T at all.

constexpr unsigned int bits(int idx1)
{
     return (1<<idx1);
}
template <typename... Rest>
constexpr unsigned int bits(int idx1, Rest... r)
{
     return (1<<idx1) | bits(r...);
}


Regards,
Steven
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.