regalloc: Fuse mapping lookup and removal

b9413ac4162e1b492d96cd9b85029618f848e92e2e5b99b2faaccef35608feb0
Last-use handling searched the active register map once to find the
physical register and again to remove the same mapping.

Return the physical register from `rmapRemove`, allowing one
traversal to both remove the mapping and release its physical
register.

Assisted-by: Codex:gpt-5.6-sol
Alexis Sellier committed ago 1 parent 151d50c0
lib/std/lang/gen/regalloc/assign.rad +6 -6
218 218
    set rmap.virtRegs[rmap.n] = virtReg;
219 219
    set rmap.physRegs[rmap.n] = physReg;
220 220
    set rmap.n += 1;
221 221
}
222 222
223 -
/// Remove a mapping from register map.
224 -
fn rmapRemove(rmap: *mut RegMap, virtReg: u32) {
223 +
/// Remove a mapping from the register map and return its physical register.
224 +
fn rmapRemove(rmap: *mut RegMap, virtReg: u32) -> ?gen::Reg {
225 225
    for i in 0..rmap.n {
226 226
        if rmap.virtRegs[i] == virtReg {
227 +
            let phys = rmap.physRegs[i];
227 228
            // Swap with last and decrement.
228 229
            set rmap.n -= 1;
229 230
            if i < rmap.n {
230 231
                set rmap.virtRegs[i] = rmap.virtRegs[rmap.n];
231 232
                set rmap.physRegs[i] = rmap.physRegs[rmap.n];
232 233
            }
233 -
            return;
234 +
            return phys;
234 235
        }
235 236
    }
236 -
    panic "rmapRemove: register not found";
237 +
    return nil;
237 238
}
238 239
239 240
/// Find first free register in pool, allocate it, return it.
240 241
fn findFreeInPool(usedRegs: *mut bitset::Bitset, current: *mut RegMap, ssaReg: u32, pool: *[gen::Reg]) -> ?gen::Reg {
241 242
    for i in 0..pool.len {
280 281
281 282
/// Callback for [`il::forEachReg`]: free last uses and allocate missing uses.
282 283
fn processInstrRegCb(reg: il::Reg, ctxPtr: *mut opaque) {
283 284
    let ctx = ctxPtr as *mut InstrCtx;
284 285
    if not liveness::hasLaterUse(ctx.live, ctx.func, ctx.blockIdx, ctx.instrIdx, reg) {
285 -
        if let phys = rmapFind(ctx.current, reg.n) {
286 +
        if let phys = rmapRemove(ctx.current, reg.n) {
286 287
            bitset::clear(ctx.usedRegs, *phys as u32);
287 -
            rmapRemove(ctx.current, reg.n);
288 288
        }
289 289
    }
290 290
    assert reg.n < ctx.assignments.len, "processInstrRegCb: register out of bounds";
291 291
    if spill::isSpilled(ctx.spillInfo, reg) {
292 292
        return; // Spilled values don't get physical registers.