kit

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

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

opt: parameters mutually interfere at function entry

The ABI delivers every incoming parameter simultaneously at entry, but each
param_decl marker was sequenced, so a param's live range started at its marker
rather than at the entry point. A dead parameter (e.g. an unused arg) then had a
range disjoint from a later live parameter and the allocator coalesced the two
into one physical register — yielding two entry binds targeting the same
register, which the entry-bind parallel copy cannot resolve (one clobbers the
other). Anchor every param_decl def at the entry block's base point so all
parameters interfere, forcing distinct registers. Fixes funcptr_field_first_arg
and the VLA-param cases at -O1.

Diffstat:
Msrc/opt/pass_live.c | 10+++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/opt/pass_live.c b/src/opt/pass_live.c @@ -800,7 +800,15 @@ void opt_live_ranges_build(Func* f, const OptLiveInfo* live, range_add_live_across_call(live_pregs.regs[k], &call_ctx); } - RangeCloseCtx close_ctx = {&build, raw_start + i, b}; + /* Incoming parameters are all delivered simultaneously by the ABI at + * function entry, so their values are mutually live there even though the + * param_decl markers are sequenced. Anchor every param_decl def at the + * entry block's base point so the params interfere with one another; this + * stops the allocator from coalescing a dead param (e.g. an unused arg) + * into a live param's incoming register, which the entry-bind parallel + * copy could not then resolve (two binds targeting one register). */ + u32 def_pos = ((IROp)in->op == IR_PARAM_DECL) ? raw_start : raw_start + i; + RangeCloseCtx close_ctx = {&build, def_pos, b}; for (u32 k = 0; k < refs.ndefs; ++k) range_close_def(refs.defs[k], &close_ctx); RangeUseCtx use_ctx = {&build, raw_start + i + 1u, b};