1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
80constexpr std::string OPERAND_PREFIX =
"op";
81constexpr std::string BYTE_PREFIX =
"bd";
82constexpr std::string SELECTOR_PREFIX =
"sel_op_dc_";
84constexpr size_t NUM_OF_OPERANDS = 6;
97uint32_t encode_operand_idx_with_layout(uint8_t operand_idx, uint8_t
offset, uint8_t
len)
99 uint32_t layout =
len;
100 layout += (
static_cast<uint32_t
>(
offset) << 8);
101 layout += (
static_cast<uint32_t
>(operand_idx) << 16);
105uint8_t get_op_idx(uint32_t op_idx_with_layout)
107 return static_cast<uint8_t
>(op_idx_with_layout >> 16);
110OperandLayout get_op_layout(uint32_t op_idx_with_layout)
112 uint8_t
offset =
static_cast<uint8_t
>((op_idx_with_layout >> 8) & 0xFF);
113 uint8_t
len =
static_cast<uint8_t
>(op_idx_with_layout & 0xFF);
114 return OperandLayout{ .offset =
offset, .len =
len };
120 for (
const auto& wire_opcode : set) {
121 value += (
static_cast<uint128_t>(1) <<
static_cast<uint8_t
>(wire_opcode));
129 size_t num_of_selectors = sel_bitmasks.size();
130 std::vector<bool> selectors;
131 selectors.reserve(num_of_selectors);
133 for (
const auto& bitmask : sel_bitmasks) {
134 selectors.push_back(((
static_cast<uint128_t>(1) <<
static_cast<uint128_t>(wire_opcode)) & bitmask) != 0);
137 std::string output =
format(
"{", selectors[0]);
138 for (
size_t i = 1; i < num_of_selectors; i++) {
139 output +=
format(
", ", selectors[i]);
145auto add_fold = [](
const std::string&
a,
const std::string&
b) {
return a +
" + " +
b; };
152 for (
const auto& partition : partitions) {
153 output +=
format(
"pol ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.union_subset));
154 output +=
format(
" = ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_1));
155 output +=
format(
" + ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_2),
";\n");
161std::string render_operand_layout_pil(OperandLayout layout)
163 std::vector<std::string> monomials;
164 monomials.reserve(layout.len);
165 uint8_t byte_offset = layout.offset;
166 for (
int i = 0; i < layout.len; i++) {
168 format(BYTE_PREFIX, byte_offset + i + 1,
" * 2**", 8 * (layout.len - i - 1)));
171 return std::accumulate(std::next(monomials.begin()), monomials.end(), monomials[0], add_fold);
174std::string render_pil(
177 std::string pil_equations;
178 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
179 pil_equations += (i == 0) ?
"#[ADDRESSING_MODE_BYTES_DECOMPOSITION]\n"
180 :
format(
"#[OP", static_cast<uint32_t>(i),
"_BYTES_DECOMPOSITION]\n");
181 pil_equations += (i == 0) ?
"addressing_mode = " :
format(OPERAND_PREFIX, static_cast<uint32_t>(i),
" = ");
183 pil_equations +=
"(1 - PARSING_ERROR_EXCEPT_TAG_ERROR) * (";
185 std::vector<std::string> additive_terms;
186 for (
const auto& sel_layout : sel_layout_breakdowns[i]) {
187 additive_terms.push_back(
188 format(SELECTOR_PREFIX, sel_layout.first,
" * (", render_operand_layout_pil(sel_layout.second),
")"));
191 std::accumulate(std::next(additive_terms.begin()), additive_terms.end(), additive_terms[0], add_fold);
192 pil_equations +=
");\n";
194 return pil_equations;
204 for (
const auto& [opcode,
format] : wire_formats) {
207 uint8_t byte_offset = 0;
209 for (
const auto& operand :
format) {
210 const auto operand_len =
static_cast<uint8_t
>(operand_type_sizes.at(operand));
211 const auto op_layout = OperandLayout{ .offset = byte_offset, .len = operand_len };
213 if (operand == OperandType::INDIRECT8 || operand == OperandType::INDIRECT16) {
214 operands_layout_array[0] = op_layout;
216 operands_layout_array[op_idx++] = op_layout;
218 byte_offset += operand_len;
230 for (
const auto& [wire_opcode, operand_layouts] : opcode_to_layouts) {
231 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
232 const auto& layout = operand_layouts[i];
233 if (layout.len != 0) {
234 const auto key = encode_operand_idx_with_layout(i, layout.offset, layout.len);
235 if (op_idx_with_layout_to_subset.contains(
key)) {
236 op_idx_with_layout_to_subset[
key].insert(wire_opcode);
238 op_idx_with_layout_to_subset[
key] = { wire_opcode };
243 return op_idx_with_layout_to_subset;
246TEST(DecompositionSelectors, CodeGen)
250 gen_opcode_to_operands_layout();
255 gen_op_idx_with_layout_to_opcode_subset(opcode_to_layouts);
265 for (
const auto& [op_layout, subset] : op_idx_with_layout_to_subset) {
266 const auto encoded = encode_subset_wire_opcodes(subset);
267 set_of_bitmasks.insert(encoded);
268 op_idx_with_layout_to_bitmask.insert(
std::make_pair(op_layout, encoded));
271 info(
"NUMBER OF SUBSETS: ", set_of_bitmasks.size());
274 bool partition_found =
true;
280 while (partition_found) {
281 for (
auto it1 = set_of_bitmasks.begin(); it1 != set_of_bitmasks.end(); it1++) {
283 for (it2++; it2 != set_of_bitmasks.end(); it2++) {
285 if ((*it1 & *it2) == 0 && set_of_bitmasks.contains(sub_union)) {
286 info(
"PARTITION FOUND! ", *it1,
" ", *it2,
" ", sub_union);
287 partitions.push_back(Partition{ .subset_1 = *it1, .subset_2 = *it2, .union_subset = sub_union });
288 set_of_bitmasks.erase(sub_union);
289 partition_found =
true;
292 partition_found =
false;
294 if (partition_found) {
300 info(
"NUMBER OF SUBSETS AFTER PARTITION REMOVAL: ", set_of_bitmasks.size());
308 info(
"\n#################################");
309 info(
" Precomputed Selectors Table:");
310 info(
"#################################\n");
312 info(
"constexpr size_t NUM_OP_DC_SELECTORS = ", set_of_bitmasks.size(),
";\n\n");
314 info(
"const std::unordered_map<WireOpCode, std::array<uint8_t, NUM_OP_DC_SELECTORS>> WireOpCode_DC_SELECTORS = "
319 const auto wire_opcode =
static_cast<WireOpCode>(i);
320 if (wire_formats.contains(wire_opcode)) {
321 info(
"{WireOpCode::", wire_opcode,
", ", render_selector_array(wire_opcode, bitmasks_vector),
"},");
327 for (
const auto& partition : partitions) {
328 bitmasks_vector.push_back(partition.union_subset);
333 for (
size_t i = 0; i < bitmasks_vector.size(); i++) {
341 for (
const auto& [op_idx_with_layout, bitmask] : op_idx_with_layout_to_bitmask) {
342 uint8_t op_idx = get_op_idx(op_idx_with_layout);
343 OperandLayout layout = get_op_layout(op_idx_with_layout);
344 size_t sel_idx = bitmask_to_sel_idx.at(bitmask);
345 sel_layout_breakdowns[op_idx].emplace_back(
std::make_pair(sel_idx, layout));
349 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
351 sel_layout_breakdowns[i].begin(),
352 sel_layout_breakdowns[i].end(),
356 info(
"\n##################");
357 info(
"PIL Relations:");
358 info(
"##################\n");
360 info(render_partitions_pil(partitions, bitmask_to_sel_idx));
361 info(render_pil(sel_layout_breakdowns));
std::string format(Args... args)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
const std::unordered_map< OperandType, uint32_t > & get_operand_type_sizes()
const std::unordered_map< WireOpCode, std::vector< OperandType > > & get_instruction_wire_formats()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t