compiler: Initialize block caches in checked construction
b229c0660397974dd2df9c1513c1258b02e104f61276e3dd597d4a1ba521a38c
1 parent
447c3f8a
lib/std/lang/lower.rad
+6 -9
| 2175 | 2175 | /// Returns a [`BlockId`] that can be used for jumps and branches. The block must |
|
| 2176 | 2176 | /// be switched to via [`switchToBlock`] before instructions can be emitted. |
|
| 2177 | 2177 | unsafe fn createBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, labelBase: *[u8]) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2178 | 2178 | let label = try nextLabel(self, labelBase); |
|
| 2179 | 2179 | let varCount = self.localCount; |
|
| 2180 | - | let vars = try! alloc::allocSlice( |
|
| 2181 | - | self.arena, @sizeOf(?il::Val), @alignOf(?il::Val), varCount |
|
| 2182 | - | ) as *mut [?il::Val]; |
|
| 2183 | - | ||
| 2184 | - | for i in 0..varCount { |
|
| 2185 | - | set vars[i] = nil; |
|
| 2186 | - | } |
|
| 2187 | 2180 | let allocator = alloc::arenaAllocator(self.arena); |
|
| 2188 | 2181 | let depth = self.loopDepth; |
|
| 2189 | - | return appendBlock(&mut self.blockData, label, vars, depth, allocator); |
|
| 2182 | + | return appendBlock(&mut self.blockData, label, varCount, depth, allocator); |
|
| 2190 | 2183 | } |
|
| 2191 | 2184 | ||
| 2192 | 2185 | /// Append a complete unsealed block with initialized variable slots. |
|
| 2193 | 2186 | fn appendBlock( |
|
| 2194 | 2187 | blocks: &mut *mut [BlockData], |
|
| 2195 | 2188 | label: *[u8], |
|
| 2196 | - | vars: *mut [?il::Val], |
|
| 2189 | + | varCount: u32, |
|
| 2197 | 2190 | loopDepth: u32, |
|
| 2198 | 2191 | allocator: alloc::Allocator, |
|
| 2199 | 2192 | ) -> BlockId { |
|
| 2200 | 2193 | let id = BlockId(blocks.len); |
|
| 2194 | + | let mut vars: *mut [?il::Val] = &mut []; |
|
| 2195 | + | for i in 0..varCount { |
|
| 2196 | + | vars.append(nil, allocator); |
|
| 2197 | + | } |
|
| 2201 | 2198 | blocks.append(BlockData { |
|
| 2202 | 2199 | label, |
|
| 2203 | 2200 | params: &mut [], |
|
| 2204 | 2201 | paramVars: &mut [], |
|
| 2205 | 2202 | instrs: &mut [], |
test/tests/ssa.cache.values.rad
+18 -0
| 19 | 19 | ||
| 20 | 20 | /// Exercise a function with no local cache entries. |
|
| 21 | 21 | fn empty() { |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | + | /// Preserve cached values across continue and break edges. |
|
| 25 | + | fn exits(limit: u32, start: u64) -> u64 { |
|
| 26 | + | let mut result = start; |
|
| 27 | + | for index in 0..limit { |
|
| 28 | + | if index == 7 { |
|
| 29 | + | break; |
|
| 30 | + | } |
|
| 31 | + | if index % 2 == 0 { |
|
| 32 | + | continue; |
|
| 33 | + | } |
|
| 34 | + | set result += index as u64; |
|
| 35 | + | } |
|
| 36 | + | return result; |
|
| 37 | + | } |
|
| 38 | + | ||
| 24 | 39 | /// Compare cache joins with the closed-form sums of odd and even integers. |
|
| 25 | 40 | @default fn main() -> u32 { |
|
| 26 | 41 | for start in [0 as u64, 0x100000001, 0x8000000000000000] { |
|
| 27 | 42 | for limit in 0..32 { |
|
| 28 | 43 | empty(); |
| 30 | 45 | let evens = (limit / 2) as u64; |
|
| 31 | 46 | let first = start + odds * odds; |
|
| 32 | 47 | let second = start + 2 * evens * (evens + 1); |
|
| 33 | 48 | assert run(limit, start) == first ^ second; |
|
| 34 | 49 | assert run(limit, start) == first ^ second; |
|
| 50 | + | let bound: u32 = 7 if limit > 7 else limit; |
|
| 51 | + | let count = (bound / 2) as u64; |
|
| 52 | + | assert exits(limit, start) == start + count * count; |
|
| 35 | 53 | } |
|
| 36 | 54 | } |
|
| 37 | 55 | return 0; |
|
| 38 | 56 | } |