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)
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)
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
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, )
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, )
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
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, )
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, )
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)
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)
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)
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)
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)
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)
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)
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
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, )
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
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
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
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, )
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, )