compiler: Borrow local liveness tables in checked code
5d3e041489d25636d3e27b32e6d29403fbae3af231153a7d8d32dd8ee5fc82f2
1 parent
972c0b10
lib/std/lang/gen/regalloc/liveness.rad
+13 -8
| 92 | 92 | let defs = try storage.fill(0 as u32, count); |
|
| 93 | 93 | let uses = try storage.fill(0 as u32, count); |
|
| 94 | 94 | ||
| 95 | 95 | // Compute local defs and uses for each block. |
|
| 96 | 96 | for b in 0..blockCount { |
|
| 97 | - | computeLocalDefsUses(&func.blocks[b], &mut defs[b * words..(b + 1) * words], &mut uses[b * words..(b + 1) * words]); |
|
| 97 | + | let block = &func.blocks[b]; |
|
| 98 | + | computeLocalDefsUses(block.params, block.instrs, &mut defs[b * words..(b + 1) * words], &mut uses[b * words..(b + 1) * words]); |
|
| 98 | 99 | } |
|
| 99 | 100 | // Live sets grow monotonically from empty sets; no scratch set is needed. |
|
| 100 | 101 | let mut changed = true; |
|
| 101 | 102 | ||
| 102 | 103 | while changed { |
| 137 | 138 | } |
|
| 138 | 139 | return changed; |
|
| 139 | 140 | } |
|
| 140 | 141 | ||
| 141 | 142 | /// Compute local defs and uses for a single block. |
|
| 142 | - | unsafe fn computeLocalDefsUses(block: &il::Block, defs: &mut [u32], uses: &mut [u32]) { |
|
| 143 | - | for p in block.params { |
|
| 143 | + | fn computeLocalDefsUses(params: &[il::Param], instructions: &[il::Instr], defs: &mut [u32], uses: &mut [u32]) { |
|
| 144 | + | for p in params { |
|
| 144 | 145 | bitset::put(defs, p.value.n); |
|
| 145 | 146 | } |
|
| 146 | - | for instr in block.instrs { |
|
| 147 | - | let mut registers = il::registers(&instr); |
|
| 148 | - | while let reg = il::nextReg(&mut registers, &instr) { |
|
| 149 | - | addUse(reg, defs, uses); |
|
| 147 | + | for i in 0..instructions.len { |
|
| 148 | + | let instr = &instructions[i]; |
|
| 149 | + | let mut registers = il::registers(instr); |
|
| 150 | + | // Argument groups contain raw views into the function's IL storage. |
|
| 151 | + | unsafe { |
|
| 152 | + | while let reg = il::nextReg(&mut registers, instr) { |
|
| 153 | + | addUse(reg, defs, uses); |
|
| 154 | + | } |
|
| 150 | 155 | } |
|
| 151 | 156 | ||
| 152 | - | if let dst = il::instrDst(instr) { |
|
| 157 | + | if let dst = il::instrDst(*instr) { |
|
| 153 | 158 | bitset::put(defs, dst.n); |
|
| 154 | 159 | } |
|
| 155 | 160 | } |
|
| 156 | 161 | } |
|
| 157 | 162 |
lib/std/lang/gen/regalloc/liveness/tests.rad
+29 -0
| 40 | 40 | try check(super::liveOutRow(&live, 4), false, false, false); |
|
| 41 | 41 | } |
|
| 42 | 42 | } |
|
| 43 | 43 | } |
|
| 44 | 44 | ||
| 45 | + | /// Local uses precede definitions, and block parameters define their registers. |
|
| 46 | + | @test unsafe fn testLocalDefinitionOrder() throws (testing::TestError) { |
|
| 47 | + | let parameter = il::Reg { n: 33 }; |
|
| 48 | + | let temporary = il::Reg { n: 66 }; |
|
| 49 | + | let external = il::Reg { n: 0 }; |
|
| 50 | + | let params = [il::Param { value: parameter, type: il::Type::W64 }]; |
|
| 51 | + | let mut instructions = [ |
|
| 52 | + | il::Instr::BinOp { op: il::BinOp::Add, typ: il::Type::W64, dst: temporary, |
|
| 53 | + | a: il::Val::Reg(external), b: il::Val::Reg(parameter) }, |
|
| 54 | + | il::Instr::Copy { dst: external, val: il::Val::Reg(temporary) }, |
|
| 55 | + | il::Instr::Ret { val: il::Val::Reg(external) }, |
|
| 56 | + | ]; |
|
| 57 | + | let blocks = [il::Block { label: "entry", params: ¶ms[..], |
|
| 58 | + | instrs: &mut instructions[..], locs: &[], preds: &[], loopDepth: 0 }, |
|
| 59 | + | block("empty", &mut [])]; |
|
| 60 | + | let function = il::Fn { name: "local", params: &[], returnType: il::Type::W64, |
|
| 61 | + | isExtern: false, isLeaf: true, blocks: &blocks[..] }; |
|
| 62 | + | static DATA: [u8; 8192] = [0; 8192]; |
|
| 63 | + | let mut arena = alloc::new(&mut DATA[..]); |
|
| 64 | + | use arena as analysis in { |
|
| 65 | + | let live = try! super::analyze(&function, &analysis); |
|
| 66 | + | try check(&live.defs[..live.words], true, true, true); |
|
| 67 | + | try check(&live.uses[..live.words], true, false, false); |
|
| 68 | + | try check(super::liveInRow(&live, 0), true, false, false); |
|
| 69 | + | try check(&live.defs[live.words..], false, false, false); |
|
| 70 | + | try check(&live.uses[live.words..], false, false, false); |
|
| 71 | + | } |
|
| 72 | + | } |
|
| 73 | + | ||
| 45 | 74 | /// Liveness sizes its rows from register operands and definitions. |
|
| 46 | 75 | @test unsafe fn testLargeRegisterExtent() throws (testing::TestError) { |
|
| 47 | 76 | for index in [8191 as u32, 8192, 8193, 16384] { |
|
| 48 | 77 | let source = il::Reg { n: index }; |
|
| 49 | 78 | let destination = il::Reg { n: index + 1 }; |