compiler: Own block parameter tables
294a5bd7a2534bdbc98e7865aa292d52f0cd98defbce1bfadb18993e7911158c
1 parent
b82d80b2
lib/std/lang/lower.rad
+10 -9
| 530 | 530 | record BlockData { |
|
| 531 | 531 | /// Block label for debugging and IL printing. |
|
| 532 | 532 | label: *[u8], |
|
| 533 | 533 | /// Block parameters for merging values at control flow joins. These |
|
| 534 | 534 | /// receive values from predecessor edges when control flow merges. |
|
| 535 | - | params: *unsafe mut [il::Param], |
|
| 535 | + | params: *mut [il::Param], |
|
| 536 | 536 | /// Variable ids in parameter order. Before sealing, these are the variables |
|
| 537 | 537 | /// whose predecessor arguments must be resolved. |
|
| 538 | - | paramVars: *unsafe mut [u32], |
|
| 538 | + | paramVars: *mut [u32], |
|
| 539 | 539 | /// Instructions accumulated so far. The last instruction should eventually |
|
| 540 | 540 | /// be a terminator. |
|
| 541 | 541 | instrs: *mut [il::Instr], |
|
| 542 | 542 | /// Debug source locations, one per instruction. Only populated when |
|
| 543 | 543 | /// debug info is enabled. |
| 2087 | 2087 | return sym; |
|
| 2088 | 2088 | } |
|
| 2089 | 2089 | ||
| 2090 | 2090 | /// Remove the last block parameter and its associated variable. |
|
| 2091 | 2091 | /// Used when detecting a trivial phi that can be eliminated. |
|
| 2092 | - | unsafe fn removeLastBlockParam 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, block: BlockId) where 'arena: 'phase, 'phase: 'function { |
|
| 2093 | - | let blk = getBlockMut(self, block); |
|
| 2092 | + | fn removeLastBlockParam 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, block: BlockId) where 'arena: 'phase, 'phase: 'function { |
|
| 2093 | + | let blk = &mut self.blockData[*block]; |
|
| 2094 | 2094 | if blk.params.len > 0 { |
|
| 2095 | 2095 | // TODO: Use `pop`? |
|
| 2096 | - | set blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap); |
|
| 2096 | + | blk.params.delete(blk.params.len - 1); |
|
| 2097 | 2097 | } |
|
| 2098 | 2098 | if blk.paramVars.len > 0 { |
|
| 2099 | 2099 | // TODO: Use `pop`? |
|
| 2100 | - | set blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap); |
|
| 2100 | + | blk.paramVars.delete(blk.paramVars.len - 1); |
|
| 2101 | 2101 | } |
|
| 2102 | 2102 | } |
|
| 2103 | 2103 | ||
| 2104 | 2104 | /// Rewrite cached SSA values for a variable across all blocks, and also |
|
| 2105 | 2105 | /// rewrite any terminator arguments that reference the provisional register. |
| 2216 | 2216 | unsafe fn sealBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, block: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2217 | 2217 | let blk = getBlockMut(self, block); |
|
| 2218 | 2218 | let case Sealed::No = blk.sealState else { |
|
| 2219 | 2219 | return; // Already sealed. |
|
| 2220 | 2220 | }; |
|
| 2221 | - | // Keep the current parameter list. Resolution can add more parameters. |
|
| 2222 | - | let paramVars = blk.paramVars; |
|
| 2221 | + | // Keep the current parameter count. Resolution can add more parameters. |
|
| 2222 | + | let paramCount = blk.paramVars.len; |
|
| 2223 | 2223 | set blk.sealState = Sealed::Yes; |
|
| 2224 | 2224 | ||
| 2225 | 2225 | // Complete each parameter that was created before sealing. |
|
| 2226 | - | for varId, paramIdx in paramVars { |
|
| 2226 | + | for paramIdx in 0..paramCount { |
|
| 2227 | + | let varId = self.blockData[*block].paramVars[paramIdx]; |
|
| 2227 | 2228 | try resolveBlockArgs(self, block, Var(varId), paramIdx); |
|
| 2228 | 2229 | } |
|
| 2229 | 2230 | } |
|
| 2230 | 2231 | ||
| 2231 | 2232 | /// Seal a block and switch to it. |
test/tests/ssa.predecessor.storage.rad
+17 -0
| 20 | 20 | } |
|
| 21 | 21 | } |
|
| 22 | 22 | return total + carry + stable; |
|
| 23 | 23 | } |
|
| 24 | 24 | ||
| 25 | + | /// Merge identical values beside a changing loop counter. |
|
| 26 | + | fn unchanged(limit: u32) -> u32 { |
|
| 27 | + | let mut first: u32 = 7; |
|
| 28 | + | let mut second: u32 = 11; |
|
| 29 | + | let mut count: u32 = 0; |
|
| 30 | + | for index in 0..limit { |
|
| 31 | + | if index % 2 == 0 { |
|
| 32 | + | set first = 7; |
|
| 33 | + | } else { |
|
| 34 | + | set second = 11; |
|
| 35 | + | } |
|
| 36 | + | set count += 1; |
|
| 37 | + | } |
|
| 38 | + | return first + second + count; |
|
| 39 | + | } |
|
| 40 | + | ||
| 25 | 41 | /// Compare both branch paths over empty and repeated loop iterations. |
|
| 26 | 42 | @default fn main() -> u32 { |
|
| 27 | 43 | for limit in 0..32 { |
|
| 44 | + | assert unchanged(limit) == 18 + limit; |
|
| 28 | 45 | for choose in [false, true] { |
|
| 29 | 46 | let mut total: u32 = 3; |
|
| 30 | 47 | let mut carry: u32 = 5; |
|
| 31 | 48 | for index in 0..limit { |
|
| 32 | 49 | set carry += 7 if choose and index % 2 == 0 else 13; |