Пример #1
0
def test_assert_eq_double_dereference():
    assert parse_and_build('[ap + 2] = [[fp]]') == \
        Instruction(
            off0=2,
            off1=0,
            off2=0,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.OP0,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
    assert parse_and_build('[ap + 2] = [[ap - 4] + 7]; ap++') == \
        Instruction(
            off0=2,
            off1=-4,
            off2=7,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.OP0,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.ADD1,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
Пример #2
0
def test_call_instruction():
    assert parse_and_build('call abs [fp + 4]') == \
        Instruction(
            off0=0,
            off1=1,
            off2=4,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP,
            ap_update=Instruction.ApUpdate.ADD2,
            fp_update=Instruction.FpUpdate.AP_PLUS2,
            opcode=Instruction.Opcode.CALL)

    assert parse_and_build('call rel [fp + 4]') == \
        Instruction(
            off0=0,
            off1=1,
            off2=4,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP_REL,
            ap_update=Instruction.ApUpdate.ADD2,
            fp_update=Instruction.FpUpdate.AP_PLUS2,
            opcode=Instruction.Opcode.CALL)
    assert parse_and_build('call rel [ap + 4]') == \
        Instruction(
            off0=0,
            off1=1,
            off2=4,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP_REL,
            ap_update=Instruction.ApUpdate.ADD2,
            fp_update=Instruction.FpUpdate.AP_PLUS2,
            opcode=Instruction.Opcode.CALL)
    assert parse_and_build('call rel 123') == \
        Instruction(
            off0=0,
            off1=1,
            off2=1,
            imm=123,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP_REL,
            ap_update=Instruction.ApUpdate.ADD2,
            fp_update=Instruction.FpUpdate.AP_PLUS2,
            opcode=Instruction.Opcode.CALL)
Пример #3
0
def test_assert_eq():
    encoded = [0x480680017fff8000, 1]
    instruction = Instruction(
        off0=0,
        off1=-1,
        off2=1,
        imm=1,
        dst_register=Register.AP,
        op0_register=Register.FP,
        op1_addr=Instruction.Op1Addr.IMM,
        res=Instruction.Res.OP1,
        pc_update=Instruction.PcUpdate.REGULAR,
        ap_update=Instruction.ApUpdate.ADD1,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.ASSERT_EQ,
    )
    assert build_instruction(
        parse_instruction('[ap] = 1; ap++')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction

    # Remove "ap++".
    instruction = dataclasses.replace(instruction,
                                      ap_update=Instruction.ApUpdate.REGULAR)
    encoded = [0x400680017fff8000, 1]
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(*encoded) is False
Пример #4
0
def _build_addap_instruction(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is an
    AddApInstruction.
    """
    instruction_body: AddApInstruction = cast(AddApInstruction, instruction_ast.body)

    res_desc = _parse_res(instruction_body.expr)

    if instruction_ast.inc_ap:
        raise InstructionBuilderError(
            'ap++ may not be used with the addap opcode.', location=instruction_ast.location)

    return Instruction(
        # In this case dst is not involved. Choose [fp - 1] as the default.
        off0=-1,
        off1=res_desc.off1,
        off2=res_desc.off2,
        imm=res_desc.imm,
        dst_register=Register.FP,
        op0_register=res_desc.op0_register,
        op1_addr=res_desc.op1_addr,
        res=res_desc.res,
        pc_update=Instruction.PcUpdate.REGULAR,
        ap_update=Instruction.ApUpdate.ADD,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.NOP,
    )
Пример #5
0
def _build_assert_eq_instruction_inner(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is of type AssertEq.
    """
    instruction_body: AssertEqInstruction = cast(AssertEqInstruction, instruction_ast.body)

    instruction_body = _apply_inverse_syntactic_sugar(instruction_body)

    dst_expr = _parse_dereference(instruction_body.a)
    dst_register, off0 = _parse_register_offset(dst_expr)

    res_desc = _parse_res(instruction_body.b)

    ap_update = Instruction.ApUpdate.ADD1 if instruction_ast.inc_ap else \
        Instruction.ApUpdate.REGULAR

    return Instruction(
        off0=off0,
        off1=res_desc.off1,
        off2=res_desc.off2,
        imm=res_desc.imm,
        dst_register=dst_register,
        op0_register=res_desc.op0_register,
        op1_addr=res_desc.op1_addr,
        res=res_desc.res,
        pc_update=Instruction.PcUpdate.REGULAR,
        ap_update=ap_update,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.ASSERT_EQ,
    )
Пример #6
0
def test_jmp():
    encoded = [0x0129800080027fff]
    instruction = Instruction(
        off0=-1,
        off1=2,
        off2=0,
        imm=None,
        dst_register=Register.FP,
        op0_register=Register.AP,
        op1_addr=Instruction.Op1Addr.FP,
        res=Instruction.Res.ADD,
        pc_update=Instruction.PcUpdate.JUMP_REL,
        ap_update=Instruction.ApUpdate.REGULAR,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.NOP,
    )
    assert build_instruction(
        parse_instruction('jmp rel [ap + 2] + [fp]')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction

    # Change to jmp abs.
    instruction = dataclasses.replace(instruction,
                                      pc_update=Instruction.PcUpdate.JUMP)
    encoded = [0x00a9800080027fff]
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(encoded[0], None) is False
Пример #7
0
def _build_jump_instruction(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is a JumpInstruction.
    """
    instruction_body: JumpInstruction = cast(JumpInstruction, instruction_ast.body)

    res_desc = _parse_res(instruction_body.val)

    ap_update = Instruction.ApUpdate.ADD1 if instruction_ast.inc_ap else \
        Instruction.ApUpdate.REGULAR
    pc_update = Instruction.PcUpdate.JUMP_REL if instruction_body.relative else \
        Instruction.PcUpdate.JUMP

    return Instruction(
        # In this case dst is not involved. Choose [fp - 1] as the default.
        off0=-1,
        off1=res_desc.off1,
        off2=res_desc.off2,
        imm=res_desc.imm,
        dst_register=Register.FP,
        op0_register=res_desc.op0_register,
        op1_addr=res_desc.op1_addr,
        res=res_desc.res,
        pc_update=pc_update,
        ap_update=ap_update,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.NOP,
    )
Пример #8
0
def _build_ret_instruction(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is a RetInstruction.
    """

    if instruction_ast.inc_ap:
        raise InstructionBuilderError(
            'ap++ may not be used with the ret opcode.', location=instruction_ast.location)

    return Instruction(
        # Use dst for fp <- [fp - 2].
        off0=-2,
        # In this case op0 is not involved. Choose[fp - 1] as the default.
        off1=-1,
        # Use op1 for pc <- [fp - 1].
        off2=-1,
        imm=None,
        dst_register=Register.FP,
        op0_register=Register.FP,
        op1_addr=Instruction.Op1Addr.FP,
        res=Instruction.Res.OP1,
        pc_update=Instruction.PcUpdate.JUMP,
        ap_update=Instruction.ApUpdate.REGULAR,
        fp_update=Instruction.FpUpdate.DST,
        opcode=Instruction.Opcode.RET,
    )
Пример #9
0
def test_addap_instruction():
    assert parse_and_build('ap += [fp + 4] + [fp]') == \
        Instruction(
            off0=-1,
            off1=4,
            off2=0,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.ADD,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.ADD,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('ap += [ap + 4] + [ap]') == \
        Instruction(
            off0=-1,
            off1=4,
            off2=0,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.ADD,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.ADD,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('ap += 123') == \
        Instruction(
            off0=-1,
            off1=-1,
            off2=1,
            imm=123,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.ADD,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
Пример #10
0
def test_assert_eq():
    assert parse_and_build('[ap] = [fp]; ap++') == \
        Instruction(
            off0=0,
            off1=-1,
            off2=0,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.ADD1,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
    assert parse_and_build('[fp - 3] = [fp + 7]') == \
        Instruction(
            off0=-3,
            off1=-1,
            off2=7,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
    assert parse_and_build('[ap - 3] = [ap]') == \
        Instruction(
            off0=-3,
            off1=-1,
            off2=0,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
Пример #11
0
def test_jnz_instruction():
    assert parse_and_build('jmp rel [fp - 1] if [fp - 7] != 0') == \
        Instruction(
            off0=-7,
            off1=-1,
            off2=-1,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.UNCONSTRAINED,
            pc_update=Instruction.PcUpdate.JNZ,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('jmp rel [ap - 1] if [fp - 7] != 0') == \
        Instruction(
            off0=-7,
            off1=-1,
            off2=-1,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.UNCONSTRAINED,
            pc_update=Instruction.PcUpdate.JNZ,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('jmp rel 123 if [ap] != 0; ap++') == \
        Instruction(
            off0=0,
            off1=-1,
            off2=1,
            imm=123,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.UNCONSTRAINED,
            pc_update=Instruction.PcUpdate.JNZ,
            ap_update=Instruction.ApUpdate.ADD1,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
Пример #12
0
def test_jump_instruction():
    assert parse_and_build('jmp rel [ap + 1] + [fp - 7]') == \
        Instruction(
            off0=-1,
            off1=1,
            off2=-7,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.ADD,
            pc_update=Instruction.PcUpdate.JUMP_REL,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('jmp abs 123; ap++') == \
        Instruction(
            off0=-1,
            off1=-1,
            off2=1,
            imm=123,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP,
            ap_update=Instruction.ApUpdate.ADD1,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
    assert parse_and_build('jmp rel [ap + 1] + [ap - 7]') == \
        Instruction(
            off0=-1,
            off1=1,
            off2=-7,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.ADD,
            pc_update=Instruction.PcUpdate.JUMP_REL,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.NOP)
Пример #13
0
def test_assert_eq_operation():
    assert parse_and_build('[ap + 1] = [ap - 7] * [fp + 3]') == \
        Instruction(
            off0=1,
            off1=-7,
            off2=3,
            imm=None,
            dst_register=Register.AP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.MUL,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
    assert parse_and_build('[ap + 10] = [fp] + 1234567890') == \
        Instruction(
            off0=10,
            off1=0,
            off2=1,
            imm=1234567890,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.ADD,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
    assert parse_and_build('[fp - 3] = [ap + 7] * [ap + 8]') == \
        Instruction(
            off0=-3,
            off1=7,
            off2=8,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.AP,
            op1_addr=Instruction.Op1Addr.AP,
            res=Instruction.Res.MUL,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
Пример #14
0
def test_assert_eq_imm():
    assert parse_and_build('[ap + 2] = 1234567890') == \
        Instruction(
            off0=2,
            off1=-1,
            off2=1,
            imm=1234567890,
            dst_register=Register.AP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.IMM,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.REGULAR,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.REGULAR,
            opcode=Instruction.Opcode.ASSERT_EQ)
Пример #15
0
def test_ret_instruction():
    assert parse_and_build('ret') == \
        Instruction(
            off0=-2,
            off1=-1,
            off2=-1,
            imm=None,
            dst_register=Register.FP,
            op0_register=Register.FP,
            op1_addr=Instruction.Op1Addr.FP,
            res=Instruction.Res.OP1,
            pc_update=Instruction.PcUpdate.JUMP,
            ap_update=Instruction.ApUpdate.REGULAR,
            fp_update=Instruction.FpUpdate.DST,
            opcode=Instruction.Opcode.RET)
Пример #16
0
def test_addap():
    encoded = [0x40780017fff7fff, 123]
    instruction = Instruction(off0=-1,
                              off1=-1,
                              off2=1,
                              imm=123,
                              dst_register=Register.FP,
                              op0_register=Register.FP,
                              op1_addr=Instruction.Op1Addr.IMM,
                              res=Instruction.Res.OP1,
                              pc_update=Instruction.PcUpdate.REGULAR,
                              ap_update=Instruction.ApUpdate.ADD,
                              fp_update=Instruction.FpUpdate.REGULAR,
                              opcode=Instruction.Opcode.NOP)
    assert build_instruction(parse_instruction('ap += 123')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(*encoded) is False
Пример #17
0
def _build_call_instruction(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is a CallInstruction.
    """
    instruction_body: CallInstruction = cast(CallInstruction, instruction_ast.body)

    val = instruction_body.val
    if isinstance(val, ExprDeref):
        op1_reg, off2 = _parse_register_offset(val.addr)
        imm = None
        op1_addr = Instruction.Op1Addr.FP if op1_reg is Register.FP else Instruction.Op1Addr.AP
    elif isinstance(val, ExprConst):
        off2 = 1
        imm = val.val
        op1_addr = Instruction.Op1Addr.IMM
    else:
        raise InstructionBuilderError(
            'Invalid offset for call.', location=val.location)

    if instruction_ast.inc_ap:
        raise InstructionBuilderError(
            'ap++ may not be used with the call opcode.', location=instruction_ast.location)

    pc_update = Instruction.PcUpdate.JUMP_REL if instruction_body.relative else \
        Instruction.PcUpdate.JUMP

    return Instruction(
        # Use dst for [ap] <- fp.
        off0=0,
        # Use op0 for [ap + 1] <- pc.
        off1=1,
        # Use op1 for jmp offset.
        off2=off2,
        imm=imm,
        dst_register=Register.AP,
        op0_register=Register.AP,
        op1_addr=op1_addr,
        res=Instruction.Res.OP1,
        pc_update=pc_update,
        ap_update=Instruction.ApUpdate.ADD2,
        fp_update=Instruction.FpUpdate.AP_PLUS2,
        opcode=Instruction.Opcode.CALL,
    )
Пример #18
0
def test_ret():
    encoded = [0x208b7fff7fff7ffe]
    instruction = Instruction(
        off0=-2,
        off1=-1,
        off2=-1,
        imm=None,
        dst_register=Register.FP,
        op0_register=Register.FP,
        op1_addr=Instruction.Op1Addr.FP,
        res=Instruction.Res.OP1,
        pc_update=Instruction.PcUpdate.JUMP,
        ap_update=Instruction.ApUpdate.REGULAR,
        fp_update=Instruction.FpUpdate.DST,
        opcode=Instruction.Opcode.RET,
    )
    assert build_instruction(parse_instruction('ret')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(encoded[0], None) is False
Пример #19
0
def test_call():
    encoded = [0x1104800180018000, 1234]
    instruction = Instruction(
        off0=0,
        off1=1,
        off2=1,
        imm=1234,
        dst_register=Register.AP,
        op0_register=Register.AP,
        op1_addr=Instruction.Op1Addr.IMM,
        res=Instruction.Res.OP1,
        pc_update=Instruction.PcUpdate.JUMP_REL,
        ap_update=Instruction.ApUpdate.ADD2,
        fp_update=Instruction.FpUpdate.AP_PLUS2,
        opcode=Instruction.Opcode.CALL,
    )
    assert build_instruction(parse_instruction('call rel 1234')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(*encoded) is True
Пример #20
0
def test_jnz():
    encoded = [0x020a7ff07fff8003]
    instruction = Instruction(
        off0=3,
        off1=-1,
        off2=-16,
        imm=None,
        dst_register=Register.AP,
        op0_register=Register.FP,
        op1_addr=Instruction.Op1Addr.FP,
        res=Instruction.Res.UNCONSTRAINED,
        pc_update=Instruction.PcUpdate.JNZ,
        ap_update=Instruction.ApUpdate.REGULAR,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.NOP,
    )
    assert build_instruction(
        parse_instruction('jmp rel [fp - 16] if [ap + 3] != 0')) == instruction
    assert encode_instruction(instruction, prime=PRIME) == encoded
    assert decode_instruction(*encoded) == instruction
    assert is_call_instruction(encoded[0], None) is False
Пример #21
0
def _build_jnz_instruction(instruction_ast: InstructionAst) -> Instruction:
    """
    Builds an Instruction object from the AST object, assuming the instruction is a JnzInstruction.
    """
    instruction_body: JnzInstruction = cast(JnzInstruction, instruction_ast.body)

    cond_addr = _parse_dereference(instruction_body.condition)
    dst_register, off0 = _parse_register_offset(cond_addr)

    jump_offset = instruction_body.jump_offset
    if isinstance(jump_offset, ExprDeref):
        op1_reg, off2 = _parse_register_offset(jump_offset.addr)
        imm = None
        op1_addr = Instruction.Op1Addr.FP if op1_reg is Register.FP else Instruction.Op1Addr.AP
    elif isinstance(jump_offset, ExprConst):
        off2 = 1
        imm = jump_offset.val
        op1_addr = Instruction.Op1Addr.IMM
    else:
        raise InstructionBuilderError(
            'Invalid expression for jmp offset.', location=jump_offset.location)

    ap_update = Instruction.ApUpdate.ADD1 if instruction_ast.inc_ap else \
        Instruction.ApUpdate.REGULAR

    return Instruction(
        off0=off0,
        # In this case op0 is not involved. Choose[fp - 1] as the default.
        off1=-1,
        off2=off2,
        imm=imm,
        dst_register=dst_register,
        op0_register=Register.FP,
        op1_addr=op1_addr,
        res=Instruction.Res.UNCONSTRAINED,
        pc_update=Instruction.PcUpdate.JNZ,
        ap_update=ap_update,
        fp_update=Instruction.FpUpdate.REGULAR,
        opcode=Instruction.Opcode.NOP,
    )
Пример #22
0
def decode_instruction(encoding: int,
                       imm: Optional[int] = None) -> Instruction:
    """
    Given 1 or 2 integers representing an instruction, returns the Instruction.
    If imm is given for an instruction with no immediate, it will be ignored.
    """
    flags, off0_enc, off1_enc, off2_enc = decode_instruction_values(encoding)

    # Get dst_register.
    dst_register = Register.FP if (flags >> DST_REG_BIT) & 1 else Register.AP

    # Get op0_register.
    op0_register = Register.FP if (flags >> OP0_REG_BIT) & 1 else Register.AP

    # Get op1.
    op1_addr = {
        (1, 0, 0): Instruction.Op1Addr.IMM,
        (0, 1, 0): Instruction.Op1Addr.AP,
        (0, 0, 1): Instruction.Op1Addr.FP,
        (0, 0, 0): Instruction.Op1Addr.OP0
    }[(flags >> OP1_IMM_BIT) & 1, (flags >> OP1_AP_BIT) & 1,
      (flags >> OP1_FP_BIT) & 1]

    if op1_addr is Instruction.Op1Addr.IMM:
        assert imm is not None, 'op1_addr is Op1Addr.IMM, but no immediate given'
    else:
        imm = None

    # Get pc_update.
    pc_update = {
        (1, 0, 0): Instruction.PcUpdate.JUMP,
        (0, 1, 0): Instruction.PcUpdate.JUMP_REL,
        (0, 0, 1): Instruction.PcUpdate.JNZ,
        (0, 0, 0): Instruction.PcUpdate.REGULAR
    }[(flags >> PC_JUMP_ABS_BIT) & 1, (flags >> PC_JUMP_REL_BIT) & 1,
      (flags >> PC_JNZ_BIT) & 1]

    # Get res.
    res = {
        (1, 0):
        Instruction.Res.ADD,
        (0, 1):
        Instruction.Res.MUL,
        (0, 0):
        Instruction.Res.UNCONSTRAINED
        if pc_update is Instruction.PcUpdate.JNZ else Instruction.Res.OP1,
    }[(flags >> RES_ADD_BIT) & 1, (flags >> RES_MUL_BIT) & 1]

    # JNZ opcode means res must be UNCONSTRAINED.
    if pc_update is Instruction.PcUpdate.JNZ:
        assert res is Instruction.Res.UNCONSTRAINED

    # Get ap_update.
    ap_update = {
        (1, 0): Instruction.ApUpdate.ADD,
        (0, 1): Instruction.ApUpdate.ADD1,
        (0, 0): Instruction.ApUpdate.
        REGULAR,  # OR ADD2, depending if we have CALL opcode.
    }[(flags >> AP_ADD_BIT) & 1, (flags >> AP_ADD1_BIT) & 1]

    # Get opcode.
    opcode = {
        (1, 0, 0): Instruction.Opcode.CALL,
        (0, 1, 0): Instruction.Opcode.RET,
        (0, 0, 1): Instruction.Opcode.ASSERT_EQ,
        (0, 0, 0): Instruction.Opcode.NOP
    }[(flags >> OPCODE_CALL_BIT) & 1, (flags >> OPCODE_RET_BIT) & 1,
      (flags >> OPCODE_ASSERT_EQ_BIT) & 1]

    # CALL opcode means ap_update must be ADD2.
    if opcode is Instruction.Opcode.CALL:
        assert ap_update is Instruction.ApUpdate.REGULAR, 'CALL must have update_ap is ADD2'
        ap_update = Instruction.ApUpdate.ADD2

    # Get fp_update.
    if opcode is Instruction.Opcode.CALL:
        fp_update = Instruction.FpUpdate.AP_PLUS2
    elif opcode is Instruction.Opcode.RET:
        fp_update = Instruction.FpUpdate.DST
    else:
        fp_update = Instruction.FpUpdate.REGULAR

    return Instruction(
        off0=off0_enc - 2**(OFFSET_BITS - 1),
        off1=off1_enc - 2**(OFFSET_BITS - 1),
        off2=off2_enc - 2**(OFFSET_BITS - 1),
        imm=imm,
        dst_register=dst_register,
        op0_register=op0_register,
        op1_addr=op1_addr,
        res=res,
        pc_update=pc_update,
        ap_update=ap_update,
        fp_update=fp_update,
        opcode=opcode,
    )