compiler: Borrow owned blocks during SSA mutation

10f56b0500a320f753e749ee18e03c951761ebcaaf7b55dffa1a4e4f56dbf788
Alexis Sellier committed ago 1 parent 9066f1a3
lib/std/lang/lower.rad +12 -15
2118 2118
/// The latter is necessary because recursive SSA resolution may have already
2119 2119
/// patched terminator arguments with the provisional value before it was
2120 2120
/// found to be trivial.
2121 2121
unsafe fn rewriteCachedVarValue 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, from: il::Val, to: il::Val) where 'arena: 'phase, 'phase: 'function {
2122 2122
    for i in 0..self.blockData.len {
2123 -
        let blk = getBlockMut(self, BlockId(i));
2123 +
        let blk = &mut self.blockData[i];
2124 2124
        if blk.vars[*v] == from {
2125 2125
            set blk.vars[*v] = to;
2126 2126
        }
2127 2127
        if blk.instrs.len > 0 {
2128 2128
            let ix = blk.instrs.len - 1;
2255 2255
/// Get the number of predecessors for a block.
2256 2256
fn predecessorCount(blocks: &[BlockData], block: BlockId) -> u32 {
2257 2257
    return blocks[*block].preds.len;
2258 2258
}
2259 2259
2260 -
/// Get mutable block data by block id.
2261 -
unsafe fn getBlockMut 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, block: BlockId) -> *unsafe mut BlockData where 'arena: 'phase, 'phase: 'function {
2262 -
    return &mut self.blockData[*block];
2263 -
}
2264 -
2265 2260
/// Get the current block being built.
2266 2261
fn currentBlock 'arena 'phase 'function (self: &FnLowerer 'arena 'phase 'function) -> BlockId where 'arena: 'phase, 'phase: 'function {
2267 2262
    let block = self.currentBlock else {
2268 2263
        panic "currentBlock: no current block";
2269 2264
    };
3217 3212
    from: BlockId,         // The predecessor block containing the terminator to patch.
3218 3213
    target: u32,           // The index of the target block we're passing the value to.
3219 3214
    paramIdx: u32,         // The index of the block parameter to set.
3220 3215
    val: il::Val           // The value to pass as the argument.
3221 3216
) where 'arena: 'phase, 'phase: 'function {
3222 -
    let data = getBlockMut(self, from);
3217 +
    let allocator = alloc::arenaAllocator(self.arena);
3218 +
    // Get mutable block data by block id.
3219 +
    let data = &mut self.blockData[*from];
3223 3220
    let ix = data.instrs.len - 1; // The terminator is always the last instruction.
3224 3221
3225 3222
    // TODO: We shouldn't need to use a mutable subscript here, given that the
3226 3223
    // fields are already mutable.
3227 3224
    match &mut data.instrs[ix] {
3228 3225
        case il::Instr::Jmp { args, .. } => {
3229 -
            set *args = growArgs(self, *args, paramIdx + 1);
3226 +
            set *args = growArgs(*args, paramIdx + 1, allocator);
3230 3227
            set args[paramIdx] = val;
3231 3228
        }
3232 3229
        case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => {
3233 3230
            // Nb. both branches could target the same block (e.g. `if cond { x } else { x }`).
3234 3231
            if *thenTarget == target {
3235 -
                set *thenArgs = growArgs(self, *thenArgs, paramIdx + 1);
3232 +
                set *thenArgs = growArgs(*thenArgs, paramIdx + 1, allocator);
3236 3233
                set thenArgs[paramIdx] = val;
3237 3234
            }
3238 3235
            if *elseTarget == target {
3239 -
                set *elseArgs = growArgs(self, *elseArgs, paramIdx + 1);
3236 +
                set *elseArgs = growArgs(*elseArgs, paramIdx + 1, allocator);
3240 3237
                set elseArgs[paramIdx] = val;
3241 3238
            }
3242 3239
        }
3243 3240
        case il::Instr::Switch { defaultTarget, defaultArgs, cases, .. } => {
3244 3241
            if *defaultTarget == target {
3245 -
                set *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1);
3242 +
                set *defaultArgs = growArgs(*defaultArgs, paramIdx + 1, allocator);
3246 3243
                set defaultArgs[paramIdx] = val;
3247 3244
            }
3248 3245
            let idx = paramIdx + 1;
3249 3246
            for ci in 0..cases.len {
3250 3247
                if cases[ci].target == target {
3251 -
                    set cases[ci].args = growArgs(self, cases[ci].args, idx);
3248 +
                    set cases[ci].args = growArgs(cases[ci].args, idx, allocator);
3252 3249
                    set cases[ci].args[paramIdx] = val;
3253 3250
                }
3254 3251
            }
3255 3252
        }
3256 3253
        else => {
3258 3255
        }
3259 3256
    }
3260 3257
}
3261 3258
3262 3259
/// Grow an args array to hold at least the given capacity.
3263 -
unsafe fn growArgs 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, args: *unsafe mut [il::Val], capacity: u32) -> *unsafe mut [il::Val] where 'arena: 'phase, 'phase: 'function {
3260 +
unsafe fn growArgs(args: *unsafe mut [il::Val], capacity: u32, allocator: alloc::Allocator) -> *unsafe mut [il::Val] {
3264 3261
    if args.len >= capacity {
3265 3262
        return args;
3266 3263
    }
3267 3264
    let mut newArgs: *mut [il::Val] = &mut [];
3268 3265
3269 3266
    for arg in args {
3270 -
        newArgs.append(arg, alloc::arenaAllocator(self.arena));
3267 +
        newArgs.append(arg, allocator);
3271 3268
    }
3272 3269
    for i in args.len..capacity {
3273 -
        newArgs.append(il::Val::Undef, alloc::arenaAllocator(self.arena));
3270 +
        newArgs.append(il::Val::Undef, allocator);
3274 3271
    }
3275 3272
    return (&mut newArgs[..]) as *unsafe mut [il::Val];
3276 3273
}
3277 3274
3278 3275
/// Select a receiver or explicit parameter name from its AST declaration.
test/tests/ssa.argument.growth.rad +6 -3
8 8
    let mut d: u32 = 4;
9 9
    let mut e: u32 = 5;
10 10
    let mut f: u32 = 6;
11 11
    let mut g: u32 = 7;
12 12
    let mut h: u32 = 8;
13 +
    let mut marker: u32 = 17;
13 14
    for index in 0..limit {
14 15
        let mut step: u32 = 0;
15 16
        match index % 3 {
16 -
            case 0 => set step = 1,
17 -
            case 1 => set step = 3,
18 -
            else => set step = 5,
17 +
            case 0 => { set step = 1; set marker = 17; }
18 +
            case 1 => { set step = 3; set marker = 17; }
19 +
            else => { set step = 5; set marker = 17; }
19 20
        }
20 21
        if index % 2 == 0 {
21 22
            set a += step;
22 23
            set c += step * 3;
23 24
            set e += step * 5;
26 27
            set b += step * 2;
27 28
            set d += step * 4;
28 29
            set f += step * 6;
29 30
            set h += step * 8;
30 31
        }
32 +
        assert marker == 17;
31 33
    }
34 +
    assert marker == 17;
32 35
    return a + 2*b + 3*c + 4*d + 5*e + 6*f + 7*g + 8*h;
33 36
}
34 37
35 38
/// Compute the weighted sum without carrying the eight separate values.
36 39
fn expected(limit: u32) -> u32 {