https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81423
--- Comment #3 from Uroš Bizjak <ubizjak at gmail dot com> ---
Following is a c testcase:
--cut here--
unsigned long long int ll = 0;
unsigned long long int ull1 = 1ULL;
unsigned long long int ull2 = 12008284144813806346ULL;
unsigned long long int ull3;
void
foo ()
{
ll = -5597998501375493990LL;
ll = (5677365550390624949L - ll) - (ull1 > 0);
ull3 = (unsigned int)
(2067854353L <<
(((ll + -2129105131L) ^ 10280750144413668236ULL) -
10280750143997242009ULL)) >> ((2873442921854271231ULL | ull2)
- 12098357307243495419ULL);
}
int
main ()
{
foo ();
printf ("%llu expected 3998784)\n", ull3);
printf ("%x expected 3d0440)\n", ull3);
return 0;
}
--cut here--
The problem is in combine pass, which combines following sequence in the main
function:
(insn 17 16 18 2 (parallel [
(set (reg:SI 114)
(ior:SI (subreg:SI (reg:DI 113 [ ull2 ]) 0)
(const_int -8651009 [0xffffffffff7bfeff])))
(clobber (reg:CC 17 flags))
]) "pr81423.c":15 415 {*iorsi_1}
(expr_list:REG_DEAD (reg:DI 113 [ ull2 ])
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil))))
(insn 18 17 19 2 (parallel [
(set (reg:SI 115)
(plus:SI (reg:SI 114)
(const_int 5 [0x5])))
(clobber (reg:CC 17 flags))
]) "pr81423.c":16 217 {*addsi_1}
(expr_list:REG_DEAD (reg:SI 114)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil))))
(insn 19 18 20 2 (parallel [
(set (reg:SI 116)
(lshiftrt:SI (subreg:SI (reg:DI 111) 0)
(subreg:QI (reg:SI 115) 0)))
(clobber (reg:CC 17 flags))
]) "pr81423.c":15 544 {*lshrsi3_1}
(expr_list:REG_DEAD (reg:SI 115)
(expr_list:REG_DEAD (reg:DI 111)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))))
(insn 20 19 21 2 (set (reg:DI 103 [ _20 ])
(zero_extend:DI (reg:SI 116))) "pr81423.c":15 131 {*zero_extendsidi2}
(expr_list:REG_DEAD (reg:SI 116)
(nil)))
Trying 17, 18, 19 -> 20:
Failed to match this instruction:
(set (reg:DI 103 [ _20 ])
(zero_extract:DI (reg:DI 111)
(const_int 32 [0x20])
(const_int 4 [0x4])))
Failed to match this instruction:
(set (reg:DI 103 [ _20 ])
(and:DI (lshiftrt:DI (reg:DI 111)
(const_int 4 [0x4]))
(const_int 4294967295 [0xffffffff])))
Successfully matched this instruction:
(set (reg:DI 116)
(ashift:DI (reg:DI 111)
(const_int 28 [0x1c])))
Successfully matched this instruction:
(set (reg:DI 103 [ _20 ])
(lshiftrt:DI (reg:DI 116)
(const_int 32 [0x20])))
allowing combination of insns 17, 18, 19 and 20
original costs 6 + 4 + 4 + 1 = 15
replacement costs 4 + 4 = 8
deferring deletion of insn with uid = 18.
deferring deletion of insn with uid = 17.
deferring deletion of insn with uid = 16.
modifying insn i2 19: {r116:DI=r111:DI<<0x1c;clobber flags:CC;}
REG_UNUSED flags:CC
REG_DEAD r111:DI
deferring rescan insn with uid = 19.
modifying insn i3 20: {r103:DI=r116:DI 0>>0x20;clobber flags:CC;}
REG_UNUSED flags:CC
REG_DEAD r116:DI
deferring rescan insn with uid = 20.
Please note that we have in the original sequence:
(insn 19 18 20 2 (parallel [
(set (reg:SI 116)
(lshiftrt:SI (subreg:SI (reg:DI 111) 0)
(subreg:QI (reg:SI 115) 0)))
(clobber (reg:CC 17 flags))
]) "pr81423.c":15 544 {*lshrsi3_1}
(expr_list:REG_DEAD (reg:SI 115)
(expr_list:REG_DEAD (reg:DI 111)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))))
in effect, this insn is shifting value, truncated to 32 bits, from
rax 0x1ed03d04400 2117482857472
by 4 via:
0x0000000000400557 <+71>: add $0x5,%ecx
0x000000000040055a <+74>: shr %cl,%eax
resulting in:
rax 0x3d0440 3998784
rcx 0x4 4
However, combine tries to create:
(set (reg:DI 103 [ _20 ])
(zero_extract:DI (reg:DI 111)
(const_int 32 [0x20])
(const_int 4 [0x4])))
trying to extract 32bit value from position 4. This is not correct, due to
32bit left shift in the sequence, the combined insn should zero-extract 28
bits only.