compiler: Borrow owned blocks during SSA mutation
10f56b0500a320f753e749ee18e03c951761ebcaaf7b55dffa1a4e4f56dbf788
1 parent
9066f1a3
lib/std/lang/lower.rad
+12 -15
| 2118 | 2118 | /// The latter is necessary because recursive SSA resolution may have already |
|
| 2119 | 2119 | /// patched terminator arguments with the provisional value before it was |
|
| 2120 | 2120 | /// found to be trivial. |
|
| 2121 | 2121 | unsafe fn rewriteCachedVarValue 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, v: Var, from: il::Val, to: il::Val) where 'arena: 'phase, 'phase: 'function { |
|
| 2122 | 2122 | for i in 0..self.blockData.len { |
|
| 2123 | - | let blk = getBlockMut(self, BlockId(i)); |
|
| 2123 | + | let blk = &mut self.blockData[i]; |
|
| 2124 | 2124 | if blk.vars[*v] == from { |
|
| 2125 | 2125 | set blk.vars[*v] = to; |
|
| 2126 | 2126 | } |
|
| 2127 | 2127 | if blk.instrs.len > 0 { |
|
| 2128 | 2128 | let ix = blk.instrs.len - 1; |
| 2255 | 2255 | /// Get the number of predecessors for a block. |
|
| 2256 | 2256 | fn predecessorCount(blocks: &[BlockData], block: BlockId) -> u32 { |
|
| 2257 | 2257 | return blocks[*block].preds.len; |
|
| 2258 | 2258 | } |
|
| 2259 | 2259 | ||
| 2260 | - | /// Get mutable block data by block id. |
|
| 2261 | - | unsafe fn getBlockMut 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, block: BlockId) -> *unsafe mut BlockData where 'arena: 'phase, 'phase: 'function { |
|
| 2262 | - | return &mut self.blockData[*block]; |
|
| 2263 | - | } |
|
| 2264 | - | ||
| 2265 | 2260 | /// Get the current block being built. |
|
| 2266 | 2261 | fn currentBlock 'arena 'phase 'function (self: &FnLowerer 'arena 'phase 'function) -> BlockId where 'arena: 'phase, 'phase: 'function { |
|
| 2267 | 2262 | let block = self.currentBlock else { |
|
| 2268 | 2263 | panic "currentBlock: no current block"; |
|
| 2269 | 2264 | }; |
| 3217 | 3212 | from: BlockId, // The predecessor block containing the terminator to patch. |
|
| 3218 | 3213 | target: u32, // The index of the target block we're passing the value to. |
|
| 3219 | 3214 | paramIdx: u32, // The index of the block parameter to set. |
|
| 3220 | 3215 | val: il::Val // The value to pass as the argument. |
|
| 3221 | 3216 | ) where 'arena: 'phase, 'phase: 'function { |
|
| 3222 | - | let data = getBlockMut(self, from); |
|
| 3217 | + | let allocator = alloc::arenaAllocator(self.arena); |
|
| 3218 | + | // Get mutable block data by block id. |
|
| 3219 | + | let data = &mut self.blockData[*from]; |
|
| 3223 | 3220 | let ix = data.instrs.len - 1; // The terminator is always the last instruction. |
|
| 3224 | 3221 | ||
| 3225 | 3222 | // TODO: We shouldn't need to use a mutable subscript here, given that the |
|
| 3226 | 3223 | // fields are already mutable. |
|
| 3227 | 3224 | match &mut data.instrs[ix] { |
|
| 3228 | 3225 | case il::Instr::Jmp { args, .. } => { |
|
| 3229 | - | set *args = growArgs(self, *args, paramIdx + 1); |
|
| 3226 | + | set *args = growArgs(*args, paramIdx + 1, allocator); |
|
| 3230 | 3227 | set args[paramIdx] = val; |
|
| 3231 | 3228 | } |
|
| 3232 | 3229 | case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => { |
|
| 3233 | 3230 | // Nb. both branches could target the same block (e.g. `if cond { x } else { x }`). |
|
| 3234 | 3231 | if *thenTarget == target { |
|
| 3235 | - | set *thenArgs = growArgs(self, *thenArgs, paramIdx + 1); |
|
| 3232 | + | set *thenArgs = growArgs(*thenArgs, paramIdx + 1, allocator); |
|
| 3236 | 3233 | set thenArgs[paramIdx] = val; |
|
| 3237 | 3234 | } |
|
| 3238 | 3235 | if *elseTarget == target { |
|
| 3239 | - | set *elseArgs = growArgs(self, *elseArgs, paramIdx + 1); |
|
| 3236 | + | set *elseArgs = growArgs(*elseArgs, paramIdx + 1, allocator); |
|
| 3240 | 3237 | set elseArgs[paramIdx] = val; |
|
| 3241 | 3238 | } |
|
| 3242 | 3239 | } |
|
| 3243 | 3240 | case il::Instr::Switch { defaultTarget, defaultArgs, cases, .. } => { |
|
| 3244 | 3241 | if *defaultTarget == target { |
|
| 3245 | - | set *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1); |
|
| 3242 | + | set *defaultArgs = growArgs(*defaultArgs, paramIdx + 1, allocator); |
|
| 3246 | 3243 | set defaultArgs[paramIdx] = val; |
|
| 3247 | 3244 | } |
|
| 3248 | 3245 | let idx = paramIdx + 1; |
|
| 3249 | 3246 | for ci in 0..cases.len { |
|
| 3250 | 3247 | if cases[ci].target == target { |
|
| 3251 | - | set cases[ci].args = growArgs(self, cases[ci].args, idx); |
|
| 3248 | + | set cases[ci].args = growArgs(cases[ci].args, idx, allocator); |
|
| 3252 | 3249 | set cases[ci].args[paramIdx] = val; |
|
| 3253 | 3250 | } |
|
| 3254 | 3251 | } |
|
| 3255 | 3252 | } |
|
| 3256 | 3253 | else => { |
| 3258 | 3255 | } |
|
| 3259 | 3256 | } |
|
| 3260 | 3257 | } |
|
| 3261 | 3258 | ||
| 3262 | 3259 | /// Grow an args array to hold at least the given capacity. |
|
| 3263 | - | unsafe fn growArgs 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, args: *unsafe mut [il::Val], capacity: u32) -> *unsafe mut [il::Val] where 'arena: 'phase, 'phase: 'function { |
|
| 3260 | + | unsafe fn growArgs(args: *unsafe mut [il::Val], capacity: u32, allocator: alloc::Allocator) -> *unsafe mut [il::Val] { |
|
| 3264 | 3261 | if args.len >= capacity { |
|
| 3265 | 3262 | return args; |
|
| 3266 | 3263 | } |
|
| 3267 | 3264 | let mut newArgs: *mut [il::Val] = &mut []; |
|
| 3268 | 3265 | ||
| 3269 | 3266 | for arg in args { |
|
| 3270 | - | newArgs.append(arg, alloc::arenaAllocator(self.arena)); |
|
| 3267 | + | newArgs.append(arg, allocator); |
|
| 3271 | 3268 | } |
|
| 3272 | 3269 | for i in args.len..capacity { |
|
| 3273 | - | newArgs.append(il::Val::Undef, alloc::arenaAllocator(self.arena)); |
|
| 3270 | + | newArgs.append(il::Val::Undef, allocator); |
|
| 3274 | 3271 | } |
|
| 3275 | 3272 | return (&mut newArgs[..]) as *unsafe mut [il::Val]; |
|
| 3276 | 3273 | } |
|
| 3277 | 3274 | ||
| 3278 | 3275 | /// Select a receiver or explicit parameter name from its AST declaration. |
test/tests/ssa.argument.growth.rad
+6 -3
| 8 | 8 | let mut d: u32 = 4; |
|
| 9 | 9 | let mut e: u32 = 5; |
|
| 10 | 10 | let mut f: u32 = 6; |
|
| 11 | 11 | let mut g: u32 = 7; |
|
| 12 | 12 | let mut h: u32 = 8; |
|
| 13 | + | let mut marker: u32 = 17; |
|
| 13 | 14 | for index in 0..limit { |
|
| 14 | 15 | let mut step: u32 = 0; |
|
| 15 | 16 | match index % 3 { |
|
| 16 | - | case 0 => set step = 1, |
|
| 17 | - | case 1 => set step = 3, |
|
| 18 | - | else => set step = 5, |
|
| 17 | + | case 0 => { set step = 1; set marker = 17; } |
|
| 18 | + | case 1 => { set step = 3; set marker = 17; } |
|
| 19 | + | else => { set step = 5; set marker = 17; } |
|
| 19 | 20 | } |
|
| 20 | 21 | if index % 2 == 0 { |
|
| 21 | 22 | set a += step; |
|
| 22 | 23 | set c += step * 3; |
|
| 23 | 24 | set e += step * 5; |
| 26 | 27 | set b += step * 2; |
|
| 27 | 28 | set d += step * 4; |
|
| 28 | 29 | set f += step * 6; |
|
| 29 | 30 | set h += step * 8; |
|
| 30 | 31 | } |
|
| 32 | + | assert marker == 17; |
|
| 31 | 33 | } |
|
| 34 | + | assert marker == 17; |
|
| 32 | 35 | return a + 2*b + 3*c + 4*d + 5*e + 6*f + 7*g + 8*h; |
|
| 33 | 36 | } |
|
| 34 | 37 | ||
| 35 | 38 | /// Compute the weighted sum without carrying the eight separate values. |
|
| 36 | 39 | fn expected(limit: u32) -> u32 { |