compiler: Own SSA variable caches
6f0b3aeca38af341aeb397eb847e196d04df154ee6668d2fe35324338f138856
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 | + | } |