Richard Biener <richard.guent...@gmail.com> writes:
> On Thu, Sep 11, 2025 at 4:43 PM Richard Sandiford
> <rdsandif...@googlemail.com> wrote:
>>
>> Jakub Jelinek via Gcc <gcc@gcc.gnu.org> writes:
>> > On Thu, Sep 11, 2025 at 11:02:26AM +0200, Richard Biener via Gcc wrote:
>> >> > Does the doc need clarification on the semantics of RTL shift
>> >> > operations when the shift amount is out of range?
>> >>
>> >> The SHIFT_COUNT_TRUNCATED target macro is also relevant in
>> >> this context.  On x86 which is a "mixed" ISA in this regard we make
>> >> sure to recognize shifts with an (and ...) shift operand which is
>> >> what the middle-end will add (the and) when !SHIFT_COUNT_TRUNCATED
>> >> IIRC.
>> >
>> > For SHIFT_COUNT_TRUNCATED targets, the shift count is certainly
>> > modulo the bitsize, though it is fuzzy what happens when the bitsize is not
>> > a power of two and the count is negative (whether it is treated as unsigned
>> > modulo or something else (eventhough -27 % 24 is -3 and not 21 (24 - 3)
>> > or 13 (-27U % 24)).
>> > For !SHIFT_COUNT_TRUNCATED, I think we generally consider it UB even
>> > on RTL,
>> > although it doesn't mean we can ICE on it etc., we can just punt on trying
>> > to optimize it, but it still needs to be assembled one way or another,
>> > the code might invoke UB but can't be proven to be always executed.
>>
>> FWIW, I thought that for !SHIFT_COUNT_TRUNCATED, we treated out-of-range
>> shifts as target-specific.  E.g. it's possible for a !SHIFT_COUNT_TRUNCATED
>> target to use lshift in the expansion of another operation (such as a
>> doubleword shift) and rely on target-specific behaviour for shifts
>> greater than the bit count.  That applies to negative shifts as well.
>>
>> That's why, for example, simplify-rtx.cc is careful to punt when trying
>> to fold shifts to constants if !SHIFT_COUNT_TRUNCATED and the shift
>> is out of range.  If the shift was UB, we could instead fold all shifts
>> according to SHIFT_COUNT_TRUNCATED semantics.
>
> Yes, RTL expansion inserts an AND operation when !SHIFT_COUNT_TRUNCATED.

Yeah, but that would be necessary for both undefined behaviour and
target-specific behaviour, so I don't think it's indicative when deciding
between the two.

> What I was saying there's no way to get a negative shift count flip shift
> direction to RTL - it would require a target specific intrinsic that's a
> builtin
> call before RTL expansion and an UNSPEC after.

I suppose.  Having negative shifts shift in the opposite direction seems
like a reasonable choice of target-specific behaviour.  But if we were
going to support that, we would probably need to distinguish between
ASHIFT and LSHIFT.  Also:

      /* NEG commutes with ASHIFT since it is multiplication.  Only do
         this if we can then eliminate the NEG (e.g., if the operand
         is a constant).  */
      if (GET_CODE (op) == ASHIFT)
        {
          temp = simplify_unary_operation (NEG, mode, XEXP (op, 0), mode);
          if (temp)
            return simplify_gen_binary (ASHIFT, mode, temp, XEXP (op, 1));
        }

assumes that ASHIFT is a multiplication and wouldn't be safe for ASHIFTs
that shift right.  (I couldn't see a fold for:

  (a << c) + (b << c) => (a + b) << c

though, maybe I missed it.)

Richard

Reply via email to