I'm seeing invalid code produced for a simple test case targeting arm- none-elf (attached), which I believe is caused by an invalid transformation in simplify_comparison. It's transforming code of the form:

  (compare (subreg:QI (plus (reg:SI) (-1)))
           (-3))

into:

  (compare (plus (reg:SI) (-1))
           (-3))

But I don't believe this transformation (lifting the subreg) is valid for this particular instance. Here are the more explicit rtl dumps - before:

(insn 14 12 15 0 (set (reg:SI 104)
        (plus:SI (reg:SI 103 [ <variable>.uc8 ])
(const_int -1 [0xffffffff]))) 4 {*arm_addsi3} (insn_list:REG_DEP_TRUE 12 (nil))
    (expr_list:REG_DEAD (reg:SI 103 [ <variable>.uc8 ])
        (nil)))

(insn 15 14 16 0 (set (reg:SI 105)
        (and:SI (reg:SI 104)
(const_int 255 [0xff]))) 53 {*arm_andsi3_insn} (insn_list:REG_DEP_TRUE 14 (nil))
    (expr_list:REG_DEAD (reg:SI 104)
        (nil)))

(insn 16 15 17 0 (set (reg:CC 24 cc)
        (compare:CC (reg:SI 105)
(const_int 253 [0xfd]))) 194 {*arm_cmpsi_insn} (insn_list:REG_DEP_TRUE 15 (nil))
    (expr_list:REG_DEAD (reg:SI 105)
        (nil)))

After:

(note 14 12 15 0 NOTE_INSN_DELETED)

(insn 15 14 16 0 (set (reg:SI 105)
        (plus:SI (reg:SI 103 [ <variable>.uc8 ])
(const_int -1 [0xffffffff]))) 4 {*arm_addsi3} (insn_list:REG_DEP_TRUE 12 (nil))
    (expr_list:REG_DEAD (reg:SI 103 [ <variable>.uc8 ])
        (nil)))

(insn 16 15 17 0 (set (reg:CC 24 cc)
        (compare:CC (reg:SI 105)
(const_int -3 [0xfffffffd]))) 194 {*arm_cmpsi_insn} (insn_list:REG_DEP_TRUE 15 (nil))
    (expr_list:REG_DEAD (reg:SI 105)
        (nil)))

The conversion is being done at the "case SUBREG" code starting around line 10191 of combine.c. The conversion is allowed because the following tests are met:

    ((unsigned HOST_WIDE_INT) c1
      < (unsigned HOST_WIDE_INT) 1 << (mode_width - 2)
     /* (A - C1) always sign-extends, like C2.  */
     && num_sign_bit_copies (a, inner_mode)
        > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
                          - mode_width - 1))

In my case:
  c1 is 3, which is less than 1 << 6, and
num_sign_bit_copies(a,SI) is 24 (because the SI register "a" contains a zero-extended QI value), and
  "GET_MODE_BITSIZE (inner_mode) - mode_width - 1" is 23

Now, as I understand things, we're trying to see if "compare (subreg (a - c1), c2)" is the same as "compare (a - c1, c2)". And, this is considered acceptable if the result of "a - c1" is identical to a sign extended "subreg (a - c1)". So far, so good. However, as I apply the code to the SI/QI subreg case reads:

if (INTVAL (c1) < 64) and there are at least 24 identical bits at the top of a

This logic, however, doesn't seem to match. First, it would seem there should be at least 25 identical bits to verify that we do indeed have a sign-extended QI value. But even with that addressed, consider another case (again with the QI/SI for concreteness). Suppose we have an expression like:

  lt (subreg (a - 1), -3)

And, suppose for this example that "a" is a SI sign-extended from a signed QI. So, num_sign_bit_copies would be 25. The transformation would be allowed (because c1 is less than 64 and num_sign_bit_copies is greater than 24). However, if "a" contained a value of -128 at run-time:

  lt (subreg (a - 1), -3) becomes
    lt (subreg (-129), -3) becomes
      lt (127), -3 == FALSE

whereas after the transformation:

  lt (a - 1, -3) becomes
    lt (-129, -3) == TRUE

Am I misinterpreting the logic? Am I missing something fundamental? I appreciate any feedback / pointers / clues / etc...

- Josh


Attachment: test.c
Description: Binary data

Reply via email to