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.

Reply via email to