compiler: Own block instruction storage
b82d80b26439d663506e7ccaa0a9e267386cda63103a1689c6cafb6607981309
1 parent
6f0b3aec
lib/std/lang/lower.rad
+21 -10
| 536 | 536 | /// Variable ids in parameter order. Before sealing, these are the variables |
|
| 537 | 537 | /// whose predecessor arguments must be resolved. |
|
| 538 | 538 | paramVars: *unsafe mut [u32], |
|
| 539 | 539 | /// Instructions accumulated so far. The last instruction should eventually |
|
| 540 | 540 | /// be a terminator. |
|
| 541 | - | instrs: *unsafe mut [il::Instr], |
|
| 541 | + | instrs: *mut [il::Instr], |
|
| 542 | 542 | /// Debug source locations, one per instruction. Only populated when |
|
| 543 | 543 | /// debug info is enabled. |
|
| 544 | - | locs: *unsafe mut [il::SrcLoc], |
|
| 544 | + | locs: *mut [il::SrcLoc], |
|
| 545 | 545 | /// Predecessor block ids. Used for SSA construction to propagate values |
|
| 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 |
| 2256 | 2256 | // Instruction Emission // |
|
| 2257 | 2257 | ////////////////////////// |
|
| 2258 | 2258 | ||
| 2259 | 2259 | /// Emit an instruction to the current block. |
|
| 2260 | 2260 | unsafe fn emit 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, instr: il::Instr) where 'arena: 'phase, 'phase: 'function { |
|
| 2261 | - | let blk = self.currentBlock else panic; |
|
| 2262 | - | let mut block = getBlockMut(self, blk); |
|
| 2261 | + | let allocator = alloc::arenaAllocator(self.arena); |
|
| 2262 | + | recordInstruction(self, &instr, allocator); |
|
| 2263 | + | } |
|
| 2263 | 2264 | ||
| 2265 | + | /// Append an instruction and its enabled source location to the current block. |
|
| 2266 | + | fn recordInstruction 'arena 'phase 'function ( |
|
| 2267 | + | self: &mut FnLowerer 'arena 'phase 'function, |
|
| 2268 | + | instr: &il::Instr, |
|
| 2269 | + | allocator: alloc::Allocator |
|
| 2270 | + | ) where 'arena: 'phase, 'phase: 'function { |
|
| 2271 | + | let blk = currentBlock(self); |
|
| 2272 | + | let debug = self.low.options.debug; |
|
| 2273 | + | let srcLoc = self.srcLoc; |
|
| 2264 | 2274 | // Track whether this function is a leaf. |
|
| 2265 | - | if il::isCall(instr) { |
|
| 2275 | + | if il::isCall(*instr) { |
|
| 2266 | 2276 | set self.isLeaf = false; |
|
| 2267 | 2277 | } |
|
| 2278 | + | let block = &mut self.blockData[*blk]; |
|
| 2268 | 2279 | // Record source location alongside instruction when enabled. |
|
| 2269 | - | if self.low.options.debug { |
|
| 2270 | - | block.locs.append(self.srcLoc, alloc::arenaAllocator(self.arena)); |
|
| 2280 | + | if debug { |
|
| 2281 | + | block.locs.append(srcLoc, allocator); |
|
| 2271 | 2282 | } |
|
| 2272 | - | block.instrs.append(instr, alloc::arenaAllocator(self.arena)); |
|
| 2283 | + | block.instrs.append(*instr, allocator); |
|
| 2273 | 2284 | } |
|
| 2274 | 2285 | ||
| 2275 | 2286 | /// Emit an unconditional jump to `target`. |
|
| 2276 | 2287 | unsafe fn emitJmp 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId) throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2277 | 2288 | emit(self, il::Instr::Jmp { target: *target, args: &mut [] }); |
| 2774 | 2785 | unsafe fn finalizeBlocks 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> *unsafe [il::Block] throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2775 | 2786 | let mut blocks: *mut [il::Block] = &mut []; |
|
| 2776 | 2787 | let allocator = alloc::arenaAllocator(self.arena); |
|
| 2777 | 2788 | ||
| 2778 | 2789 | for i in 0..self.blockData.len { |
|
| 2779 | - | let data = &self.blockData[i]; |
|
| 2790 | + | let data = &mut self.blockData[i]; |
|
| 2780 | 2791 | ||
| 2781 | 2792 | blocks.append(il::Block { |
|
| 2782 | 2793 | label: data.label, |
|
| 2783 | 2794 | params: &data.params[..], |
|
| 2784 | - | instrs: data.instrs, |
|
| 2795 | + | instrs: (&mut data.instrs[..]) as *unsafe mut [il::Instr], |
|
| 2785 | 2796 | locs: &data.locs[..], |
|
| 2786 | 2797 | preds: &data.preds[..], |
|
| 2787 | 2798 | loopDepth: data.loopDepth, |
|
| 2788 | 2799 | }, allocator); |
|
| 2789 | 2800 | } |
test/tests/ssa.instruction.storage.rad
added
+31 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Leaf computation used by a non-leaf function. |
|
| 4 | + | fn advance(value: u64) -> u64 { |
|
| 5 | + | return value + 7; |
|
| 6 | + | } |
|
| 7 | + | ||
| 8 | + | /// Retain values across calls and merge their arithmetic results. |
|
| 9 | + | fn combine(value: u64, selected: bool) -> u64 { |
|
| 10 | + | let first = advance(value); |
|
| 11 | + | let second = advance(first); |
|
| 12 | + | let third = advance(second); |
|
| 13 | + | let mut result = first * 3 + second * 5; |
|
| 14 | + | if selected { |
|
| 15 | + | set result += third * 11; |
|
| 16 | + | } else { |
|
| 17 | + | set result += third * 13; |
|
| 18 | + | } |
|
| 19 | + | return result; |
|
| 20 | + | } |
|
| 21 | + | ||
| 22 | + | /// Check call preservation, leaf state, and repeated instruction emission. |
|
| 23 | + | @default fn main() -> u32 { |
|
| 24 | + | for index in 0..32 { |
|
| 25 | + | let value = (index as u64) + 0x100000000; |
|
| 26 | + | let base = (value + 7) * 3 + (value + 14) * 5; |
|
| 27 | + | assert combine(value, true) == base + (value + 21) * 11; |
|
| 28 | + | assert combine(value, false) == base + (value + 21) * 13; |
|
| 29 | + | } |
|
| 30 | + | return 0; |
|
| 31 | + | } |