fn emit_binop<F: FnOnce(&mut Assembler, &ValueStack, Register, Register)>(
        assembler: &mut Assembler,
        value_stack: &mut ValueStack,
        f: F,
        in_ty: WpType,
        out_ty: WpType,
    ) -> Result<(), CodegenError> {
        let (a, b) = value_stack.pop2()?;
        if a.ty != in_ty || b.ty != in_ty {
            return Err(CodegenError {
                message: "binop(i32) type mismatch",
            });
        }
        value_stack.push(out_ty);

        if a.location.is_register() && b.location.is_register() {
            // output is in a_reg.
            f(
                assembler,
                value_stack,
                Register::from_scratch_reg(a.location.get_register()?),
                Register::from_scratch_reg(b.location.get_register()?),
            );
        } else if a.location.is_register() {
            dynasm!(
                assembler
                ; pop rax
            );
            f(
                assembler,
                value_stack,
                Register::from_scratch_reg(a.location.get_register()?),
                Register::RAX,
            );
        } else if b.location.is_register() {
            unreachable!();
        } else {
            dynasm!(
                assembler
                ; push rcx
                ; mov rcx, [rsp + 16]
                ; mov rax, [rsp + 8]
            );
            f(assembler, value_stack, Register::RCX, Register::RAX);
            dynasm!(
                assembler
                ; mov [rsp + 16], rcx
                ; pop rcx
                ; add rsp, 8
            );
        }

        Ok(())
    }
/// Emits a binary operator.
///
/// Guarantees that the first Register parameter to callback `f` will never be `Register::RAX`.
Emits a binary operator.
Guarantees that the first Register parameter to callback `f` will never be `Register::RAX`.
Emits a binary operator . Guarantees that the first Register parameter to callback ` f ` will never be ` Register :: RAX ` .
fn emit_binop<F: FnOnce(&mut Assembler, &ValueStack, Register, Register)>(
        assembler: &mut Assembler,
        value_stack: &mut ValueStack,
        f: F,
        in_ty: WpType,
        out_ty: WpType,
    ) -> Result<(), CodegenError> {
        let (a, b) = value_stack.pop2()?;
        if a.ty != in_ty || b.ty != in_ty {
            return Err(CodegenError {
                message: "binop(i32) type mismatch",
            });
        }
        value_stack.push(out_ty);
        if a.location.is_register() && b.location.is_register() {
            // output is in a_reg.
            f(
                assembler,
                value_stack,
                Register::from_scratch_reg(a.location.get_register()?),
                Register::from_scratch_reg(b.location.get_register()?),
            );
        } else if a.location.is_register() {
            dynasm!(
                assembler
                ; pop rax
            );
            f(
                assembler,
                value_stack,
                Register::from_scratch_reg(a.location.get_register()?),
                Register::RAX,
            );
        } else if b.location.is_register() {
            unreachable!();
        } else {
            dynasm!(
                assembler
                ; push rcx
                ; mov rcx, [rsp + 16]
                ; mov rax, [rsp + 8]
            );
            f(assembler, value_stack, Register::RCX, Register::RAX);
            dynasm!(
                assembler
                ; mov [rsp + 16], rcx
                ; pop rcx
                ; add rsp, 8
            );
        }
        Ok(())
    }
fn emit_binop < F : FnOnce ( & mut Assembler , & ValueStack , Register , Register ) > ( assembler : & mut Assembler , value_stack : & mut ValueStack , f : F , in_ty : WpType , out_ty : WpType , ) -> Result < ( ) , CodegenError > { let ( a , b ) = value_stack . pop2 ( ) ? ; if a . ty != in_ty || b . ty != in_ty { return Err ( CodegenError { message : " " , } ) ; } value_stack . push ( out_ty ) ; if a . location . is_register ( ) && b . location . is_register ( ) { // output is in a_reg. f ( assembler , value_stack , Register :: from_scratch_reg ( a . location . get_register ( ) ? ) , Register :: from_scratch_reg ( b . location . get_register ( ) ? ) , ) ; } else if a . location . is_register ( ) { dynasm ! ( assembler pop rax ) ; f ( assembler , value_stack , Register :: from_scratch_reg ( a . location . get_register ( ) ? ) , Register :: RAX , ) ; } else if b . location . is_register ( ) { unreachable ! ( ) ; } else { dynasm ! ( assembler push rcx mov rcx [ rsp 16 ] mov rax [ rsp 8 ] ) ; f ( assembler , value_stack , Register :: RCX , Register :: RAX ) ; dynasm ! ( assembler mov [ rsp 16 ] rcx pop rcx add rsp 8 ) ; } Ok ( ( ) ) }
Emits a binary operator.
Emits a binary operator .
assembler
&mut Assembler
value_stack
&mut ValueStack
f
F
in_ty
WpType
out_ty
WpType
assembler
&mut Assembler
value_stack
&mut ValueStack
f
F
in_ty
WpType
out_ty
WpType