http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57130
Bug #: 57130 Summary: Incorrect "and --> extract" conversion in combine Classification: Unclassified Product: gcc Version: 4.9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization AssignedTo: unassig...@gcc.gnu.org ReportedBy: w...@google.com Created attachment 29986 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=29986 Testcase For the smallcase 1.ii attached. ~/workarea/gcc-r198433/build/install/bin/g++ 1.ii -o a1.out ./a1.out --> correct output: 1 3 ~/workarea/gcc-r198433/build/install/bin/g++ -fno-inline -fno-omit-frame-pointer -O2 1.ii -o a2.out ./a2.out --> incorrect output: 1 -1 In 1.ii.196r.ud_dce: (insn 7 2 84 2 (set (reg:DI 64) (const_int -4294967296 [0xffffffff00000000])) 1.ii:26 84 {*movdi_internal} (nil)) ... (insn 40 36 44 2 (parallel [ (set (reg:DI 88) (and:DI (reg:DI 80) (reg:DI 64))) (clobber (reg:CC 17 flags)) ]) 1.ii:32 386 {*anddi_1} (expr_list:REG_DEAD (reg:DI 80) (expr_list:REG_DEAD (reg:DI 64) (expr_list:REG_UNUSED (reg:CC 17 flags) (expr_list:REG_EQUAL (and:DI (reg:DI 80) (const_int -4294967296 [0xffffffff00000000])) (nil)))))) (insn 44 40 45 2 (set (reg:DI 92 [ mini_rect ]) (zero_extend:DI (subreg:SI (reg:DI 88) 0))) 1.ii:33 127 {*zero_extendsidi2} (expr_list:REG_DEAD (reg:DI 88) (nil))) The value of r92 here should always be 0. After try_combine with params (i3==insn44, i2==insn40, i1==insn7), insn44 is transformed to: (insn 44 40 45 2 (parallel [ (set (reg:DI 92 [ mini_rect ]) (ashiftrt:DI (reg:DI 88) (const_int 63 [0x3f]))) (clobber (reg:CC 17 flags)) ]) 1.ii:33 528 {ashrdi3_cvt} (expr_list:REG_UNUSED (reg:CC 17 flags) (expr_list:REG_DEAD (reg:DI 88) (nil)))) The value of r92 now equals either 0 or -1 which depends on the highest bit of r88. Try to understand what happen in try_combine: In try_combine, after subst(PATTERN (i3), i2dest, i2src, ...), insn 44 is transformed to the following form. This step is correct. (insn 44 40 45 2 (set (reg:DI 92 [ mini_rect ]) (neg:DI (ne:DI (subreg:SI (and:DI (reg:DI 80) (reg:DI 64)) 0) (const_int 0 [0])))) 1.ii:33 127 {*zero_extendsidi2} (expr_list:REG_DEAD (reg:DI 88) (nil))) In subst(PATTERN (i3), i1dest, i1src, ...), insn 44 is firstly transformed to the following in simplify_logical, which is correct: (insn 44 40 45 2 (set (reg:DI 92 [ mini_rect ]) (neg:DI (ne:DI (subreg:SI ((and:DI (reg:DI 80) (const_int 34359738368 [0x800000000]))) 0) (const_int 0 [0])))) 1.ii:33 127 {*zero_extendsidi2} (expr_list:REG_DEAD (reg:DI 88) (nil))) then it is transformed to the following in make_compound_operation, which is incorrect: (insn 44 40 45 2 (set (reg:DI 92 [ mini_rect ]) (sign_extract:DI (reg:DI 80) (const_int 1 [0x1]) (const_int 35 [0x23]))) 1.ii:33 127 {*zero_extendsidi2} (expr_list:REG_DEAD (reg:DI 88) (nil))) make_compound_operation transforms (and:DI (reg:DI 80) (const_int 34359738368 [0x800000000])) to (zero_extract:DI (reg:DI 80) (const_int 1 [0x1]) (const_int 35 [0x23])) because it thinks the "and expr" here is in a compare. But actually the "and expr" is firstly the kid in a subreg: subreg:SI ((and:DI (reg:DI 80) (const_int 34359738368 [0x800000000])) ==> always 0 is not identical with subreg:SI ((zero_extract:DI (reg:DI 80) (const_int 1 [0x1]) (const_int 35 [0x23])) ==> 0 or 1 So it is the cause of the problem. The second actual of make_compound_operation (combine.c:7701, r198433) should not be in_code.