compiler: Own SSA variable caches

6f0b3aeca38af341aeb397eb847e196d04df154ee6668d2fe35324338f138856
Alexis Sellier committed ago 1 parent a9e07213
lib/std/lang/lower.rad +6 -5
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
550 550
    /// [`defVar`], queried by [`useVarInBlock`].
551 -
    vars: *unsafe mut [?il::Val],
551 +
    vars: *mut [?il::Val],
552 552
    /// Sealing state. Once sealed, all predecessors are known and we can resolve
553 553
    /// variable uses that need to pull values from predecessors.
554 554
    sealState: Sealed,
555 555
    /// Loop nesting depth when this block was created.
556 556
    loopDepth: u32,
2179 2179
        params: &mut [],
2180 2180
        paramVars: &mut [],
2181 2181
        instrs: &mut [],
2182 2182
        locs: &mut [],
2183 2183
        preds: &mut [],
2184 -
        vars: (&mut vars[..]) as *unsafe mut [?il::Val],
2184 +
        vars,
2185 2185
        sealState: Sealed::No,
2186 2186
        loopDepth: self.loopDepth,
2187 2187
    }, alloc::arenaAllocator(self.arena));
2188 2188
2189 2189
    return id;
2935 2935
// a block parameter, but defer filling in the terminator arguments. When the
2936 2936
// block is later sealed via [`sealBlock`], all incomplete block params are resolved.
2937 2937
2938 2938
/// Declare a new source-level variable and define its initial value.
2939 2939
/// If called before any block exists (e.g., for parameters), the definition is skipped.
2940 -
unsafe fn newVar 'arena 'phase 'function (
2940 +
fn newVar 'arena 'phase 'function (
2941 2941
    self: &mut FnLowerer 'arena 'phase 'function,
2942 2942
    name: ?*[u8],
2943 2943
    type: il::Type,
2944 2944
    mutable: bool,
2945 2945
    val: il::Val
2957 2957
2958 2958
/// Define (write) a variable. Record the SSA value of a variable in the
2959 2959
/// current block. Called when a variable is assigned or initialized (`let`
2960 2960
/// bindings, assignments, loop updates). When [`useVar`] is later called,
2961 2961
/// it will retrieve this value.
2962 -
unsafe fn defVar 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, val: il::Val) where 'arena: 'phase, 'phase: 'function {
2962 +
fn defVar 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, val: il::Val) where 'arena: 'phase, 'phase: 'function {
2963 2963
    assert *v < self.vars.len;
2964 -
    set getBlockMut(self, currentBlock(self)).vars[*v] = val;
2964 +
    let block = currentBlock(self);
2965 +
    set self.blockData[*block].vars[*v] = val;
2965 2966
}
2966 2967
2967 2968
/// Use (read) the current value of a variable in the current block.
2968 2969
/// May insert block parameters if the value must come from predecessors.
2969 2970
unsafe fn useVar 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var) -> il::Val throws (LowerError) where 'arena: 'phase, 'phase: 'function {
test/tests/ssa.cache.values.rad added +38 -0
1 +
//! returns: 0
2 +
3 +
/// Keep two full-width values and a boolean live across alternating joins.
4 +
fn run(limit: u32, start: u64) -> u64 {
5 +
    let mut first = start;
6 +
    let mut second = start;
7 +
    let mut selected = true;
8 +
    for index in 0..limit {
9 +
        let amount = (index as u64) + 1;
10 +
        if selected {
11 +
            set first += amount;
12 +
        } else {
13 +
            set second += 2 * amount;
14 +
        }
15 +
        set selected = not selected;
16 +
    }
17 +
    return first ^ second;
18 +
}
19 +
20 +
/// Exercise a function with no local cache entries.
21 +
fn empty() {
22 +
}
23 +
24 +
/// Compare cache joins with the closed-form sums of odd and even integers.
25 +
@default fn main() -> u32 {
26 +
    for start in [0 as u64, 0x100000001, 0x8000000000000000] {
27 +
        for limit in 0..32 {
28 +
            empty();
29 +
            let odds = ((limit + 1) / 2) as u64;
30 +
            let evens = (limit / 2) as u64;
31 +
            let first = start + odds * odds;
32 +
            let second = start + 2 * evens * (evens + 1);
33 +
            assert run(limit, start) == first ^ second;
34 +
            assert run(limit, start) == first ^ second;
35 +
        }
36 +
    }
37 +
    return 0;
38 +
}