[bug] cbi optimization error for 8-bit AVRs

Szikra István <[email protected]>
Newsgroups gmane.comp.hardware.avr.gcc
Message-ID <[email protected]>
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...);
}

int main(void)
{
	DDRB = 0x0f;
	for(;;) {
		PORTB |= bits(4);
		PORTB &=~bits(4);

		PORTB |= (1<<4);
		PORTB &=~(1<<4);
	}
}

It’s compiled with avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.4_1229) 4.8.1 
(Atmel Studio 6.2):
avr-gcc -c -mmcu=attiny13 -I. -x c++ -gdwarf-2 -DF_CPU=9600000UL -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums 
-fno-exceptions -Wall -Wundef -fno-strict-aliasing -Winline 
-fno-inline-small-functions  -fno-default-inline -save-temps 
-Wa,-adhlns=./test.lst -ID:/Lib/ -std=gnu++11 -MMD -MP -MF .dep/test.o.d 
test.cpp -o test.o

My older compiler versions do not support -std=gnu++11.  By the way, 
does anyone know when Atmel is coming out with GCC 4.8.3 version for AVR?

----
Here is the preproc output:
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...);
}

int main(void)
{
  (*(volatile uint8_t *)((0x17) + 0x20)) = 0x0f;
  for(;;) {
   (*(volatile uint8_t *)((0x18) + 0x20)) |= bits(4);
   (*(volatile uint8_t *)((0x18) + 0x20)) &=~bits(4);

   (*(volatile uint8_t *)((0x18) + 0x20)) |= (1<<4);
   (*(volatile uint8_t *)((0x18) + 0x20)) &=~(1<<4);
  }
}

----
Assembly list file (relevant part only):
   19:test.cpp      **** 	for(;;) {
   20:test.cpp      **** 		PORTB |= bits(4);
   26               		.loc 1 20 0 discriminator 1
   27 0004 C49A      		sbi 0x18,4
   28               	.LVL1:
   21:test.cpp      **** 		PORTB &=~bits(4);
   29               		.loc 1 21 0 discriminator 1
   30 0006 88B3      		in r24,0x18
   31 0008 90E0      		ldi r25,0
   32 000a 8F7E      		andi r24,239
   33 000c 88BB      		out 0x18,r24
   22:test.cpp      ****
   23:test.cpp      **** 		PORTB |= (1<<4);
   34               		.loc 1 23 0 discriminator 1
   35 000e C49A      		sbi 0x18,4
   24:test.cpp      **** 		PORTB &=~(1<<4);
   36               		.loc 1 24 0 discriminator 1
   37 0010 C498      		cbi 0x18,4


and the objdump (in case someone likes it better, like me)
	for(;;) {
		PORTB |= bits(4);
   26:	c4 9a       	sbi	0x18, 4	; 24
		PORTB &=~bits(4);
   28:	88 b3       	in	r24, 0x18	; 24
   2a:	90 e0       	ldi	r25, 0x00	; 0	<---WTF?
   2c:	8f 7e       	andi	r24, 0xEF	; 239
   2e:	88 bb       	out	0x18, r24	; 24

		PORTB |= (1<<4);
   30:	c4 9a       	sbi	0x18, 4	; 24
		PORTB &=~(1<<4);
   32:	c4 98       	cbi	0x18, 4	; 24
   34:	f8 cf       	rjmp	.-16     	; 0x26 <main+0x4>


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.