compiler: Own block instruction storage

b82d80b26439d663506e7ccaa0a9e267386cda63103a1689c6cafb6607981309
Alexis Sellier committed ago 1 parent 6f0b3aec
lib/std/lang/lower.rad +21 -10
536 536
    /// Variable ids in parameter order. Before sealing, these are the variables
537 537
    /// whose predecessor arguments must be resolved.
538 538
    paramVars: *unsafe mut [u32],
539 539
    /// Instructions accumulated so far. The last instruction should eventually
540 540
    /// be a terminator.
541 -
    instrs: *unsafe mut [il::Instr],
541 +
    instrs: *mut [il::Instr],
542 542
    /// Debug source locations, one per instruction. Only populated when
543 543
    /// debug info is enabled.
544 -
    locs: *unsafe mut [il::SrcLoc],
544 +
    locs: *mut [il::SrcLoc],
545 545
    /// Predecessor block ids. Used for SSA construction to propagate values
546 546
    /// from predecessors when a variable is used before being defined locally.
547 547
    preds: *mut [u32],
548 548
    /// The current SSA value of each variable in this block. Indexed by variable
549 549
    /// id. A `nil` means the variable wasn't assigned in this block. Updated by
2256 2256
// Instruction Emission //
2257 2257
//////////////////////////
2258 2258
2259 2259
/// Emit an instruction to the current block.
2260 2260
unsafe fn emit 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, instr: il::Instr) where 'arena: 'phase, 'phase: 'function {
2261 -
    let blk = self.currentBlock else panic;
2262 -
    let mut block = getBlockMut(self, blk);
2261 +
    let allocator = alloc::arenaAllocator(self.arena);
2262 +
    recordInstruction(self, &instr, allocator);
2263 +
}
2263 2264
2265 +
/// Append an instruction and its enabled source location to the current block.
2266 +
fn recordInstruction 'arena 'phase 'function (
2267 +
    self: &mut FnLowerer 'arena 'phase 'function,
2268 +
    instr: &il::Instr,
2269 +
    allocator: alloc::Allocator
2270 +
) where 'arena: 'phase, 'phase: 'function {
2271 +
    let blk = currentBlock(self);
2272 +
    let debug = self.low.options.debug;
2273 +
    let srcLoc = self.srcLoc;
2264 2274
    // Track whether this function is a leaf.
2265 -
    if il::isCall(instr) {
2275 +
    if il::isCall(*instr) {
2266 2276
        set self.isLeaf = false;
2267 2277
    }
2278 +
    let block = &mut self.blockData[*blk];
2268 2279
    // Record source location alongside instruction when enabled.
2269 -
    if self.low.options.debug {
2270 -
        block.locs.append(self.srcLoc, alloc::arenaAllocator(self.arena));
2280 +
    if debug {
2281 +
        block.locs.append(srcLoc, allocator);
2271 2282
    }
2272 -
    block.instrs.append(instr, alloc::arenaAllocator(self.arena));
2283 +
    block.instrs.append(*instr, allocator);
2273 2284
}
2274 2285
2275 2286
/// Emit an unconditional jump to `target`.
2276 2287
unsafe fn emitJmp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2277 2288
    emit(self, il::Instr::Jmp { target: *target, args: &mut [] });
2774 2785
unsafe fn finalizeBlocks 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> *unsafe [il::Block] throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2775 2786
    let mut blocks: *mut [il::Block] = &mut [];
2776 2787
    let allocator = alloc::arenaAllocator(self.arena);
2777 2788
2778 2789
    for i in 0..self.blockData.len {
2779 -
        let data = &self.blockData[i];
2790 +
        let data = &mut self.blockData[i];
2780 2791
2781 2792
        blocks.append(il::Block {
2782 2793
            label: data.label,
2783 2794
            params: &data.params[..],
2784 -
            instrs: data.instrs,
2795 +
            instrs: (&mut data.instrs[..]) as *unsafe mut [il::Instr],
2785 2796
            locs: &data.locs[..],
2786 2797
            preds: &data.preds[..],
2787 2798
            loopDepth: data.loopDepth,
2788 2799
        }, allocator);
2789 2800
    }
test/tests/ssa.instruction.storage.rad added +31 -0
1 +
//! returns: 0
2 +
3 +
/// Leaf computation used by a non-leaf function.
4 +
fn advance(value: u64) -> u64 {
5 +
    return value + 7;
6 +
}
7 +
8 +
/// Retain values across calls and merge their arithmetic results.
9 +
fn combine(value: u64, selected: bool) -> u64 {
10 +
    let first = advance(value);
11 +
    let second = advance(first);
12 +
    let third = advance(second);
13 +
    let mut result = first * 3 + second * 5;
14 +
    if selected {
15 +
        set result += third * 11;
16 +
    } else {
17 +
        set result += third * 13;
18 +
    }
19 +
    return result;
20 +
}
21 +
22 +
/// Check call preservation, leaf state, and repeated instruction emission.
23 +
@default fn main() -> u32 {
24 +
    for index in 0..32 {
25 +
        let value = (index as u64) + 0x100000000;
26 +
        let base = (value + 7) * 3 + (value + 14) * 5;
27 +
        assert combine(value, true) == base + (value + 21) * 11;
28 +
        assert combine(value, false) == base + (value + 21) * 13;
29 +
    }
30 +
    return 0;
31 +
}