kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 586ad5a64c6b437ca1ea066d3845e42aadc1f491
parent 2b9dd35027292377b9741f0e6cbd9d154699024f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 29 May 2026 12:32:52 -0700

opt/x64: report the rdx:rax clobber of the unsigned multiply-overflow intrinsic

__builtin_umul*_overflow lowers to a one-operand MUL whose rdx:rax product
clobbers rdx (allocable). A value living in rdx across the intrinsic (e.g. a
constant kept for a later use) was silently destroyed. Teach machinize to build
a NativeMachineOp for IR_INTRINSIC and have the x64 hook report {rax,rdx} for
INTRIN_UMUL_OVERFLOW; the signed variant uses two-operand IMUL and clobbers
nothing. Fixes builtin_26_sadd_overflow at -O1.

Diffstat:
Msrc/arch/x64/native.c | 10++++++++++
Msrc/opt/pass_machinize.c | 7+++++++
2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/src/arch/x64/native.c b/src/arch/x64/native.c @@ -3699,6 +3699,16 @@ static int x64_machine_op_clobbers(NativeTarget* t, const NativeMachineOp* op, if (!op->result_is_fp) return 0; mask[NATIVE_REG_INT] = (1u << X64_RAX); return 1; + case NATIVE_MOP_INTRINSIC: + /* The unsigned multiply-overflow intrinsic emits a one-operand MUL, whose + * rdx:rax product clobbers both registers. The signed variant uses a + * two-operand IMUL (no fixed-register clobber); other intrinsics keep to + * the reserved emit scratch. */ + if ((IntrinKind)op->intrin == INTRIN_UMUL_OVERFLOW) { + mask[NATIVE_REG_INT] = (1u << X64_RAX) | (1u << X64_RDX); + return 1; + } + return 0; default: return 0; } diff --git a/src/opt/pass_machinize.c b/src/opt/pass_machinize.c @@ -173,6 +173,13 @@ static void machinize_inst_clobbers(Func* f, NativeTarget* target) { break; case IR_ATOMIC_CAS: mop.kind = NATIVE_MOP_ATOMIC_CAS; break; case IR_ATOMIC_RMW: mop.kind = NATIVE_MOP_ATOMIC_RMW; break; + case IR_INTRINSIC: { + const IRIntrinAux* aux = (const IRIntrinAux*)in->extra.aux; + if (!aux) continue; + mop.kind = NATIVE_MOP_INTRINSIC; + mop.intrin = (u8)aux->kind; + break; + } default: continue; } mask[0] = mask[1] = mask[2] = 0;