compiler: Check branch instruction printing
3b4ce6f2f680fc5ea207eaa03a60fc3a199c297e5b48db079f378044f470e928
1 parent
b1a85855
lib/std/lang/il/printer.rad
+34 -22
| 177 | 177 | ////////////////////////// |
|
| 178 | 178 | // Instruction printing // |
|
| 179 | 179 | ////////////////////////// |
|
| 180 | 180 | ||
| 181 | 181 | /// Write an instruction. |
|
| 182 | - | unsafe fn writeInstr(out: &mut opaque sexpr::Output, blocks: *unsafe [super::Block], inst: super::Instr) { |
|
| 182 | + | unsafe fn writeInstr(out: &mut opaque sexpr::Output, blocks: &[super::Block], inst: super::Instr) { |
|
| 183 | 183 | match inst { |
|
| 184 | 184 | case super::Instr::Call { args, .. } => writeOperandInstr(out, inst, args), |
|
| 185 | 185 | ||
| 186 | 186 | case super::Instr::Jmp { target, args } => { |
|
| 187 | 187 | write(out, "jmp "); |
|
| 188 | 188 | writeTarget(out, blocks, target, args); |
|
| 189 | 189 | } |
|
| 190 | - | case super::Instr::Br { op, typ, a: va, b: vb, thenTarget, thenArgs, elseTarget, elseArgs } => { |
|
| 191 | - | write(out, "br."); |
|
| 192 | - | match op { |
|
| 193 | - | case super::CmpOp::Eq => write(out, "eq"), |
|
| 194 | - | case super::CmpOp::Ne => write(out, "ne"), |
|
| 195 | - | case super::CmpOp::Slt => write(out, "slt"), |
|
| 196 | - | case super::CmpOp::Ult => write(out, "ult"), |
|
| 197 | - | } |
|
| 198 | - | write(out, " "); |
|
| 199 | - | writeType(out, typ); |
|
| 200 | - | write(out, " "); |
|
| 201 | - | writeVal(out, va); |
|
| 202 | - | write(out, " "); |
|
| 203 | - | writeVal(out, vb); |
|
| 204 | - | write(out, " "); |
|
| 205 | - | writeTarget(out, blocks, thenTarget, thenArgs); |
|
| 206 | - | write(out, " "); |
|
| 207 | - | writeTarget(out, blocks, elseTarget, elseArgs); |
|
| 208 | - | } |
|
| 190 | + | case super::Instr::Br { thenArgs, elseArgs, .. } => |
|
| 191 | + | writeBranch(out, blocks, inst, thenArgs, elseArgs), |
|
| 209 | 192 | case super::Instr::Switch { val, defaultTarget, defaultArgs, cases } => { |
|
| 210 | 193 | write(out, "switch "); |
|
| 211 | 194 | writeVal(out, val); |
|
| 212 | 195 | for c in cases { |
|
| 213 | 196 | write(out, " ("); |
| 221 | 204 | } |
|
| 222 | 205 | else => writeOperandInstr(out, inst, &[]), |
|
| 223 | 206 | } |
|
| 224 | 207 | } |
|
| 225 | 208 | ||
| 209 | + | /// Write a comparison and both of its control-flow edges. |
|
| 210 | + | fn writeBranch( |
|
| 211 | + | out: &mut opaque sexpr::Output, |
|
| 212 | + | blocks: &[super::Block], |
|
| 213 | + | inst: super::Instr, |
|
| 214 | + | thenArgs: &[super::Val], |
|
| 215 | + | elseArgs: &[super::Val], |
|
| 216 | + | ) { |
|
| 217 | + | let case super::Instr::Br { op, typ, a: va, b: vb, thenTarget, elseTarget, .. } = inst |
|
| 218 | + | else panic "writeBranch: expected branch"; |
|
| 219 | + | write(out, "br."); |
|
| 220 | + | match op { |
|
| 221 | + | case super::CmpOp::Eq => write(out, "eq"), |
|
| 222 | + | case super::CmpOp::Ne => write(out, "ne"), |
|
| 223 | + | case super::CmpOp::Slt => write(out, "slt"), |
|
| 224 | + | case super::CmpOp::Ult => write(out, "ult"), |
|
| 225 | + | } |
|
| 226 | + | write(out, " "); |
|
| 227 | + | writeType(out, typ); |
|
| 228 | + | write(out, " "); |
|
| 229 | + | writeVal(out, va); |
|
| 230 | + | write(out, " "); |
|
| 231 | + | writeVal(out, vb); |
|
| 232 | + | write(out, " "); |
|
| 233 | + | writeTarget(out, blocks, thenTarget, thenArgs); |
|
| 234 | + | write(out, " "); |
|
| 235 | + | writeTarget(out, blocks, elseTarget, elseArgs); |
|
| 236 | + | } |
|
| 237 | + | ||
| 226 | 238 | /// Write a target label and its optional block arguments. |
|
| 227 | 239 | fn writeTarget(out: &mut opaque sexpr::Output, blocks: &[super::Block], target: u32, args: &[super::Val]) { |
|
| 228 | 240 | write(out, "@"); |
|
| 229 | 241 | write(out, blocks[target].label); |
|
| 230 | 242 | if args.len > 0 { |
| 401 | 413 | //////////////////// |
|
| 402 | 414 | // Block printing // |
|
| 403 | 415 | //////////////////// |
|
| 404 | 416 | ||
| 405 | 417 | /// Write a basic block. |
|
| 406 | - | unsafe fn writeBlock(out: &mut opaque sexpr::Output, blocks: *unsafe [super::Block], block: *unsafe super::Block) { |
|
| 418 | + | unsafe fn writeBlock(out: &mut opaque sexpr::Output, blocks: &[super::Block], block: &super::Block) { |
|
| 407 | 419 | // Block label. |
|
| 408 | 420 | write(out, " @"); |
|
| 409 | 421 | write(out, block.label); |
|
| 410 | 422 | ||
| 411 | 423 | // Block parameters. |
| 427 | 439 | /////////////////////// |
|
| 428 | 440 | // Function printing // |
|
| 429 | 441 | /////////////////////// |
|
| 430 | 442 | ||
| 431 | 443 | /// Write a function. |
|
| 432 | - | unsafe fn writeFn(out: &mut opaque sexpr::Output, f: *unsafe super::Fn) { |
|
| 444 | + | unsafe fn writeFn(out: &mut opaque sexpr::Output, f: &super::Fn) { |
|
| 433 | 445 | // Function signature. |
|
| 434 | 446 | if f.isExtern { |
|
| 435 | 447 | write(out, "extern "); |
|
| 436 | 448 | } |
|
| 437 | 449 | write(out, "fn "); |
lib/std/lang/il/tests.rad
+9 -6
| 8 | 8 | unsafe fn checkPrintedInstruction(instr: super::Instr, expected: &[u8]) throws (testing::TestError) { |
|
| 9 | 9 | let mut instructions = [instr]; |
|
| 10 | 10 | let blocks = [super::Block { |
|
| 11 | 11 | label: "entry", params: &[], instrs: &mut instructions[..], |
|
| 12 | 12 | locs: &[], preds: &[], loopDepth: 0, |
|
| 13 | + | }, super::Block { |
|
| 14 | + | label: "exit", params: &[], instrs: &mut [], |
|
| 15 | + | locs: &[], preds: &[], loopDepth: 0, |
|
| 13 | 16 | }]; |
|
| 14 | 17 | let function = super::Fn { |
|
| 15 | 18 | name: "sample", params: &[], returnType: super::Type::W64, |
|
| 16 | 19 | isExtern: false, isLeaf: true, blocks: &blocks[..], |
|
| 17 | 20 | }; |
| 86 | 89 | let mut args = [value, other]; |
|
| 87 | 90 | try checkPrintedInstruction(super::Instr::Jmp { target: 0, args: &mut [] }, "jmp @entry"); |
|
| 88 | 91 | try checkPrintedInstruction(super::Instr::Jmp { target: 0, args: &mut args[..] }, "jmp @entry(%3, -7)"); |
|
| 89 | 92 | try checkPrintedInstruction(super::Instr::Br { |
|
| 90 | 93 | op: super::CmpOp::Eq, typ: super::Type::W8, a: value, b: other, |
|
| 91 | - | thenTarget: 0, thenArgs: &mut [], elseTarget: 0, elseArgs: &mut [], |
|
| 92 | - | }, "br.eq w8 %3 -7 @entry @entry"); |
|
| 94 | + | thenTarget: 0, thenArgs: &mut [], elseTarget: 1, elseArgs: &mut [], |
|
| 95 | + | }, "br.eq w8 %3 -7 @entry @exit"); |
|
| 93 | 96 | try checkPrintedInstruction(super::Instr::Br { |
|
| 94 | 97 | op: super::CmpOp::Ne, typ: super::Type::W16, a: value, b: other, |
|
| 95 | - | thenTarget: 0, thenArgs: &mut args[..], elseTarget: 0, elseArgs: &mut [], |
|
| 96 | - | }, "br.ne w16 %3 -7 @entry(%3, -7) @entry"); |
|
| 98 | + | thenTarget: 1, thenArgs: &mut args[..], elseTarget: 0, elseArgs: &mut [], |
|
| 99 | + | }, "br.ne w16 %3 -7 @exit(%3, -7) @entry"); |
|
| 97 | 100 | try checkPrintedInstruction(super::Instr::Br { |
|
| 98 | 101 | op: super::CmpOp::Slt, typ: super::Type::W32, a: value, b: other, |
|
| 99 | - | thenTarget: 0, thenArgs: &mut [], elseTarget: 0, elseArgs: &mut args[..], |
|
| 100 | - | }, "br.slt w32 %3 -7 @entry @entry(%3, -7)"); |
|
| 102 | + | thenTarget: 0, thenArgs: &mut [], elseTarget: 1, elseArgs: &mut args[..], |
|
| 103 | + | }, "br.slt w32 %3 -7 @entry @exit(%3, -7)"); |
|
| 101 | 104 | try checkPrintedInstruction(super::Instr::Br { |
|
| 102 | 105 | op: super::CmpOp::Ult, typ: super::Type::W64, a: value, b: other, |
|
| 103 | 106 | thenTarget: 0, thenArgs: &mut args[..], elseTarget: 0, elseArgs: &mut args[..], |
|
| 104 | 107 | }, "br.ult w64 %3 -7 @entry(%3, -7) @entry(%3, -7)"); |
|
| 105 | 108 | let mut cases = [ |