Bad optimization for 4-bit shift, g++ only ??

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there something I'm not understanding about C++ ? I have a trivial program:

extern void foo(unsigned char c);
extern void bar(int c);

extern unsigned char c;

int main()
{
    foo(c>>4);
    bar(c>>4);
}

If I compile with avr-gcc I get the expected optimization using SWAP:

gcc --version
i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)

 avr-gcc -Os -g -mmcu=atmega8 -c -o shift.o shift.c
BillW-MacOSX-2<1155> avr-objdump -S shift.o

00000000 
: extern unsigned char c; int main() { foo(c>>4); 0: 80 91 00 00 lds r24, 0x0000 4: 82 95 swap r24 6: 8f 70 andi r24, 0x0F ; 15 8: 00 d0 rcall .+0 ; 0xa bar(c>>4); a: 80 91 00 00 lds r24, 0x0000 e: 82 95 swap r24 10: 8f 70 andi r24, 0x0F ; 15 12: 90 e0 ldi r25, 0x00 ; 0 14: 00 d0 rcall .+0 ; 0x16 } 16: 08 95 ret

If I compile the SAME FILE using g++, it apparently does the promotion to int much earlier, and generates much bulkier and slower code:

g++ --version
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5493)

 avr-g++ -Os -g -mmcu=atmega8 -c -o shift.o 

avr-objdump -S shift.o

00000000 
: extern unsigned char c; int main() { foo(c>>4); 0: 80 91 00 00 lds r24, 0x0000 4: 82 95 swap r24 6: 8f 70 andi r24, 0x0F ; 15 8: 00 d0 rcall .+0 ; 0xa bar(c>>4); a: 80 91 00 00 lds r24, 0x0000 e: 90 e0 ldi r25, 0x00 ; 0 10: 24 e0 ldi r18, 0x04 ; 4 12: 96 95 lsr r25 14: 87 95 ror r24 16: 2a 95 dec r18 18: 01 f4 brne .+0 ; 0x1a 1a: 00 d0 rcall .+0 ; 0x1c } 1c: 80 e0 ldi r24, 0x00 ; 0 1e: 90 e0 ldi r25, 0x00 ; 0 20: 08 95 ret

Is this expected? Is it bug-worthy ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is what happens on Windows using WinAVR:

D:\test>avr-g++ -Os -g -mmcu=atmega8 -c test.c -o test.o

D:\test>avr-objdump -S test.o

test.o:     file format elf32-avr


Disassembly of section .text:

00000000 
: extern unsigned char c; int main() { foo(c>>4); 0: 80 91 00 00 lds r24, 0x0000 4: 82 95 swap r24 6: 8f 70 andi r24, 0x0F ; 15 8: 00 d0 rcall .+0 ; 0xa bar(c>>4); a: 80 91 00 00 lds r24, 0x0000 e: 90 e0 ldi r25, 0x00 ; 0 10: 24 e0 ldi r18, 0x04 ; 4 12: 96 95 lsr r25 14: 87 95 ror r24 16: 2a 95 dec r18 18: 01 f4 brne .+0 ; 0x1a 1a: 00 d0 rcall .+0 ; 0x1c } 1c: 80 e0 ldi r24, 0x00 ; 0 1e: 90 e0 ldi r25, 0x00 ; 0 20: 08 95 ret

I'd therefore check your toolchain.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'd therefore check your toolchain.

huh? You show the same "bad" results that I got...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry I was looking at the first swap. Missed the point you were making. :oops:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The same for avr-g++ 4.3.4 in Ubuntu/x64 10.04

wbr, ReAl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Is this expected? Is it bug-worthy ?

Hmmm--perhaps the c compiler is the "bug worthy" one. Or neither. Or both.

There have been some detailed discussions here on promotion. As I recall, right-shift of a signed quantity is indeed a topic for discussion.

I always say "give the compiler writer a chance". Do you really intend/need to right-shift a signed quantity? Do you get the same results with unsigned?

I'll leave to the purists the topic of whether to treat char c as a signed or unsigned.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Quote:

Is this expected? Is it bug-worthy ?

Hmmm--perhaps the c compiler is the "bug worthy" one. Or neither. Or both.

There have been some detailed discussions here on promotion. As I recall, right-shift of a signed quantity is indeed a topic for discussion.

I always say "give the compiler writer a chance". Do you really intend/need to right-shift a signed quantity? Do you get the same results with unsigned?

I'll leave to the purists the topic of whether to treat char c as a signed or unsigned.

In this case, it doesn't matter.
OP has no plain chars.
With avr-g++, INT_MAX>=UCHAR_MAX,
therefore an unsigned char will never be promoted to a negative int.
Right shift of a non-negative signed quantity is a fairly dull topic of discussion.

Regardless of what the compiler should have done,
it should have done the same thing both times.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It seems that the compiler just make 4 ASR for signed char, and not the faster swap.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
It seems that the compiler just make 4 ASR for signed char, and not the faster swap.
What signed char?

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The same thing happens if the prototype for bar() is changed to specify an unsigned int for the argument. If any "issues" with signed right shift are involved, then tha's a bug all by itself.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
sparrow2 wrote:
It seems that the compiler just make 4 ASR for signed char, and not the faster swap.
What signed char?

It was just to see how general the swap was used!