From 5f386963b06752087c2600949cbb4bb2910b25ef Mon Sep 17 00:00:00 2001 From: Facundo Date: Wed, 30 Oct 2024 17:06:17 +0000 Subject: [PATCH] feat(avm)!: use 32 bit locations (#9596) Contrary to what was expected months ago, we have to support contracts > 65 kB. So we need 32 bit locations in the upcoming move to byte-indexed PCs. This increseases bytecode ~8% in the short term. In the longer term, we might introduce relative jumps with 8 and 16 bit variants. That would likely leave us in an even better place than where we are today. Part of #9059. --- avm-transpiler/src/opcodes.rs | 8 +++---- avm-transpiler/src/transpile.rs | 10 ++++----- .../vm/avm/tests/execution.test.cpp | 22 +++++++++---------- .../vm/avm/trace/deserialization.cpp | 6 ++--- .../barretenberg/vm/avm/trace/execution.cpp | 10 ++++----- .../barretenberg/vm/avm/trace/fixed_gas.cpp | 4 ++-- .../src/barretenberg/vm/avm/trace/opcode.cpp | 8 +++---- .../src/barretenberg/vm/avm/trace/opcode.hpp | 4 ++-- .../src/barretenberg/vm/avm/trace/trace.cpp | 4 ++-- yarn-project/simulator/src/avm/avm_gas.ts | 4 ++-- .../src/avm/opcodes/control_flow.test.ts | 12 +++++----- .../simulator/src/avm/opcodes/control_flow.ts | 10 ++++----- .../instruction_serialization.ts | 4 ++-- 13 files changed, 53 insertions(+), 53 deletions(-) diff --git a/avm-transpiler/src/opcodes.rs b/avm-transpiler/src/opcodes.rs index 3584d63b643..a3189c30df5 100644 --- a/avm-transpiler/src/opcodes.rs +++ b/avm-transpiler/src/opcodes.rs @@ -40,8 +40,8 @@ pub enum AvmOpcode { RETURNDATASIZE, RETURNDATACOPY, // Control flow - JUMP_16, - JUMPI_16, + JUMP_32, + JUMPI_32, INTERNALCALL, INTERNALRETURN, // Memory @@ -130,8 +130,8 @@ impl AvmOpcode { // Machine State // Machine State - Internal Control Flow - AvmOpcode::JUMP_16 => "JUMP_16", - AvmOpcode::JUMPI_16 => "JUMPI_16", + AvmOpcode::JUMP_32 => "JUMP_32", + AvmOpcode::JUMPI_32 => "JUMPI_32", AvmOpcode::INTERNALCALL => "INTERNALCALL", AvmOpcode::INTERNALRETURN => "INTERNALRETURN", // Machine State - Memory diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 799d0017b6c..d1442196a80 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -233,20 +233,20 @@ pub fn brillig_to_avm( BrilligOpcode::Jump { location } => { let avm_loc = brillig_pcs_to_avm_pcs[*location]; avm_instrs.push(AvmInstruction { - opcode: AvmOpcode::JUMP_16, - operands: vec![make_operand(16, &avm_loc)], + opcode: AvmOpcode::JUMP_32, + operands: vec![make_operand(32, &avm_loc)], ..Default::default() }); } BrilligOpcode::JumpIf { condition, location } => { let avm_loc = brillig_pcs_to_avm_pcs[*location]; avm_instrs.push(AvmInstruction { - opcode: AvmOpcode::JUMPI_16, + opcode: AvmOpcode::JUMPI_32, indirect: Some( AddressingModeBuilder::default().direct_operand(condition).build(), ), operands: vec![ - make_operand(16, &avm_loc), + make_operand(32, &avm_loc), make_operand(16, &condition.to_usize()), ], ..Default::default() @@ -298,7 +298,7 @@ pub fn brillig_to_avm( let avm_loc = brillig_pcs_to_avm_pcs[*location]; avm_instrs.push(AvmInstruction { opcode: AvmOpcode::INTERNALCALL, - operands: vec![AvmOperand::U16 { value: avm_loc as u16 }], + operands: vec![AvmOperand::U32 { value: avm_loc as u32 }], ..Default::default() }); } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp index 1f00b899d9a..4640e94585d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp @@ -323,7 +323,7 @@ TEST_F(AvmExecutionTests, simpleInternalCall) "0D3D2518" // val 222111000 = 0xD3D2518 "0004" // dst_offset 4 + to_hex(OpCode::INTERNALCALL) + // opcode INTERNALCALL - "0004" // jmp_dest + "00000004" // jmp_dest + to_hex(OpCode::ADD_16) + // opcode ADD "00" // Indirect flag "0004" // addr a 4 @@ -351,7 +351,7 @@ TEST_F(AvmExecutionTests, simpleInternalCall) // INTERNALCALL EXPECT_THAT(instructions.at(1), AllOf(Field(&Instruction::op_code, OpCode::INTERNALCALL), - Field(&Instruction::operands, ElementsAre(VariantWith(4))))); + Field(&Instruction::operands, ElementsAre(VariantWith(4))))); // INTERNALRETURN EXPECT_EQ(instructions.at(5).op_code, OpCode::INTERNALRETURN); @@ -388,7 +388,7 @@ TEST_F(AvmExecutionTests, nestedInternalCalls) { auto internalCallInstructionHex = [](std::string const& dst_offset) { return to_hex(OpCode::INTERNALCALL) // opcode INTERNALCALL - + "00" + dst_offset; + + "000000" + dst_offset; }; auto setInstructionHex = [](std::string const& val, std::string const& dst_offset) { @@ -471,8 +471,8 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy) "0000" // cd_offset "0001" // copy_size "000A" // dst_offset // M[10] = 13, M[11] = 156 - + to_hex(OpCode::JUMP_16) + // opcode JUMP - "0005" // jmp_dest (FDIV located at 3) + + to_hex(OpCode::JUMP_32) + // opcode JUMP + "00000005" // jmp_dest (FDIV located at 3) + to_hex(OpCode::SUB_8) + // opcode SUB "00" // Indirect flag "0B" // addr 11 @@ -507,8 +507,8 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy) // JUMP EXPECT_THAT(instructions.at(3), - AllOf(Field(&Instruction::op_code, OpCode::JUMP_16), - Field(&Instruction::operands, ElementsAre(VariantWith(5))))); + AllOf(Field(&Instruction::op_code, OpCode::JUMP_32), + Field(&Instruction::operands, ElementsAre(VariantWith(5))))); std::vector returndata; ExecutionHints execution_hints; @@ -566,9 +566,9 @@ TEST_F(AvmExecutionTests, jumpiAndCalldatacopy) + to_hex(AvmMemoryTag::U16) + "14" // val 20 "65" // dst_offset 101 - + to_hex(OpCode::JUMPI_16) + // opcode JUMPI + + to_hex(OpCode::JUMPI_32) + // opcode JUMPI "00" // Indirect flag - "0006" // jmp_dest (MUL located at 6) + "00000006" // jmp_dest (MUL located at 6) "000A" // cond_offset 10 + to_hex(OpCode::ADD_16) + // opcode ADD "00" // Indirect flag @@ -596,9 +596,9 @@ TEST_F(AvmExecutionTests, jumpiAndCalldatacopy) // JUMPI EXPECT_THAT( instructions.at(4), - AllOf(Field(&Instruction::op_code, OpCode::JUMPI_16), + AllOf(Field(&Instruction::op_code, OpCode::JUMPI_32), Field(&Instruction::operands, - ElementsAre(VariantWith(0), VariantWith(6), VariantWith(10))))); + ElementsAre(VariantWith(0), VariantWith(6), VariantWith(10))))); std::vector returndata; ExecutionHints execution_hints; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/deserialization.cpp index 8e203151ded..a105982e1bd 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/deserialization.cpp @@ -90,9 +90,9 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = { OperandType::INDIRECT8, OperandType::UINT16, OperandType::UINT16, OperandType::UINT16 } }, // Machine State - Internal Control Flow - { OpCode::JUMP_16, { OperandType::UINT16 } }, - { OpCode::JUMPI_16, { OperandType::INDIRECT8, OperandType::UINT16, OperandType::UINT16 } }, - { OpCode::INTERNALCALL, { OperandType::UINT16 } }, + { OpCode::JUMP_32, { OperandType::UINT32 } }, + { OpCode::JUMPI_32, { OperandType::INDIRECT8, OperandType::UINT32, OperandType::UINT16 } }, + { OpCode::INTERNALCALL, { OperandType::UINT32 } }, { OpCode::INTERNALRETURN, {} }, // Machine State - Memory diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp index 5ab799bf4ef..cc03e9375fb 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp @@ -508,16 +508,16 @@ std::vector Execution::gen_trace(std::vector const& calldata, break; // Machine State - Internal Control Flow - case OpCode::JUMP_16: - trace_builder.op_jump(std::get(inst.operands.at(0))); + case OpCode::JUMP_32: + trace_builder.op_jump(std::get(inst.operands.at(0))); break; - case OpCode::JUMPI_16: + case OpCode::JUMPI_32: trace_builder.op_jumpi(std::get(inst.operands.at(0)), - std::get(inst.operands.at(1)), + std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); break; case OpCode::INTERNALCALL: - trace_builder.op_internal_call(std::get(inst.operands.at(0))); + trace_builder.op_internal_call(std::get(inst.operands.at(0))); break; case OpCode::INTERNALRETURN: trace_builder.op_internal_return(); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/fixed_gas.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/fixed_gas.cpp index 8fa808e4ad3..bb9eda6172e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/fixed_gas.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/fixed_gas.cpp @@ -52,8 +52,8 @@ const std::unordered_map GAS_COST_TABLE = { { OpCode::CALLDATACOPY, make_cost(AVM_CALLDATACOPY_BASE_L2_GAS, 0, AVM_CALLDATACOPY_DYN_L2_GAS, 0) }, { OpCode::RETURNDATASIZE, make_cost(AVM_RETURNDATASIZE_BASE_L2_GAS, 0, 0, 0) }, { OpCode::RETURNDATACOPY, make_cost(AVM_RETURNDATACOPY_BASE_L2_GAS, 0, AVM_RETURNDATACOPY_DYN_L2_GAS, 0) }, - { OpCode::JUMP_16, make_cost(AVM_JUMP_BASE_L2_GAS, 0, 0, 0) }, - { OpCode::JUMPI_16, make_cost(AVM_JUMPI_BASE_L2_GAS, 0, 0, 0) }, + { OpCode::JUMP_32, make_cost(AVM_JUMP_BASE_L2_GAS, 0, 0, 0) }, + { OpCode::JUMPI_32, make_cost(AVM_JUMPI_BASE_L2_GAS, 0, 0, 0) }, { OpCode::INTERNALCALL, make_cost(AVM_INTERNALCALL_BASE_L2_GAS, 0, 0, 0) }, { OpCode::INTERNALRETURN, make_cost(AVM_INTERNALRETURN_BASE_L2_GAS, 0, 0, 0) }, { OpCode::SET_8, make_cost(AVM_SET_BASE_L2_GAS, 0, 0, 0) }, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.cpp index d247fca4661..b77070e08bf 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.cpp @@ -95,10 +95,10 @@ std::string to_string(OpCode opcode) return "CALLDATACOPY"; // Machine State // Machine State - Internal Control Flow - case OpCode::JUMP_16: - return "JUMP_16"; - case OpCode::JUMPI_16: - return "JUMPI_16"; + case OpCode::JUMP_32: + return "JUMP_32"; + case OpCode::JUMPI_32: + return "JUMPI_32"; case OpCode::INTERNALCALL: return "INTERNALCALL"; case OpCode::INTERNALRETURN: diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp index cc5318be696..d2ad53e4a26 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/opcode.hpp @@ -61,8 +61,8 @@ enum class OpCode : uint8_t { // Machine State // Machine State - Internal Control Flow - JUMP_16, - JUMPI_16, + JUMP_32, + JUMPI_32, INTERNALCALL, INTERNALRETURN, // Machine State - Memory diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp index a0aa672c22e..6eea5900967 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp @@ -1695,7 +1695,7 @@ void AvmTraceBuilder::op_jump(uint32_t jmp_dest, bool skip_gas) // Constrain gas cost if (!skip_gas) { - gas_trace_builder.constrain_gas(clk, OpCode::JUMP_16); + gas_trace_builder.constrain_gas(clk, OpCode::JUMP_32); } main_trace.push_back(Row{ @@ -1739,7 +1739,7 @@ void AvmTraceBuilder::op_jumpi(uint8_t indirect, uint32_t jmp_dest, uint32_t con uint32_t next_pc = !id_zero ? jmp_dest : pc + 1; // Constrain gas cost - gas_trace_builder.constrain_gas(clk, OpCode::JUMPI_16); + gas_trace_builder.constrain_gas(clk, OpCode::JUMPI_32); main_trace.push_back(Row{ .main_clk = clk, diff --git a/yarn-project/simulator/src/avm/avm_gas.ts b/yarn-project/simulator/src/avm/avm_gas.ts index 3e2a31367da..7d571a7c907 100644 --- a/yarn-project/simulator/src/avm/avm_gas.ts +++ b/yarn-project/simulator/src/avm/avm_gas.ts @@ -91,8 +91,8 @@ const BASE_GAS_COSTS: Record = { [Opcode.CALLDATACOPY]: makeCost(c.AVM_CALLDATACOPY_BASE_L2_GAS, 0), [Opcode.RETURNDATASIZE]: makeCost(c.AVM_RETURNDATASIZE_BASE_L2_GAS, 0), [Opcode.RETURNDATACOPY]: makeCost(c.AVM_RETURNDATACOPY_BASE_L2_GAS, 0), - [Opcode.JUMP_16]: makeCost(c.AVM_JUMP_BASE_L2_GAS, 0), - [Opcode.JUMPI_16]: makeCost(c.AVM_JUMPI_BASE_L2_GAS, 0), + [Opcode.JUMP_32]: makeCost(c.AVM_JUMP_BASE_L2_GAS, 0), + [Opcode.JUMPI_32]: makeCost(c.AVM_JUMPI_BASE_L2_GAS, 0), [Opcode.INTERNALCALL]: makeCost(c.AVM_INTERNALCALL_BASE_L2_GAS, 0), [Opcode.INTERNALRETURN]: makeCost(c.AVM_INTERNALRETURN_BASE_L2_GAS, 0), [Opcode.SET_8]: makeCost(c.AVM_SET_BASE_L2_GAS, 0), diff --git a/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts b/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts index 0dac3c087a8..9500c62ff37 100644 --- a/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts @@ -15,9 +15,9 @@ describe('Control Flow Opcodes', () => { it('Should (de)serialize correctly', () => { const buf = Buffer.from([ Jump.opcode, // opcode - ...Buffer.from('1234', 'hex'), // loc + ...Buffer.from('12340000', 'hex'), // loc ]); - const inst = new Jump(/*loc=*/ 0x1234); + const inst = new Jump(/*loc=*/ 0x12340000); expect(Jump.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -39,10 +39,10 @@ describe('Control Flow Opcodes', () => { const buf = Buffer.from([ JumpI.opcode, // opcode 0x01, // indirect - ...Buffer.from('1234', 'hex'), // loc + ...Buffer.from('12340000', 'hex'), // loc ...Buffer.from('a234', 'hex'), // condOffset ]); - const inst = new JumpI(/*indirect=*/ 1, /*loc=*/ 0x1234, /*condOffset=*/ 0xa234); + const inst = new JumpI(/*indirect=*/ 1, /*loc=*/ 0x12340000, /*condOffset=*/ 0xa234); expect(JumpI.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -84,9 +84,9 @@ describe('Control Flow Opcodes', () => { it('INTERNALCALL Should (de)serialize correctly', () => { const buf = Buffer.from([ InternalCall.opcode, // opcode - ...Buffer.from('1234', 'hex'), // loc + ...Buffer.from('12340000', 'hex'), // loc ]); - const inst = new InternalCall(/*loc=*/ 0x1234); + const inst = new InternalCall(/*loc=*/ 0x12340000); expect(InternalCall.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); diff --git a/yarn-project/simulator/src/avm/opcodes/control_flow.ts b/yarn-project/simulator/src/avm/opcodes/control_flow.ts index a83af756468..24ca6762777 100644 --- a/yarn-project/simulator/src/avm/opcodes/control_flow.ts +++ b/yarn-project/simulator/src/avm/opcodes/control_flow.ts @@ -7,9 +7,9 @@ import { Instruction } from './instruction.js'; export class Jump extends Instruction { static type: string = 'JUMP'; - static readonly opcode: Opcode = Opcode.JUMP_16; + static readonly opcode: Opcode = Opcode.JUMP_32; // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT16]; + static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT32]; constructor(private jumpOffset: number) { super(); @@ -26,13 +26,13 @@ export class Jump extends Instruction { export class JumpI extends Instruction { static type: string = 'JUMPI'; - static readonly opcode: Opcode = Opcode.JUMPI_16; + static readonly opcode: Opcode = Opcode.JUMPI_32; // Instruction wire format with opcode. static readonly wireFormat: OperandType[] = [ OperandType.UINT8, OperandType.UINT8, - OperandType.UINT16, + OperandType.UINT32, OperandType.UINT16, ]; @@ -63,7 +63,7 @@ export class InternalCall extends Instruction { static readonly type: string = 'INTERNALCALL'; static readonly opcode: Opcode = Opcode.INTERNALCALL; // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT16]; + static readonly wireFormat: OperandType[] = [OperandType.UINT8, OperandType.UINT32]; constructor(private loc: number) { super(); diff --git a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts index 048d9c481d6..c9ae7a3f2d2 100644 --- a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts @@ -44,8 +44,8 @@ export enum Opcode { RETURNDATASIZE, RETURNDATACOPY, // Control flow - JUMP_16, - JUMPI_16, + JUMP_32, + JUMPI_32, INTERNALCALL, INTERNALRETURN, // Memory