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