Skip to content

Commit 234154f

Browse files
authored
feat(avm)!: shifts skeleton (#16295)
Skeleton for shift opcodes to get further in the bulk test.. fyi @MirandaWood On Mainframe ``` ## TX Label: bulk_test/0 - Total duration: `287.005 ms` - Total mana used: `441,601` - Mana per second: `1,538,654` - Total instructions executed: `25,224` - Private insertions: - Non-revertible: `7.847 ms` - Revertible: `7.047 ms` - Proving: - Simulation (all): `241 ms` - Proving (all): `20,071 ms` - Trace generation (all): `3,032 ms` - Trace generation interactions: `1,515 ms` - Trace generation traces: `1,505 ms` - Sumcheck: `5,488 ms` - PCS: `3,414 ms` - Log derivative inverse: `369 ms` - Log derivative inverse commitments: `2,847 ms` - Wire commitments: `6,245 ms` - Enqueued public calls: - **Fn: AvmTest.bulk_testing** - Duration: `246.462 ms` - Mana used: `441,601` - Mana per second: `1,791,764` - Instructions executed: `25,224`
2 parents 5b8c54d + 97ff282 commit 234154f

28 files changed

Lines changed: 435 additions & 250 deletions

barretenberg/cpp/pil/vm2/alu.pil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ CHECK_TAG_U128 * (TAG_U128_DIFF * (sel_is_u128 * (1 - tag_u128_diff_inv) + tag_u
112112
// TAG CHECKING
113113

114114
// Will become e.g. sel_op_add * ia_tag + (comparison ops) * MEM_TAG_U1 + ....
115-
pol EXPECTED_C_TAG = (sel_op_add + sel_op_sub + sel_op_mul + sel_op_div + sel_op_truncate) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;
115+
pol EXPECTED_C_TAG = (sel_op_add + sel_op_sub + sel_op_mul + sel_op_div + sel_op_truncate + sel_op_shr + sel_op_shl) * ia_tag + (sel_op_eq + sel_op_lt + sel_op_lte) * constants.MEM_TAG_U1;
116116

117117
// The tag of c is generated by the opcode and is never wrong.
118118
// Gating with (1 - sel_tag_err) is necessary because when an error occurs, we have to set the tag to 0,
@@ -139,7 +139,7 @@ sel_tag_err = sel_ab_tag_mismatch + FF_TAG_ERR - sel_ab_tag_mismatch * FF_TAG_ER
139139
// For NOT opcode, an error occurs if the tag of a is FF. In this case, tracegen will set
140140
// b's tag as 0 which, while it would currently pass the checks below, is not a tag inequality we
141141
// want to throw with sel_ab_tag_mismatch:
142-
pol CHECK_AB_TAGS = 1 - sel_op_not * sel_is_ff - sel_op_truncate;
142+
pol CHECK_AB_TAGS = 1 - sel_op_not * sel_is_ff - sel_op_truncate - sel_op_shr - sel_op_shl; // note: shifts are temporary, they should be subject to AB checks
143143
pol AB_TAGS_EQ = 1 - sel_ab_tag_mismatch;
144144
pol commit ab_tags_diff_inv;
145145
// Prove that sel_ab_tag_mismatch = 1 <==> we have a disallowed inequality between the tags:

barretenberg/cpp/pil/vm2/context.pil

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,18 @@ namespace execution;
179179
NOT_LAST_EXEC * sel_enter_call * (is_static' - sel_execute_static_call) = 0;
180180

181181
// nested_exit_call = 1 ==> constraints come from lookup
182-
// sel_enter_call = 1 ==> parent_calldata_addr' = rop[3] (resolved operand 4 from execution trace)
182+
// sel_enter_call = 1 ==> parent_calldata_addr' = rop[4] (resolved operand 5 from execution trace)
183183
// otherwise = 0 ==> parent_calldata_addr' = parent_calldata_addr
184184
#[CD_OFFSET_NEXT_ROW]
185185
NOT_LAST_EXEC * DEFAULT_CTX_ROW * (parent_calldata_addr' - parent_calldata_addr) = 0;
186-
NOT_LAST_EXEC * sel_enter_call * (parent_calldata_addr' - rop[3]) = 0;
186+
NOT_LAST_EXEC * sel_enter_call * (parent_calldata_addr' - rop[4]) = 0;
187187

188188
// nested_exit_call = 1 ==> constraints come from lookup
189-
// sel_enter_call = 1 ==> parent_calldata_size' = rop[4] (resolved operand 5 from execution trace)
190-
// otherwise = 0 ==> parent_calldata_siz' = parent_calldata_size
189+
// sel_enter_call = 1 ==> parent_calldata_size' = register[3] (register 4 from execution trace)
190+
// otherwise = 0 ==> parent_calldata_size' = parent_calldata_size
191191
#[CD_SIZE_NEXT_ROW]
192192
NOT_LAST_EXEC * DEFAULT_CTX_ROW * (parent_calldata_size' - parent_calldata_size) = 0;
193-
NOT_LAST_EXEC * sel_enter_call * (parent_calldata_size' - rop[4]) = 0;
193+
NOT_LAST_EXEC * sel_enter_call * (parent_calldata_size' - register[3]) = 0;
194194

195195
pol NESTED_RET_REV_ONLY = nested_exit_call * (1 - sel_error);
196196
// NESTED_RET_REV_ONLY = 1 ==> rop[1] (resolved operand 2 from execution trace)

barretenberg/cpp/pil/vm2/opcodes/internal_call.pil

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,29 @@ namespace execution;
99
#[skippable_if]
1010
sel = 0;
1111

12-
pol SWITCH_CALL_ID = sel_execute_internal_call + sel_execute_internal_return;
13-
pol PROPAGATE_CALL_ID = (1 - SWITCH_CALL_ID) * (1 - enqueued_call_start);
12+
// sel_enter_call && enqueued_call_start' are mutually exclusive. sel_enter_call is constrained to be non-erroring, therefore the next row cannot be enqueued call start
13+
// When we encounter this case, the internal call information is reset on the next row (i.e. internal_call_id = 1, return_id = 0 and next_internal_call_id = 2)
14+
pol RESET_NEXT_CALL_ID = sel_enter_call + enqueued_call_start';
15+
16+
// sel_exit_call includes the error case, so we gate sel_execute_internal_call and sel_execute_internal_return by (1 - sel_error). This makes them all mututally exclusive.
17+
// When we encounter this case, the internal call information in the next row is constrained to change (incremented, unwound, etc)
18+
pol NEW_NEXT_CALL_ID = (sel_execute_internal_call + sel_execute_internal_return) * (1 - sel_error) + sel_exit_call;
19+
20+
pol PROPAGATE_CALL_ID = 1 - RESET_NEXT_CALL_ID - NEW_NEXT_CALL_ID;
1421

1522
// =============================
1623
// === Internal Call Pointer ===
1724
// =============================
1825
// The following is grouped together as the Internal Call Pointer struct in the simulator
1926

20-
// The current call id, constrained to be 1 at the start of an enqueued call
27+
// The current call id, constrained to be 1 at the start of a new context
2128
pol commit internal_call_id;
2229
#[CALL_ID_STARTS_ONE]
23-
enqueued_call_start * (internal_call_id - 1) = 0;
30+
RESET_NEXT_CALL_ID * (internal_call_id' - 1) = 0;
2431
// If we encounter a sel_execute_internal_call, the next internal_call_id is the current next_internal_call_id
2532
#[NEW_CALL_ID_ON_CALL]
2633
sel_execute_internal_call * (internal_call_id' - next_internal_call_id) = 0;
27-
// If we encounter a sel_return_call, the next internal call id is the current inter_call_return_id
34+
// If we encounter a sel_return_call, the next internal_call_id is the current internal_call_return_id
2835
#[RESTORE_INTERNAL_ID_ON_RETURN]
2936
sel_execute_internal_return * (internal_call_id' - internal_call_return_id) = 0;
3037
// Otherwise it's propagated down
@@ -34,7 +41,7 @@ namespace execution;
3441
// The call id when the next internal return is invoked, constrained to be 0 at the start of an enqueued call
3542
pol commit internal_call_return_id;
3643
#[RET_ID_STARTS_ZERO]
37-
enqueued_call_start * internal_call_return_id = 0;
44+
RESET_NEXT_CALL_ID * internal_call_return_id' = 0;
3845
// If we encounter a sel_execute_internal_call, the next internal_call_return_id is the current internal_call_id
3946
#[NEW_RETURN_ID_ON_CALL]
4047
sel_execute_internal_call * (internal_call_return_id' - internal_call_id) = 0;
@@ -46,10 +53,11 @@ namespace execution;
4653
// Constrained to start at 2 at the start of an enqueued call
4754
pol commit next_internal_call_id;
4855
#[NEXT_CALL_ID_STARTS_TWO]
49-
enqueued_call_start * (next_internal_call_id - 2) = 0;
50-
// If we encounter a sel_execute_internal_call, we increment the next next_internal_call_id
56+
RESET_NEXT_CALL_ID * (next_internal_call_id' - 2) = 0;
57+
// If we encounter a sel_execute_internal_call, we increment the next next_internal_call_id, unless we are changing context
58+
pol CONTEXT_CHANGE = (RESET_NEXT_CALL_ID + sel_exit_call) - (RESET_NEXT_CALL_ID * sel_exit_call) ;
5159
#[INCR_NEXT_INT_CALL_ID]
52-
NOT_LAST_EXEC * (next_internal_call_id' - (next_internal_call_id + sel_execute_internal_call)) = 0;
60+
NOT_LAST_EXEC * (1 - CONTEXT_CHANGE) * (next_internal_call_id' - (next_internal_call_id + sel_execute_internal_call)) = 0;
5361

5462
// =============================
5563
// === Error Handling ====

barretenberg/cpp/src/barretenberg/vm2/common/instruction_spec.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,14 @@ const std::unordered_map<ExecutionOpCode, ExecInstructionSpec> EXEC_INSTRUCTION_
500500
/*da_gas*/ ValueTag::U32,
501501
/*contract_address*/ ValueTag::FF,
502502
/*cd_size*/ ValueTag::U32 }) } },
503+
{ ExecutionOpCode::STATICCALL,
504+
{ .num_addresses = 5,
505+
.gas_cost = { .opcode_gas = AVM_STATICCALL_BASE_L2_GAS, .base_da = 0, .dyn_l2 = 0, .dyn_da = 0 },
506+
.register_info = RegisterInfo().add_inputs({ /*l2_gas*/ ValueTag::U32,
507+
/*da_gas*/ ValueTag::U32,
508+
/*contract_address*/ ValueTag::FF,
509+
/*cd_size*/ ValueTag::U32 }) } },
510+
503511
{ ExecutionOpCode::RETURN,
504512
{ .num_addresses = 2,
505513
.gas_cost = { .opcode_gas = AVM_RETURN_BASE_L2_GAS, .base_da = 0, .dyn_l2 = 0, .dyn_da = 0 },
@@ -674,7 +682,22 @@ const std::unordered_map<ExecutionOpCode, ExecInstructionSpec> EXEC_INSTRUCTION_
674682
ExecutionOpCode::SHA256COMPRESSION,
675683
{ .num_addresses = 3,
676684
.gas_cost = { .opcode_gas = AVM_SHA256COMPRESSION_BASE_L2_GAS, .base_da = 0, .dyn_l2 = 0, .dyn_da = 0 } },
677-
}
685+
},
686+
687+
{ ExecutionOpCode::SHR,
688+
{ .num_addresses = 3,
689+
.gas_cost = { .opcode_gas = AVM_SHR_BASE_L2_GAS, .base_da = 0, .dyn_l2 = 0, .dyn_da = 0 },
690+
.register_info = RegisterInfo()
691+
.add_inputs({ /*a*/ RegisterInfo::ANY_TAG,
692+
/*b*/ RegisterInfo::ANY_TAG })
693+
.add_output(/*c*/) } },
694+
{ ExecutionOpCode::SHL,
695+
{ .num_addresses = 3,
696+
.gas_cost = { .opcode_gas = AVM_SHL_BASE_L2_GAS, .base_da = 0, .dyn_l2 = 0, .dyn_da = 0 },
697+
.register_info = RegisterInfo()
698+
.add_inputs({ /*a*/ RegisterInfo::ANY_TAG,
699+
/*b*/ RegisterInfo::ANY_TAG })
700+
.add_output(/*c*/) } },
678701
};
679702

680703
} // namespace bb::avm2

barretenberg/cpp/src/barretenberg/vm2/common/tagged_value.test.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -508,25 +508,25 @@ TEST(TaggedValueTest, ErrorCases)
508508
// Test shift operations with different right-side types
509509
TEST(TaggedValueTest, ShiftOperationsWithDifferentTypes)
510510
{
511-
auto u32_val = TaggedValue::from<uint32_t>(1);
511+
auto shift_val = TaggedValue::from<uint8_t>(3);
512512

513-
// Shift with uint8_t
513+
// Shift a uint8_t by shift_val
514514
auto u8_amount = TaggedValue::from<uint8_t>(3);
515-
auto result_shl_u8 = u32_val << u8_amount;
516-
EXPECT_EQ(result_shl_u8.get_tag(), ValueTag::U32);
517-
EXPECT_EQ(result_shl_u8.as<uint32_t>(), 1 << 3);
515+
auto result_shl_u8 = u8_amount << shift_val;
516+
ASSERT_EQ(result_shl_u8.get_tag(), ValueTag::U8);
517+
EXPECT_EQ(result_shl_u8.as<uint8_t>(), 3 << 3);
518518

519-
// Shift with uint16_t
519+
// Shift a uint16_t by shift_val
520520
auto u16_amount = TaggedValue::from<uint16_t>(4);
521-
auto result_shl_u16 = u32_val << u16_amount;
522-
EXPECT_EQ(result_shl_u16.get_tag(), ValueTag::U32);
523-
EXPECT_EQ(result_shl_u16.as<uint32_t>(), 1 << 4);
521+
auto result_shl_u16 = u16_amount << shift_val;
522+
ASSERT_EQ(result_shl_u16.get_tag(), ValueTag::U16);
523+
EXPECT_EQ(result_shl_u16.as<uint16_t>(), 4 << 3);
524524

525-
// Shift with uint1_t
525+
// Shift a uint32_t by shift_val
526526
auto u1_amount = TaggedValue::from<uint1_t>(1);
527-
auto result_shl_u1 = u32_val << u1_amount;
528-
EXPECT_EQ(result_shl_u1.get_tag(), ValueTag::U32);
529-
EXPECT_EQ(result_shl_u1.as<uint32_t>(), 2);
527+
auto result_shl_u1 = u1_amount << shift_val;
528+
ASSERT_EQ(result_shl_u1.get_tag(), ValueTag::U1);
529+
EXPECT_EQ(result_shl_u1.as<uint1_t>(), static_cast<uint1_t>(0)); // 1 << 3 = 0 with overflow
530530
}
531531

532532
// Test boundary cases for all types

barretenberg/cpp/src/barretenberg/vm2/constraining/relations/context.test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ TEST(ContextConstrainingTest, ContextSwitchingCallReturn)
7979
{ C::execution_context_id, 1 },
8080
{ C::execution_next_context_id, 2 },
8181
{ C::execution_bytecode_id, top_bytecode_id }, // Same as previous row (propagated)
82-
{ C::execution_rop_3_, /*cd offset=*/10 },
83-
{ C::execution_rop_4_, /*cd size=*/1 },
82+
{ C::execution_rop_4_, /*cd offset=*/10 },
8483
{ C::execution_register_2_, /*contract address=*/0xdeadbeef },
84+
{ C::execution_register_3_, /*cd size=*/1 },
8585
{ C::execution_parent_l2_gas_limit, 2000 },
8686
{ C::execution_parent_da_gas_limit, 4000 },
8787
{ C::execution_parent_l2_gas_used, 500 },

barretenberg/cpp/src/barretenberg/vm2/generated/relations/alu.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,15 @@ template <typename FF_> class aluImpl {
5959
const auto alu_TAG_U128_DIFF = (in.get(C::alu_ia_tag) - constants_MEM_TAG_U128);
6060
const auto alu_EXPECTED_C_TAG =
6161
(in.get(C::alu_sel_op_add) + in.get(C::alu_sel_op_sub) + in.get(C::alu_sel_op_mul) +
62-
in.get(C::alu_sel_op_div) + in.get(C::alu_sel_op_truncate)) *
62+
in.get(C::alu_sel_op_div) + in.get(C::alu_sel_op_truncate) + in.get(C::alu_sel_op_shr) +
63+
in.get(C::alu_sel_op_shl)) *
6364
in.get(C::alu_ia_tag) +
6465
(in.get(C::alu_sel_op_eq) + in.get(C::alu_sel_op_lt) + in.get(C::alu_sel_op_lte)) * constants_MEM_TAG_U1;
6566
const auto alu_FF_TAG_ERR = (in.get(C::alu_sel_op_div) + in.get(C::alu_sel_op_not)) * in.get(C::alu_sel_is_ff);
6667
const auto alu_CHECK_AB_TAGS =
67-
((FF(1) - in.get(C::alu_sel_op_not) * in.get(C::alu_sel_is_ff)) - in.get(C::alu_sel_op_truncate));
68+
((((FF(1) - in.get(C::alu_sel_op_not) * in.get(C::alu_sel_is_ff)) - in.get(C::alu_sel_op_truncate)) -
69+
in.get(C::alu_sel_op_shr)) -
70+
in.get(C::alu_sel_op_shl));
6871
const auto alu_AB_TAGS_EQ = (FF(1) - in.get(C::alu_sel_ab_tag_mismatch));
6972
const auto alu_TWO_POW_64 = FF(uint256_t{ 0UL, 1UL, 0UL, 0UL });
7073
const auto alu_DECOMPOSED_A = in.get(C::alu_sel_mul_u128) * in.get(C::alu_ia) +

barretenberg/cpp/src/barretenberg/vm2/generated/relations/context.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ template <typename FF_> class contextImpl {
225225
{
226226
using Accumulator = typename std::tuple_element_t<23, ContainerOverSubrelations>;
227227
auto tmp = execution_NOT_LAST_EXEC * in.get(C::execution_sel_enter_call) *
228-
(in.get(C::execution_parent_calldata_addr_shift) - in.get(C::execution_rop_3_));
228+
(in.get(C::execution_parent_calldata_addr_shift) - in.get(C::execution_rop_4_));
229229
tmp *= scaling_factor;
230230
std::get<23>(evals) += typename Accumulator::View(tmp);
231231
}
@@ -239,7 +239,7 @@ template <typename FF_> class contextImpl {
239239
{
240240
using Accumulator = typename std::tuple_element_t<25, ContainerOverSubrelations>;
241241
auto tmp = execution_NOT_LAST_EXEC * in.get(C::execution_sel_enter_call) *
242-
(in.get(C::execution_parent_calldata_size_shift) - in.get(C::execution_rop_4_));
242+
(in.get(C::execution_parent_calldata_size_shift) - in.get(C::execution_register_3_));
243243
tmp *= scaling_factor;
244244
std::get<25>(evals) += typename Accumulator::View(tmp);
245245
}

barretenberg/cpp/src/barretenberg/vm2/generated/relations/internal_call.hpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ template <typename FF_> class internal_callImpl {
1414
public:
1515
using FF = FF_;
1616

17-
static constexpr std::array<size_t, 10> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 6, 3, 3, 6, 3, 4, 5 };
17+
static constexpr std::array<size_t, 10> SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 3, 6, 3, 3, 6, 3, 6, 5 };
1818

1919
template <typename AllEntities> inline static bool skip(const AllEntities& in)
2020
{
@@ -34,14 +34,19 @@ template <typename FF_> class internal_callImpl {
3434
PROFILE_THIS_NAME("accumulate/internal_call");
3535

3636
const auto execution_NOT_LAST_EXEC = in.get(C::execution_sel) * in.get(C::execution_sel_shift);
37-
const auto execution_SWITCH_CALL_ID =
38-
in.get(C::execution_sel_execute_internal_call) + in.get(C::execution_sel_execute_internal_return);
39-
const auto execution_PROPAGATE_CALL_ID =
40-
(FF(1) - execution_SWITCH_CALL_ID) * (FF(1) - in.get(C::execution_enqueued_call_start));
37+
const auto execution_RESET_NEXT_CALL_ID =
38+
in.get(C::execution_sel_enter_call) + in.get(C::execution_enqueued_call_start_shift);
39+
const auto execution_NEW_NEXT_CALL_ID =
40+
(in.get(C::execution_sel_execute_internal_call) + in.get(C::execution_sel_execute_internal_return)) *
41+
(FF(1) - in.get(C::execution_sel_error)) +
42+
in.get(C::execution_sel_exit_call);
43+
const auto execution_PROPAGATE_CALL_ID = ((FF(1) - execution_RESET_NEXT_CALL_ID) - execution_NEW_NEXT_CALL_ID);
44+
const auto execution_CONTEXT_CHANGE = ((execution_RESET_NEXT_CALL_ID + in.get(C::execution_sel_exit_call)) -
45+
execution_RESET_NEXT_CALL_ID * in.get(C::execution_sel_exit_call));
4146

4247
{ // CALL_ID_STARTS_ONE
4348
using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
44-
auto tmp = in.get(C::execution_enqueued_call_start) * (in.get(C::execution_internal_call_id) - FF(1));
49+
auto tmp = execution_RESET_NEXT_CALL_ID * (in.get(C::execution_internal_call_id_shift) - FF(1));
4550
tmp *= scaling_factor;
4651
std::get<0>(evals) += typename Accumulator::View(tmp);
4752
}
@@ -68,7 +73,7 @@ template <typename FF_> class internal_callImpl {
6873
}
6974
{ // RET_ID_STARTS_ZERO
7075
using Accumulator = typename std::tuple_element_t<4, ContainerOverSubrelations>;
71-
auto tmp = in.get(C::execution_enqueued_call_start) * in.get(C::execution_internal_call_return_id);
76+
auto tmp = execution_RESET_NEXT_CALL_ID * in.get(C::execution_internal_call_return_id_shift);
7277
tmp *= scaling_factor;
7378
std::get<4>(evals) += typename Accumulator::View(tmp);
7479
}
@@ -89,13 +94,13 @@ template <typename FF_> class internal_callImpl {
8994
}
9095
{ // NEXT_CALL_ID_STARTS_TWO
9196
using Accumulator = typename std::tuple_element_t<7, ContainerOverSubrelations>;
92-
auto tmp = in.get(C::execution_enqueued_call_start) * (in.get(C::execution_next_internal_call_id) - FF(2));
97+
auto tmp = execution_RESET_NEXT_CALL_ID * (in.get(C::execution_next_internal_call_id_shift) - FF(2));
9398
tmp *= scaling_factor;
9499
std::get<7>(evals) += typename Accumulator::View(tmp);
95100
}
96101
{ // INCR_NEXT_INT_CALL_ID
97102
using Accumulator = typename std::tuple_element_t<8, ContainerOverSubrelations>;
98-
auto tmp = execution_NOT_LAST_EXEC *
103+
auto tmp = execution_NOT_LAST_EXEC * (FF(1) - execution_CONTEXT_CHANGE) *
99104
(in.get(C::execution_next_internal_call_id_shift) -
100105
(in.get(C::execution_next_internal_call_id) + in.get(C::execution_sel_execute_internal_call)));
101106
tmp *= scaling_factor;

barretenberg/cpp/src/barretenberg/vm2/simulation/alu.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,30 @@ MemoryValue Alu::truncate(const FF& a, MemoryTag dst_tag)
187187
return c;
188188
}
189189

190+
MemoryValue Alu::shr(const MemoryValue& a, const MemoryValue& b)
191+
{
192+
// todo: Tag checks need to change to ensure LHS == RHS, this is in the ShiftVisitor in tagged value
193+
try {
194+
MemoryValue c = a >> b;
195+
events.emit({ .operation = AluOperation::SHR, .a = a, .b = b, .c = c });
196+
return c;
197+
} catch (const std::exception& e) {
198+
events.emit({ .operation = AluOperation::SHR, .a = a, .b = b, .error = AluError::TAG_ERROR });
199+
throw AluException("SHR, " + std::string(e.what()));
200+
}
201+
}
202+
203+
MemoryValue Alu::shl(const MemoryValue& a, const MemoryValue& b)
204+
{
205+
// todo: Tag checks need to change to ensure LHS == RHS, this is in the ShiftVisitor in tagged value
206+
try {
207+
MemoryValue c = a << b;
208+
events.emit({ .operation = AluOperation::SHL, .a = a, .b = b, .c = c });
209+
return c;
210+
} catch (const std::exception& e) {
211+
events.emit({ .operation = AluOperation::SHL, .a = a, .b = b, .error = AluError::TAG_ERROR });
212+
throw AluException("SHL, " + std::string(e.what()));
213+
}
214+
}
215+
190216
} // namespace bb::avm2::simulation

0 commit comments

Comments
 (0)