integer promotion difference between gnu11 and gnu++11

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

I read a few of the previous discussions on integer promotion, and none of them mentioned differences between avr-gcc (5.4.0) in gnu11 and gnu++11 modes (the default for avr-gcc and avr-g++).

When compiled with -Os as a C program, it optimizes the right shift to a single lsr.

#include <avr/io.h>

int main()
{
    uint8_t x = PORTB;
    x >>= 1;
    PORTB = x;
}

However as a C++ program (.cpp instead of .c), x gets promoted to signed int.

      in      r24, 0x18
      ldi     r25, 0x00
      asr     r25
      ror     r24
      out     0x18, r24

I've tried various combinations of casting, anding with 0xFF, and with 0x7F before shifting, all to no avail.  The only thing that worked was resorting to inline asm for the right shift.

asm ("lsr %0" : "+r"(x));

I thought both the C11 and C++11 standards specify the integer promotion, and how a compiler optimizes is implementation defined, but I was quite surprised that avr-gcc only does it the optimal way for C.

For portability and maintainability reasons I'd rather not use inline asm, so if anyone knows how to coerce avr-g++ to compile the left shift to "lsr", I'd like to know how.

 

This topic has a solution.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

Last Edited: Mon. Feb 10, 2020 - 02:18 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Yeah, I found this too some time back. The only workaround I could find was using division instead of shift.

#include <avr/io.h>

int main()
{
    uint8_t x = PORTB;
    x /= 2;
    PORTB = x;
}

 

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

El Tangas wrote:

Yeah, I found this too some time back. The only workaround I could find was using division instead of shift.

#include <avr/io.h>

int main()
{
    uint8_t x = PORTB;
    x /= 2;
    PORTB = x;
}

 

That works perfectly.  I vaguely remember reading a past post you made suggesting division instead of shift, but didn't remember to try it.  I don't think anyone mentioned it's only an issue for C++.

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

I infer that the C++ optimizer has fallen down on the job.

That said, it produces the same result as the C optimizer.

 

The current rule for promoting low-ranked integer types is that types smaller

than int and lower-ranked signed types the same size as int are promoted to int.

Other promotions are to unsigned int.

 

Iluvatar is the better part of Valar.

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


ralphd wrote:

  I don't think anyone mentioned it's only an issue for C++.

 

Is it a coincidence that there are 219 forum thread results for "c++ bloat"?

 

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

skeeve wrote:

I infer that the C++ optimizer has fallen down on the job.

That said, it produces the same result as the C optimizer.

 

The current rule for promoting low-ranked integer types is that types smaller

than int and lower-ranked signed types the same size as int are promoted to int.

Other promotions are to unsigned int.

 

 

I did some more research, and it might not be a difference in the optimizer.  gnu11 mode may be omitting the promotion altogether, as is allowed by the standard (pg 15):

"the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable tointsizeand then add the twoints and truncate the sum. Provided the addition of twochars can be done withoutoverflow, or with overflow wrapping silently to produce the correct result, the actual execution need onlyproduce the same result, possibly omitting the promotions. "

http://www.open-std.org/jtc1/sc2...

 

I've yet to dig through the c++11 standard, but read a couple posts from others that claim the promotion is mandatory in C++.  That still doesn't explain why x /= 2 generates lsr and x >>= 1 does not.

 

 

 

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
That still doesn't explain why x /= 2 generates lsr and x >>= 1 does not.

 

Be careful, they might decide it's a bug and "fix" /=2 angry

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

Is there a mode where some compilers will list "what it's doing"...so as you read the source code it will indicate (with the integrated compiler commentary) what was/was not promoted & other things it has done.  For example, if it eliminates a variable (due to optimizer assuming it never varies, or a conditional that can never be true), it could so indicate.   If some code was unrolled, it could say that too.  Perhaps this would become to too messy, but interesting.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

theusch wrote:
ralphd wrote:

 

  I don't think anyone mentioned it's only an issue for C++.

 

 

 

Is it a coincidence that there are 219 forum thread results for "c++ bloat"?

More precisely,

it's an issue for the particular C++ compiler.

C++ does not require the complained-of bloat.

Iluvatar is the better part of Valar.