compiler: Check operand cursor and argument-group transitions

7738e581e2c04f488df78e758a82876ae09bbb29eeccddfa52f06c2f85b775ef
Alexis Sellier committed ago 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, &[]);