compiler: Check SSA edge patch selection
50f94c5d7e20dd763a860dfc337ff555455c6ff64c588f7990753aa23f4a07a6
1 parent
5a3af878
lib/std/lang/lower.rad
+37 -15
| 3224 | 3224 | ) where 'arena: 'phase, 'phase: 'function { |
|
| 3225 | 3225 | let allocator = alloc::arenaAllocator(self.arena); |
|
| 3226 | 3226 | // Get mutable block data by block id. |
|
| 3227 | 3227 | let data = &mut self.blockData[*from]; |
|
| 3228 | 3228 | let ix = data.instrs.len - 1; // The terminator is always the last instruction. |
|
| 3229 | + | patchEdgeArgs(&mut data.instrs[ix], target, paramIdx, val, allocator); |
|
| 3230 | + | } |
|
| 3229 | 3231 | ||
| 3232 | + | /// Patch all edges in a terminator that pass a value to the target block. |
|
| 3233 | + | fn patchEdgeArgs(instr: &mut il::Instr, target: u32, paramIdx: u32, val: il::Val, allocator: alloc::Allocator) { |
|
| 3230 | 3234 | // TODO: We shouldn't need to use a mutable subscript here, given that the |
|
| 3231 | 3235 | // fields are already mutable. |
|
| 3232 | - | match &mut data.instrs[ix] { |
|
| 3236 | + | match instr { |
|
| 3233 | 3237 | case il::Instr::Jmp { args, .. } => { |
|
| 3234 | - | set *args = growArgs(*args, paramIdx + 1, allocator); |
|
| 3235 | - | set args[paramIdx] = val; |
|
| 3238 | + | unsafe { |
|
| 3239 | + | set *args = growArgs(*args, paramIdx + 1, allocator); |
|
| 3240 | + | set args[paramIdx] = val; |
|
| 3241 | + | } |
|
| 3236 | 3242 | } |
|
| 3237 | 3243 | case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => { |
|
| 3238 | 3244 | // Nb. both branches could target the same block (e.g. `if cond { x } else { x }`). |
|
| 3239 | 3245 | if *thenTarget == target { |
|
| 3240 | - | set *thenArgs = growArgs(*thenArgs, paramIdx + 1, allocator); |
|
| 3241 | - | set thenArgs[paramIdx] = val; |
|
| 3246 | + | unsafe { |
|
| 3247 | + | set *thenArgs = growArgs(*thenArgs, paramIdx + 1, allocator); |
|
| 3248 | + | set thenArgs[paramIdx] = val; |
|
| 3249 | + | } |
|
| 3242 | 3250 | } |
|
| 3243 | 3251 | if *elseTarget == target { |
|
| 3244 | - | set *elseArgs = growArgs(*elseArgs, paramIdx + 1, allocator); |
|
| 3245 | - | set elseArgs[paramIdx] = val; |
|
| 3252 | + | unsafe { |
|
| 3253 | + | set *elseArgs = growArgs(*elseArgs, paramIdx + 1, allocator); |
|
| 3254 | + | set elseArgs[paramIdx] = val; |
|
| 3255 | + | } |
|
| 3246 | 3256 | } |
|
| 3247 | 3257 | } |
|
| 3248 | 3258 | case il::Instr::Switch { defaultTarget, defaultArgs, cases, .. } => { |
|
| 3249 | 3259 | if *defaultTarget == target { |
|
| 3250 | - | set *defaultArgs = growArgs(*defaultArgs, paramIdx + 1, allocator); |
|
| 3251 | - | set defaultArgs[paramIdx] = val; |
|
| 3252 | - | } |
|
| 3253 | - | let idx = paramIdx + 1; |
|
| 3254 | - | for ci in 0..cases.len { |
|
| 3255 | - | if cases[ci].target == target { |
|
| 3256 | - | set cases[ci].args = growArgs(cases[ci].args, idx, allocator); |
|
| 3257 | - | set cases[ci].args[paramIdx] = val; |
|
| 3260 | + | unsafe { |
|
| 3261 | + | set *defaultArgs = growArgs(*defaultArgs, paramIdx + 1, allocator); |
|
| 3262 | + | set defaultArgs[paramIdx] = val; |
|
| 3258 | 3263 | } |
|
| 3259 | 3264 | } |
|
| 3265 | + | unsafe { |
|
| 3266 | + | patchSwitchArgs(*cases, target, paramIdx, val, allocator); |
|
| 3267 | + | } |
|
| 3260 | 3268 | } |
|
| 3261 | 3269 | else => { |
|
| 3262 | 3270 | // Other terminators (e.g. `Ret`, `Unreachable`) don't have successor blocks. |
|
| 3263 | 3271 | } |
|
| 3264 | 3272 | } |
|
| 3265 | 3273 | } |
|
| 3266 | 3274 | ||
| 3275 | + | /// Patch every switch case that passes a value to the target block. |
|
| 3276 | + | fn patchSwitchArgs(cases: &mut [il::SwitchCase], target: u32, paramIdx: u32, val: il::Val, allocator: alloc::Allocator) { |
|
| 3277 | + | let capacity = paramIdx + 1; |
|
| 3278 | + | for i in 0..cases.len { |
|
| 3279 | + | let branch = &mut cases[i]; |
|
| 3280 | + | if branch.target == target { |
|
| 3281 | + | unsafe { |
|
| 3282 | + | set branch.args = growArgs(branch.args, capacity, allocator); |
|
| 3283 | + | set branch.args[paramIdx] = val; |
|
| 3284 | + | } |
|
| 3285 | + | } |
|
| 3286 | + | } |
|
| 3287 | + | } |
|
| 3288 | + | ||
| 3267 | 3289 | /// Grow an args array to hold at least the given capacity. |
|
| 3268 | 3290 | unsafe fn growArgs(args: *unsafe mut [il::Val], capacity: u32, allocator: alloc::Allocator) -> *unsafe mut [il::Val] { |
|
| 3269 | 3291 | if args.len >= capacity { |
|
| 3270 | 3292 | return args; |
|
| 3271 | 3293 | } |