compiler: Check operand cursor and argument-group transitions
7738e581e2c04f488df78e758a82876ae09bbb29eeccddfa52f06c2f85b775ef
1 parent
91d5c00e
lib/std/lang/il.rad
+52 -23
| 549 | 549 | } |
|
| 550 | 550 | ||
| 551 | 551 | /// Return the next source register, including repeated uses. |
|
| 552 | 552 | /// Supply the unchanged instruction for every step of a scan. |
|
| 553 | 553 | export unsafe fn nextReg(cursor: &mut RegCursor, instr: &Instr) -> ?Reg { |
|
| 554 | + | return advanceReg(cursor, instr); |
|
| 555 | + | } |
|
| 556 | + | ||
| 557 | + | /// Advance fixed operands and argument groups in source-register order. |
|
| 558 | + | fn advanceReg(cursor: &mut RegCursor, instr: &Instr) -> ?Reg { |
|
| 554 | 559 | if cursor.next < cursor.count { |
|
| 555 | 560 | let reg = cursor.fixed[cursor.next]; |
|
| 556 | 561 | set cursor.next += 1; |
|
| 557 | 562 | return reg; |
|
| 558 | 563 | } |
|
| 559 | 564 | if not cursor.arguments { |
|
| 560 | 565 | return nil; |
|
| 561 | 566 | } |
|
| 562 | - | match *instr { |
|
| 567 | + | match instr { |
|
| 563 | 568 | case Instr::Call { args, .. } => { |
|
| 564 | - | if let reg = nextArgument(cursor, args) { |
|
| 565 | - | return reg; |
|
| 569 | + | unsafe { |
|
| 570 | + | if let reg = nextArgument(cursor, *args) { |
|
| 571 | + | return reg; |
|
| 572 | + | } |
|
| 566 | 573 | } |
|
| 567 | 574 | } |
|
| 568 | 575 | case Instr::Jmp { args, .. } => { |
|
| 569 | - | if let reg = nextArgument(cursor, args) { |
|
| 570 | - | return reg; |
|
| 576 | + | unsafe { |
|
| 577 | + | if let reg = nextArgument(cursor, *args) { |
|
| 578 | + | return reg; |
|
| 579 | + | } |
|
| 571 | 580 | } |
|
| 572 | 581 | } |
|
| 573 | 582 | case Instr::Br { thenArgs, elseArgs, .. } => { |
|
| 574 | - | if cursor.branch == 0 { |
|
| 575 | - | if let reg = nextArgument(cursor, thenArgs) { |
|
| 583 | + | unsafe { |
|
| 584 | + | if let reg = nextBranchArgument(cursor, *thenArgs, *elseArgs) { |
|
| 576 | 585 | return reg; |
|
| 577 | 586 | } |
|
| 578 | - | set cursor.branch = 1; |
|
| 579 | - | set cursor.argument = 0; |
|
| 580 | - | } |
|
| 581 | - | if let reg = nextArgument(cursor, elseArgs) { |
|
| 582 | - | return reg; |
|
| 583 | 587 | } |
|
| 584 | 588 | } |
|
| 585 | 589 | case Instr::Switch { defaultArgs, cases, .. } => { |
|
| 586 | - | if cursor.branch == 0 { |
|
| 587 | - | if let reg = nextArgument(cursor, defaultArgs) { |
|
| 588 | - | return reg; |
|
| 589 | - | } |
|
| 590 | - | set cursor.branch = 1; |
|
| 591 | - | set cursor.argument = 0; |
|
| 592 | - | } |
|
| 593 | - | while cursor.branch - 1 < cases.len { |
|
| 594 | - | if let reg = nextArgument(cursor, cases[cursor.branch - 1].args) { |
|
| 590 | + | unsafe { |
|
| 591 | + | if let reg = nextSwitchArgument(cursor, *defaultArgs, *cases) { |
|
| 595 | 592 | return reg; |
|
| 596 | 593 | } |
|
| 597 | - | set cursor.branch += 1; |
|
| 598 | - | set cursor.argument = 0; |
|
| 599 | 594 | } |
|
| 600 | 595 | } |
|
| 601 | 596 | else => panic "nextReg: expected instruction argument groups", |
|
| 602 | 597 | } |
|
| 603 | 598 | set cursor.arguments = false; |
|
| 604 | 599 | return nil; |
|
| 605 | 600 | } |
|
| 606 | 601 | ||
| 602 | + | /// Scan the then arguments before the else arguments. |
|
| 603 | + | fn nextBranchArgument(cursor: &mut RegCursor, thenArgs: &[Val], elseArgs: &[Val]) -> ?Reg { |
|
| 604 | + | if cursor.branch == 0 { |
|
| 605 | + | if let reg = nextArgument(cursor, thenArgs) { |
|
| 606 | + | return reg; |
|
| 607 | + | } |
|
| 608 | + | set cursor.branch = 1; |
|
| 609 | + | set cursor.argument = 0; |
|
| 610 | + | } |
|
| 611 | + | return nextArgument(cursor, elseArgs); |
|
| 612 | + | } |
|
| 613 | + | ||
| 614 | + | /// Scan default arguments and then each case's arguments in table order. |
|
| 615 | + | fn nextSwitchArgument(cursor: &mut RegCursor, defaultArgs: &[Val], cases: &[SwitchCase]) -> ?Reg { |
|
| 616 | + | if cursor.branch == 0 { |
|
| 617 | + | if let reg = nextArgument(cursor, defaultArgs) { |
|
| 618 | + | return reg; |
|
| 619 | + | } |
|
| 620 | + | set cursor.branch = 1; |
|
| 621 | + | set cursor.argument = 0; |
|
| 622 | + | } |
|
| 623 | + | while cursor.branch - 1 < cases.len { |
|
| 624 | + | let entry = &cases[cursor.branch - 1]; |
|
| 625 | + | unsafe { |
|
| 626 | + | if let reg = nextArgument(cursor, entry.args) { |
|
| 627 | + | return reg; |
|
| 628 | + | } |
|
| 629 | + | } |
|
| 630 | + | set cursor.branch += 1; |
|
| 631 | + | set cursor.argument = 0; |
|
| 632 | + | } |
|
| 633 | + | return nil; |
|
| 634 | + | } |
|
| 635 | + | ||
| 607 | 636 | /// Scan an argument group from the cursor's current position. |
|
| 608 | 637 | fn nextArgument(cursor: &mut RegCursor, args: &[Val]) -> ?Reg { |
|
| 609 | 638 | while cursor.argument < args.len { |
|
| 610 | 639 | let value = args[cursor.argument]; |
|
| 611 | 640 | set cursor.argument += 1; |
lib/std/lang/il/tests.rad
+5 -0
| 228 | 228 | try check(super::Instr::Ret { val: nil }, &[]); |
|
| 229 | 229 | try check(super::Instr::Jmp { target: 0, args: &mut args[..] }, &[1, 2, 1]); |
|
| 230 | 230 | let mut other = [b, imm]; |
|
| 231 | 231 | try check(super::Instr::Br { op: super::CmpOp::Eq, typ: super::Type::W64, a, b, |
|
| 232 | 232 | thenTarget: 0, thenArgs: &mut args[..], elseTarget: 1, elseArgs: &mut other[..] }, &[1, 2, 1, 2, 1, 2]); |
|
| 233 | + | try check(super::Instr::Br { op: super::CmpOp::Eq, typ: super::Type::W64, a: imm, b: imm, |
|
| 234 | + | thenTarget: 0, thenArgs: &mut [], elseTarget: 1, elseArgs: &mut other[..] }, &[2]); |
|
| 235 | + | try check(super::Instr::Br { op: super::CmpOp::Eq, typ: super::Type::W64, a, b, |
|
| 236 | + | thenTarget: 0, thenArgs: &mut other[..], elseTarget: 1, elseArgs: &mut [] }, &[1, 2, 2]); |
|
| 233 | 237 | let mut cases = [ |
|
| 234 | 238 | super::SwitchCase { value: 0, target: 0, args: &mut [] }, |
|
| 235 | 239 | super::SwitchCase { value: 1, target: 1, args: &mut args[..] }, |
|
| 236 | 240 | super::SwitchCase { value: 2, target: 2, args: &mut [] }, |
|
| 237 | 241 | super::SwitchCase { value: 3, target: 3, args: &mut other[..] }, |
|
| 238 | 242 | ]; |
|
| 239 | 243 | try check(super::Instr::Switch { val: b, defaultTarget: 0, defaultArgs: &mut [], cases: &mut cases[..] }, &[2, 1, 2, 1, 2]); |
|
| 244 | + | try check(super::Instr::Switch { val: a, defaultTarget: 0, defaultArgs: &mut other[..], cases: &mut cases[..] }, &[1, 2, 1, 2, 1, 2]); |
|
| 240 | 245 | try check(super::Instr::Switch { val: imm, defaultTarget: 0, defaultArgs: &mut args[..], cases: &mut [] }, &[1, 2, 1]); |
|
| 241 | 246 | try check(super::Instr::Switch { val: imm, defaultTarget: 0, defaultArgs: &mut [], cases: &mut [] }, &[]); |
|
| 242 | 247 | try check(super::Instr::Ecall { dst, num: a, a0: imm, a1: b, a2: a, a3: imm }, &[1, 2, 1]); |
|
| 243 | 248 | try check(super::Instr::Ecall { dst, num: a, a0: b, a1: a, a2: b, a3: a }, &[1, 2, 1, 2, 1]); |
|
| 244 | 249 | try check(super::Instr::Unreachable, &[]); |