Skip to content

interpreter: lower && and || as short-circuit branches#73

Open
Franklin-Qi wants to merge 1 commit into
uutils:mainfrom
Franklin-Qi:feature-task#69-Interpreter-lower-and-or-as-short-circuit
Open

interpreter: lower && and || as short-circuit branches#73
Franklin-Qi wants to merge 1 commit into
uutils:mainfrom
Franklin-Qi:feature-task#69-Interpreter-lower-and-or-as-short-circuit

Conversation

@Franklin-Qi

Copy link
Copy Markdown
Contributor

Lower logical AND/OR at codegen time using Branch and Jump instead of dedicated And/Or VM instructions. Results are coerced to integer truth values (0 or 1), matching gawk mkbool() behavior.

Closes #69

Lower logical AND/OR at codegen time using Branch and Jump instead of
dedicated And/Or VM instructions. Results are coerced to integer truth
values (0 or 1), matching gawk mkbool() behavior.

Closes uutils#69

@Alonely0 Alonely0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite nice. The only thing I'd say is that the two helpers are unnecessarily complex (see the other review comment).

Comment on lines +438 to +459
fn lower_and_into(&mut self, lhs: &Expr<'_>, rhs: &Expr<'_>, dest: Reg) {
let lhs_reg = self.alloc_reg();
self.lower_expr_into(lhs, *lhs_reg);
let br = self.bc.emit(Instruction::br(*lhs_reg, Label(0)));
let false_label = self.following_instr(0);
self.bc.nth(br).set_label(false_label);
self.free_reg(lhs_reg);

self.bc
.emit(Instruction::Copy { dest, arg: Arg { imm: 0 }, ty: ArgTy::Imm });
let jmp = self.bc.emit(Instruction::Jump { to: Label(0) });

let true_label = self.following_instr(0);
self.bc.nth(br).set_then_label(true_label);
let rhs_reg = self.alloc_reg();
self.lower_expr_into(rhs, *rhs_reg);
self.truthify(*rhs_reg, dest);
self.free_reg(rhs_reg);

let end = self.following_instr(0);
self.bc.nth(jmp).set_label(end);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure we can use the helpers like emit_branch, emit_jump to make this shorter and more robust, right?

Something like:

    fn lower_and_into(&mut self, lhs: &Expr<'_>, rhs: &Expr<'_>, dest: Reg) {
        let (if_label, _) = self.emit_branch(lhs, |this| {
            let rhs_reg = this.alloc_reg();
            this.lower_expr_into(rhs, *rhs_reg);
            this.truthify(*rhs_reg, dest);
            this.free_reg(rhs_reg);
        });
        self.bc.nth(if_label).push_end_label();
        self.emit_jump(|this| {
            this.bc
                .emit(Instruction::Copy { dest, arg: Arg { imm: 0 }, ty: ArgTy::Imm });
        });
    }

self.bc.nth(jmp).set_label(end);
}

fn lower_or_into(&mut self, lhs: &Expr<'_>, rhs: &Expr<'_>, dest: Reg) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment on lines +487 to +490
self.bc
.emit(Instruction::Negation { dest: *tmp, arg: Arg { reg: src }, ty: ArgTy::Reg });
self.bc
.emit(Instruction::Negation { dest, arg: Arg { reg: *tmp }, ty: ArgTy::Reg });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a former pythonist, this amuses me to no end. IYKYK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interpreter: lower &&, || as short-circuiting

2 participants