Wind River Support Network

HomeDefectsLIN6-8302
Fixed

LIN6-8302 : Compiler bug - produces wrong assembly code

Created: Sep 2, 2014    Updated: Dec 3, 2018
Resolved Date: Oct 14, 2014
Found In Version: 6.0.0.10
Fix Version: 6.0.0.13
Severity: Standard
Applicable for: Wind River Linux 6
Component/s: Toolchain
Architecture: ARM

Description

this is on wrl 600.10 and the following options:

cc1 -fpreprocessed -quiet -mcpu=cortex-a15 -mfpu=vfpv3-d16 -mthumb -mtls-dialect=gnu -auxbase obfuscated-org -g -O3 -Werror=implicit-function-declaration -Wno-write-strings -fdump-rtl-all -fdump-tree-all -fno-omit-frame-pointer -dAp obfuscated-org.c

We have some code like this, part of a huge piece of code that we've failed to reduce substantially (if we change anything gcc chooses to
generate different, and correct, code). Unfortunately we can not share the complete code due to it's sensitivity. I'd be happy to go through and show parts of it in live online.

Compiling the code below doesn't generate the provided assembly, but tries to demonstrate the problem. A (potential ?) fix is provided in the end.

struct a {
       unsigned int a:27;
       unsigned int b:1;
       unsigned int c:4;
       unsigned int d;
};

struct b {
       struct a a;
};

union u {
  struct a a;
  struct b b;
};


/* Below u->a.b and u->b.a.b is the same bit 
 */
void func(union u* u, long* p) {
     if(u->a.b != 0) {
        p[2] = 1;
     }
     else {
       err("An error", 43);
     }
     if(u->b.a.b != 0) {
        /* do stuff */
     }
     else
        err("An error", 42);
}

--- 8< ---

The compiler generates code;

        lsls    r2, r3, #28     @ 1149  *shiftsi3_compare0_scratch      [length = 4]
        itt     mi
        movmi   r2, #1  @ 13    *p *thumb2_movsi_insn/2 [length = 6]
        strmi r2, [r7, #8] @ 1050 *p *thumb2_movsi_insn/7 [length = 6]
        bpl     .L168   @ 1150  arm_cond_branch [length = 4]
        ...
.L168:
        beq     .L106   @ 255   arm_cond_branch [length = 2]
        ...

The first block is the first test (if) and is correct, but the beq is not correct (and unnecessary).


The fix could be (but my understanding of gcc/md is limited).


diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index ed8b83a..7fdbaea 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -12071,7 +12071,7 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
   /* An operation (on Thumb) where we want to test for a single bit.
      This is done by shifting that bit up into the top bit of a
      scratch register; we can then branch on the sign bit.  */
-  if (TARGET_THUMB1
+  if ((TARGET_THUMB1 || TARGET_THUMB2)
       && GET_MODE (x) == SImode
       && (op == EQ || op == NE)
       && GET_CODE (x) == ZERO_EXTRACT

Other Downloads


Live chat
Online