Richard Biener <[email protected]> writes:
> On Thu, Sep 11, 2025 at 4:43 PM Richard Sandiford
> <[email protected]> wrote:
>>
>> Jakub Jelinek via Gcc <[email protected]> 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