https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77543

            Bug ID: 77543
           Summary: ARM: G++ generates redundant instructions at -O0
           Product: gcc
           Version: 5.4.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mh at ashwireless dot com
  Target Milestone: ---

(This is using the 2016q2 release of the ARM toolchain, GCC 5.4.1).

Use first arm-none-eabi-gcc and then arm-none-eabi-g++ to compile this code
(without any optimisation i.e. -O0):

-------------------------
void doStuff(void);
int getNum(void);

void compare1(int n)
{
    if(n > 33)
    {
        doStuff();
    }
    if(getNum() > 44)
    {
        doStuff();
    }
}
--------------------------

GCC generates pretty much what I'd expect:

  27 0010 08301BE5 ldr  r3, [fp, #-8]
  28 0014 210053E3 cmp  r3, #33
  29 0018 000000DA ble  .L2
  30 001c FEFFFFEB bl   doStuff
  31 .L2:
  32 0020 FEFFFFEB bl   getNum
  33 0024 0030A0E1 mov  r3, r0
  34 0028 2C0053E3 cmp  r3, #44
  35 002c 000000DA ble  .L4
  36 0030 FEFFFFEB bl   doStuff
  37 .L4:

But from G++:

  32 0010 08301BE5 ldr  r3, [fp, #-8]
  33 0014 210053E3 cmp  r3, #33
  34 0018 000000DA ble  .L2
  35 001c FEFFFFEB bl   _Z8doStuffv
  36 .L2:
  37 0020 FEFFFFEB bl   _Z6getNumv
  38 0024 0030A0E1 mov  r3, r0
  39 0028 2C0053E3 cmp  r3, #44
  40 002c 0130A0C3 movgt        r3, #1 ; if >44, set flag = 1 
  41 0030 0030A0D3 movle        r3, #0 ; if <=44, set flag = 0 
  42 0034 FF3003E2 and  r3, r3, #255   ; treat as a byte
  43 0038 000053E3 cmp  r3, #0         ; compare flag == 0?
  44 003c 0000000A beq  .L4
  45 0040 FEFFFFEB bl   _Z8doStuffv
  46 .L4:

Similar constructions are generated for Thumb and Thumb-2 instruction-sets.
So the bug occurs only if compiling as C++, and only when testing a value
returned from a function.

It seems to be using a uint8_t as a flag, initially setting it true, changing
it to false if the condition is not met, then zero-extending the uint8_t to 32
bits before jumping based on its value - 7 instructions instead of 2 (and using
an extra register). So two questions - why is it using a flag at all, and why
is the flag handled as a byte rather than a word?

The redundant instructions disappear if I enable optimisation O1 or Og, but it
would be better not to generate them in the first place.

Reply via email to