compiler: Check complete block construction

6a788bde93685bb45da1f6270c866daa00b78b29c4b1b828e59bc326c81cea50
Alexis Sellier committed ago 1 parent 10f56b05
lib/std/lang/lower.rad +17 -4
2175 2175
/// The block is initially unsealed (predecessors may be added later) and empty.
2176 2176
/// Returns a [`BlockId`] that can be used for jumps and branches. The block must
2177 2177
/// be switched to via [`switchToBlock`] before instructions can be emitted.
2178 2178
unsafe fn createBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, labelBase: *[u8]) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2179 2179
    let label = try nextLabel(self, labelBase);
2180 -
    let id = BlockId(self.blockData.len);
2181 2180
    let varCount = self.localCount;
2182 2181
    let vars = try! alloc::allocSlice(
2183 2182
        self.arena, @sizeOf(?il::Val), @alignOf(?il::Val), varCount
2184 2183
    ) as *mut [?il::Val];
2185 2184
2186 2185
    for i in 0..varCount {
2187 2186
        set vars[i] = nil;
2188 2187
    }
2189 -
    self.blockData.append(BlockData {
2188 +
    let allocator = alloc::arenaAllocator(self.arena);
2189 +
    let depth = self.loopDepth;
2190 +
    return appendBlock(&mut self.blockData, label, vars, depth, allocator);
2191 +
}
2192 +
2193 +
/// Append a complete unsealed block with initialized variable slots.
2194 +
fn appendBlock(
2195 +
    blocks: &mut *mut [BlockData],
2196 +
    label: *[u8],
2197 +
    vars: *mut [?il::Val],
2198 +
    loopDepth: u32,
2199 +
    allocator: alloc::Allocator,
2200 +
) -> BlockId {
2201 +
    let id = BlockId(blocks.len);
2202 +
    blocks.append(BlockData {
2190 2203
        label,
2191 2204
        params: &mut [],
2192 2205
        paramVars: &mut [],
2193 2206
        instrs: &mut [],
2194 2207
        locs: &mut [],
2195 2208
        preds: &mut [],
2196 2209
        vars,
2197 2210
        sealState: Sealed::No,
2198 -
        loopDepth: self.loopDepth,
2199 -
    }, alloc::arenaAllocator(self.arena));
2211 +
        loopDepth,
2212 +
    }, allocator);
2200 2213
2201 2214
    return id;
2202 2215
}
2203 2216
2204 2217
/// Create a new block with a single parameter.
test/tests/ssa.block.storage.rad +11 -0
22 22
        set total += value;
23 23
    }
24 24
    return total;
25 25
}
26 26
27 +
/// Return through either a loop-body block or the final block.
28 +
fn early(limit: u32) -> u32 {
29 +
    for index in 0..limit {
30 +
        if index == 3 {
31 +
            return index;
32 +
        }
33 +
    }
34 +
    return limit;
35 +
}
36 +
27 37
/// Compare repeated branch and loop execution with a straight-line reference.
28 38
@default fn main() -> u32 {
29 39
    let values = [11 as u32, 13, 17, 19];
30 40
    for limit in 0..24 {
41 +
        assert early(limit) == (3 if limit > 3 else limit);
31 42
        let mut all: u32 = 7;
32 43
        let mut odd: u32 = 7;
33 44
        for index in 1..16 {
34 45
            if index <= limit {
35 46
                set all += values[index % 4];