A wrong REG_EQUAL is attached to SUBREG during forward propagation. Before fwprop1 (insn 56 55 57 3 double.cpp:12 (set (reg/v:DI 180 [ _D_inf ]) (const_int 0 [0x0])) 164 {*thumb1_movdi_insn} (nil)) (insn 60 59 61 3 double.cpp:12 (set (reg:SI 189) (const_int 2146435072 [0x7ff00000])) 168 {*thumb1_movsi_insn} (nil)) (insn 62 61 63 3 double.cpp:12 (set (subreg:SI (reg/v:DI 180 [ _D_inf ]) 4) (reg:SI 189)) 168 {*thumb1_movsi_insn} (nil))
After fwprop1, a note "REG_EQUAL (const_int 2146435072 [0x7ff00000]" is attached to insn 62. (insn 56 54 60 3 double.cpp:12 (set (reg/v:DI 180 [ _D_inf ]) (const_int 0 [0x0])) 164 {*thumb1_movdi_insn} (nil)) (insn 60 56 62 3 double.cpp:12 (set (reg:SI 189) (const_int 2146435072 [0x7ff00000])) 168 {*thumb1_movsi_insn} (nil)) (insn 62 60 63 3 double.cpp:12 (set (subreg:SI (reg/v:DI 180 [ _D_inf ]) 4) (reg:SI 189)) 168 {*thumb1_movsi_insn} (expr_list:REG_EQUAL (const_int 2 146435072 [0x7ff00000]) (nil))) Then at combine pass, when the three insns are combined into one insn, the operand of the set note becomes [0x7ff0000000000000], but the REG_EQUAL note is still [0x7ff00000]. (insn 62 155 63 3 double.cpp:12 (set (reg/v:DI 180 [ _D_inf ]) (const_int 9218868437227405312 [0x7ff0000000000000])) 164 {*thumb1_movdi_insn} (expr_list:REG_EQUAL (const_int 2146435072 [0x7ff00000]) (nil))) If the wrong REG_EQUAL is not used in later optimization, then nothing wrong is observed. However, we find a case that the bug is triggered at ira pass. What happens is at ira pass, in reload() (reload1.c), gcc tries to find "SET REG(regno) = const N". When gcc finds one, it records constant equivalent in reg_equiv_constant so that the use of the register will be substituted by find_reloads. gcc puts "reg_equiv_constant[regno]=x". However, notice that, "x" here is the value from the REG_EQUAL note, not the SET operand. In our case, the value in reg 180 is 0x7ff0000000000000, but gcc says reg_equiv_constant[180]=0x7ff00000. Later, when gcc tries to simplify the SUBREG for insn 65, it picks the wrong value in reg_equiv_const[180] and passes the wrong value to insn 65. (insn 65 64 66 3 double.cpp:13 (set (reg:DF 2 r2) (subreg:DF (reg/v:DI 180 [ _D_inf ]) 0)) 183 {*thumb_movdf_insn} (nil)) becomes (insn 65 64 66 3 double.cpp:13 (set (reg:DF 2 r2) (const_double:DF 1.06047983010398252661938461763305382790433594771e-314 [0x0.ffep-1043])) 183 {*thumb_movdf_insn} (nil)) The const_double in insn 65 is wrong. test case double.cpp: union _D_rep { unsigned short rep[4]; double val; }; int add(double* key, double* table) { unsigned i = 0; double* deletedEntry = 0; while (1) { double* entry = table + i; _D_rep _D_inf = {{ 0, 0, 0, 0x7ff0 }}; if (*entry == _D_inf.val) break; if (*entry == *key) return 0; _D_rep _D_inf2 = {{ 0, 0, 0, 0x7ff0 }}; if (_D_inf2.val) deletedEntry = entry; i++; } if (deletedEntry) return 1; return 0; } The command is: arm-eabi-g++ -Os -mthumb double.cpp -c -o double.o -- Summary: Wrong REG_EQUAL note is added to SUBREG node Product: gcc Version: 4.5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: jingyu at google dot com GCC build triplet: X86_64-linux-gnu GCC host triplet: X86_64-linux-gnu GCC target triplet: arm-unknown-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42691