@@ -79,6 +79,13 @@ std::vector<Instruction> Execution::parse(std::vector<uint8_t> const& bytecode)
7979 size_t num_of_operands{};
8080 size_t operands_size{};
8181
82+ // SET opcode particularity about the number of operands depending on the
83+ // instruction tag. Namely, a constant of type instruction tag and not a
84+ // memory address is passed in the operands.
85+ // The bytecode of the operands is of the form CONSTANT || dst_offset
86+ // CONSTANT is of size k bits for type Uk, k=8,16,32,64,128
87+ // dst_offset is of size 32 bits
88+ // CONSTANT has to be decomposed into 32-bit chunks
8289 if (opcode == OpCode::SET) {
8390 switch (in_tag) {
8491 case AvmMemoryTag::U8:
@@ -115,31 +122,28 @@ std::vector<Instruction> Execution::parse(std::vector<uint8_t> const& bytecode)
115122 throw std::runtime_error (" Operand is missing at position " + std::to_string (pos));
116123 }
117124
125+ // We handle operands which are encoded with less than 4 bytes.
126+ // This occurs for opcode SET and tag U8 and U16.
118127 if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U8) {
119128 operands.push_back (static_cast <uint32_t >(bytecode.at (pos)));
120- uint8_t const * ptr = &bytecode.at (pos + 1 );
121- uint32_t operand{};
122- serialize::read (ptr, operand);
123- operands.push_back (operand);
124- pos += operands_size;
129+ pos++;
130+ num_of_operands--;
125131 } else if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U16) {
126132 uint8_t const * ptr = &bytecode.at (pos);
127133 uint16_t operand{};
128134 serialize::read (ptr, operand);
129135 operands.push_back (static_cast <uint32_t >(operand));
130- ptr = &bytecode.at (pos + 2 );
131- uint32_t operand2{};
132- serialize::read (ptr, operand2);
133- operands.push_back (operand2);
134- pos += operands_size;
135- } else {
136- for (size_t i = 0 ; i < num_of_operands; i++) {
137- uint8_t const * ptr = &bytecode.at (pos);
138- uint32_t operand{};
139- serialize::read (ptr, operand);
140- operands.push_back (operand);
141- pos += AVM_OPERAND_BYTE_LENGTH;
142- }
136+ pos += 2 ;
137+ num_of_operands--;
138+ }
139+
140+ // Operands of size of 32 bits.
141+ for (size_t i = 0 ; i < num_of_operands; i++) {
142+ uint8_t const * ptr = &bytecode.at (pos);
143+ uint32_t operand{};
144+ serialize::read (ptr, operand);
145+ operands.push_back (operand);
146+ pos += AVM_OPERAND_BYTE_LENGTH;
143147 }
144148
145149 instructions.emplace_back (opcode, operands, static_cast <AvmMemoryTag>(in_tag));
@@ -192,16 +196,17 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
192196 case AvmMemoryTag::U8:
193197 case AvmMemoryTag::U16:
194198 case AvmMemoryTag::U32:
199+ // U8, U16, U32 value represented in a single uint32_t operand
195200 val = inst.operands .at (0 );
196201 dst_offset = inst.operands .at (1 );
197202 break ;
198- case AvmMemoryTag::U64:
203+ case AvmMemoryTag::U64: // value represented as 2 uint32_t operands
199204 val = inst.operands .at (0 );
200205 val <<= 32 ;
201206 val += inst.operands .at (1 );
202207 dst_offset = inst.operands .at (2 );
203208 break ;
204- case AvmMemoryTag::U128:
209+ case AvmMemoryTag::U128: // value represented as 4 uint32_t operands
205210 for (size_t i = 0 ; i < 4 ; i++) {
206211 val += inst.operands .at (i);
207212 val <<= 32 ;
0 commit comments