Emit 32-bit remainders of non-negative int32 operands

LLVM does not narrow the i64 urem of two extended int32s, so a proven
non-negative int32 remainder by a constant took the 64-bit magic-number
sequence (with its fixup). Emit urem i32 when both operands are proven
int32 ranges.
This commit is contained in:
Malte Ubl
2026-10-15 04:46:12 -07:00
parent 42e15185f2
commit 2f23fff40d
@@ -273,14 +273,17 @@ export function emitOperatorExpr(
return uint32 === undefined ? number : { ...number, uint32 };
}
if (e.op === "%" && li.range.min >= 0 && ri.range.min > 0) {
const range = { min: 0, max: Math.min(li.range.max, ri.range.max - 1) };
if (withinInt32(li.range) && withinInt32(ri.range)) {
// LLVM does not narrow the i64 remainder of two extended
// int32s; a 32-bit one takes a shorter magic-number sequence.
const result = B.tmp();
B.line(`${result} = urem i32 ${narrowInteger(host, li)}, ${narrowInteger(host, ri)}`);
return int32Number(host, result, range, e.type);
}
const result = B.tmp();
B.line(`${result} = urem i64 ${left}, ${right}`);
return integerNumber(
host,
result,
{ min: 0, max: Math.min(li.range.max, ri.range.max - 1) },
e.type,
);
return integerNumber(host, result, range, e.type);
}
if (e.op === "%") {
const integer = emitSignedIntegerRemainder(host, l, li, ri);