llvm-project
ead99b0a - [CIR] Fix unsigned/wide switch case-range lowering (#206575)

Commit
12 days ago
[CIR] Fix unsigned/wide switch case-range lowering (#206575) A `switch` over an unsigned (or wider-than-32-bit) integer with a GNU `case lo ... hi` range was miscompiled. SingleSource `pr34154.c` is the witness: it switches on an `unsigned long long` with `case 1000000000000000000ULL ... 9999999999999999999ULL`, and under `-fclangir` every value took the default. The flattening pass decided whether a range was empty with a signed compare, `lowerBound.sgt(upperBound)` in `CIRSwitchOpFlattening`. The upper bound `9999999999999999999` is larger than `INT64_MAX`, so as a signed value it is negative and the range looked empty -- it was dropped and the case body left unreachable, so control always reached the default. Behind that sat three more width/signedness slips: the small-range size gate compared a 64-bit difference against a 32-bit `APInt`, the expansion loop advanced a signed `APInt` cursor that looped forever for a range ending at the type's maximum (the cursor wraps past the top of the domain), and `condBrToRangeDestination` built the lower-bound and range-length constants and the subtraction at a hardcoded 32-bit width, which truncates a 64-bit range. The fix derives the switch operand's integer type once: the emptiness test uses the operand's signedness, the range-check constants and the subtraction are built at the operand width, and small ranges are expanded with a count-based cursor. The `sub x, lo; ule (x - lo), (hi - lo)` range check is a cyclic-distance test that works for both signed and unsigned switches, so the comparison stays unsigned; the existing 32-bit signed-range lowering is unchanged.
Author
Parents
Loading