From 2f23fff40d765c8e9cd86b2ebaeaa33bc75f5143 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 14 Oct 2026 16:42:38 -0700 Subject: [PATCH] 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. --- .../compiler/src/backend/llvm/expr-primitives.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 57a5e1bcf..a2c73f506 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -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);