The following code  (by Alex Vod.)

struct A {
 char a[400];
 float* c;
};
struct A glob;
void func();
void func1(float*);
int func2(float*, int*);
void func3(float*);

void test(int *p) {
 func1(glob.c);
 if (func2(glob.c, p)) {
   func();
 }
 func3(glob.c);
}

is compiled by gcc 4.2.1 to 56 bytes and 4.4.0 to 64 bytes. The problem is that
it calculates address glob.c *twice*, but there is no need to - it doesn't
change as glob is a global variable.
gcc 4.2.1 output:
       push    {r4, r5, r6, lr}
       ldr     r3, .L5
       ldr     r2, .L5+4
.LPIC0:
       add     r3, pc
       ldr     r5, [r3, r2]
       mov     r6, #200
       lsl     r6, r6, #1
       mov     r4, r0
       ldr     r0, [r5, r6]
       bl      func1
       ldr     r0, [r5, r6]
       mov     r1, r4
       bl      func2
       cmp     r0, #0
       beq     .L2
       bl      func
.L2:
       ldr     r0, [r5, r6]
       bl      func3
       @ sp needed for prologue
       pop     {r4, r5, r6, pc}

gcc 4.4.0 output:
       push    {r3, r4, r5, r6, r7, lr}
       ldr     r4, .L5
       ldr     r3, .L5+4
.LPIC0:
       add     r4, pc
       ldr     r6, [r4, r3]
       mov     r5, #200
       lsl     r5, r5, #1
       mov     r7, r0
       ldr     r0, [r6, r5]
       bl      func1
       ldr     r0, [r6, r5]
       mov     r1, r7
       bl      func2
       cmp     r0, #0
       beq     .L2
       bl      func
.L2:
       ldr     r3, .L5+4
       @ sp needed for prologue
       ldr     r2, [r4, r3]
       mov     r3, #200   // this is the calculation of glob.c address
       lsl     r3, r3, #1    // it is redundant, as r5 already contains #400
       ldr     r0, [r2, r3]
       bl      func3
       pop     {r3, r4, r5, r6, r7, pc}

I believe gcc 4.2.1 works correctly due to RTL CSE pass.
Before CSE:

;; Start of basic block 4, registers live: (nil)
(code_label 34 33 35 4 2 "" [1 uses])
(note 35 34 37 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(insn 37 35 38 4 (set (reg:SI 113) // put attention to this insn
       (unspec:SI [
               (symbol_ref:SI ("glob") <var_decl 0xf7d5a000 glob>)
           ] 3)) 148 {pic_load_addr_thumb} (nil)
   (nil))
(insn 38 37 39 4 (set (reg/f:SI 112)   // put attention to this insn
       (mem/u/c:SI (plus:SI (reg:SI 103)
               (reg:SI 113)) [0 S4 A32])) 146 {*thumb_movsi_insn} (nil)
   (expr_list:REG_EQUAL (symbol_ref:SI ("glob") <var_decl 0xf7d5a000 glob>)
       (nil)))
(insn 39 38 40 4 (set (reg:SI 114)             // put attention to this insn
       (const_int 400 [0x190])) 146 {*thumb_movsi_insn} (nil)
   (nil))
(insn 40 39 41 4 (set (reg:SI 115 [ glob.c ])
       (mem/s/f/c:SI (plus:SI (reg/f:SI 112)
               (reg:SI 114)) [5 glob.c+0 S4 A32])) 146 {*thumb_movsi_insn}
(nil)
   (nil))
(insn 41 40 42 4 (set (reg:SI 0 r0 [ glob.c ])
       (reg:SI 115 [ glob.c ])) 146 {*thumb_movsi_insn} (nil)
   (nil))
(call_insn 42 41 43 4 (parallel [
           (call (mem:SI (symbol_ref:SI ("func3") [flags 0x41] <function_decl
0xf7d5c100 func3>) [0 S4 A32])
               (const_int 0 [0x0]))
           (use (const_int 0 [0x0]))
           (clobber (reg:SI 14 lr))
       ]) 231 {*call_insn} (nil)
   (nil)
   (expr_list:REG_DEP_TRUE (use (reg:SI 0 r0 [ glob.c ]))
       (nil)))
;; End of basic block 4, registers live:

after CSE:

;; Start of basic block 4, registers live: (nil)
(code_label 34 33 35 4 2 "" [1 uses])
(note 35 34 40 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
(insn 40 35 41 4 (set (reg:SI 115 [ glob.c ]) // all mentioned instructions
were removed
       (mem/s/f/c:SI (plus:SI (reg/f:SI 104)
               (reg:SI 106)) [5 glob.c+0 S4 A32])) 146 {*thumb_movsi_insn}
(nil)
   (nil))
(insn 41 40 42 4 (set (reg:SI 0 r0 [ glob.c ])
       (reg:SI 115 [ glob.c ])) 146 {*thumb_movsi_insn} (nil)
   (nil))
(call_insn 42 41 43 4 (parallel [
           (call (mem:SI (symbol_ref:SI ("func3") [flags 0x41] <function_decl
0xf7d5c100 func3>) [0 S
4 A32])
               (const_int 0 [0x0]))
           (use (const_int 0 [0x0]))
           (clobber (reg:SI 14 lr))
       ]) 231 {*call_insn} (nil)
   (nil)
   (expr_list:REG_DEP_TRUE (use (reg:SI 0 r0 [ glob.c ]))
       (nil)))
;; End of basic block 4, registers live:

For some reason, this CSE pass doesn't work in gcc 4.3.1 or gcc-4.4.0


-- 
           Summary: Address of global variable is calculated multiple times;
                    CSE doesn't work properly
           Product: gcc
           Version: 4.4.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: sliao at google dot com
 GCC build triplet: i686-linux
  GCC host triplet: i686-linux
GCC target triplet: arm-eabi


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42574

Reply via email to