1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
77constexpr std::string OPERAND_PREFIX =
"op";
78constexpr std::string BYTE_PREFIX =
"bd";
79constexpr std::string SELECTOR_PREFIX =
"sel_op_dc_";
81constexpr size_t NUM_OF_OPERANDS = 8;
94uint32_t encode_operand_idx_with_layout(uint8_t operand_idx, uint8_t
offset, uint8_t
len)
96 uint32_t layout =
len;
97 layout += (
static_cast<uint32_t
>(
offset) << 8);
98 layout += (
static_cast<uint32_t
>(operand_idx) << 16);
102uint8_t get_op_idx(uint32_t op_idx_with_layout)
104 return static_cast<uint8_t
>(op_idx_with_layout >> 16);
107OperandLayout get_op_layout(uint32_t op_idx_with_layout)
109 uint8_t
offset =
static_cast<uint8_t
>((op_idx_with_layout >> 8) & 0xFF);
110 uint8_t
len =
static_cast<uint8_t
>(op_idx_with_layout & 0xFF);
111 return OperandLayout{ .offset =
offset, .len =
len };
117 for (
const auto& wire_opcode : set) {
118 value += (
static_cast<uint128_t>(1) <<
static_cast<uint8_t
>(wire_opcode));
126 size_t num_of_selectors = sel_bitmasks.size();
127 std::vector<bool> selectors;
128 selectors.reserve(num_of_selectors);
130 for (
const auto& bitmask : sel_bitmasks) {
131 selectors.push_back(((
static_cast<uint128_t>(1) <<
static_cast<uint128_t>(wire_opcode)) & bitmask) != 0);
134 std::string output =
format(
"{", selectors[0]);
135 for (
size_t i = 1; i < num_of_selectors; i++) {
136 output +=
format(
", ", selectors[i]);
142auto add_fold = [](
const std::string&
a,
const std::string&
b) {
return a +
" + " +
b; };
149 for (
const auto& partition : partitions) {
150 output +=
format(
"pol ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.union_subset));
151 output +=
format(
" = ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_1));
152 output +=
format(
" + ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_2),
";\n");
158std::string render_operand_layout_pil(OperandLayout layout)
160 std::vector<std::string> monomials;
161 monomials.reserve(layout.len);
162 uint8_t byte_offset = layout.offset;
163 for (
int i = 0; i < layout.len; i++) {
165 format(BYTE_PREFIX, byte_offset + i + 1,
" * 2**", 8 * (layout.len - i - 1)));
168 return std::accumulate(std::next(monomials.begin()), monomials.end(), monomials[0], add_fold);
171std::string render_pil(
174 std::string pil_equations;
175 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
176 pil_equations += (i == 0) ?
"#[INDIRECT_BYTES_DECOMPOSITION]\n"
177 :
format(
"#[OP", static_cast<uint32_t>(i),
"_BYTES_DECOMPOSITION]\n");
178 pil_equations += (i == 0) ?
"indirect = " :
format(OPERAND_PREFIX, static_cast<uint32_t>(i),
" = ");
180 pil_equations +=
"(1 - PARSING_ERROR_EXCEPT_TAG_ERROR) * (";
182 std::vector<std::string> additive_terms;
183 for (
const auto& sel_layout : sel_layout_breakdowns[i]) {
184 additive_terms.push_back(
185 format(SELECTOR_PREFIX, sel_layout.first,
" * (", render_operand_layout_pil(sel_layout.second),
")"));
188 std::accumulate(std::next(additive_terms.begin()), additive_terms.end(), additive_terms[0], add_fold);
189 pil_equations +=
");\n";
191 return pil_equations;
201 for (
const auto& [opcode,
format] : wire_formats) {
204 uint8_t byte_offset = 0;
206 for (
const auto& operand :
format) {
207 const auto operand_len =
static_cast<uint8_t
>(operand_type_sizes.at(operand));
208 const auto op_layout = OperandLayout{ .offset = byte_offset, .len = operand_len };
210 if (operand == OperandType::INDIRECT8 || operand == OperandType::INDIRECT16) {
211 operands_layout_array[0] = op_layout;
213 operands_layout_array[op_idx++] = op_layout;
215 byte_offset += operand_len;
227 for (
const auto& [wire_opcode, operand_layouts] : opcode_to_layouts) {
228 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
229 const auto& layout = operand_layouts[i];
230 if (layout.len != 0) {
231 const auto key = encode_operand_idx_with_layout(i, layout.offset, layout.len);
232 if (op_idx_with_layout_to_subset.contains(
key)) {
233 op_idx_with_layout_to_subset[
key].insert(wire_opcode);
235 op_idx_with_layout_to_subset[
key] = { wire_opcode };
240 return op_idx_with_layout_to_subset;
243TEST(DecompositionSelectors, CodeGen)
247 gen_opcode_to_operands_layout();
252 gen_op_idx_with_layout_to_opcode_subset(opcode_to_layouts);
262 for (
const auto& [op_layout, subset] : op_idx_with_layout_to_subset) {
263 const auto encoded = encode_subset_wire_opcodes(subset);
264 set_of_bitmasks.insert(encoded);
265 op_idx_with_layout_to_bitmask.insert(
std::make_pair(op_layout, encoded));
268 info(
"NUMBER OF SUBSETS: ", set_of_bitmasks.size());
271 bool partition_found =
true;
277 while (partition_found) {
278 for (
auto it1 = set_of_bitmasks.begin(); it1 != set_of_bitmasks.end(); it1++) {
280 for (it2++; it2 != set_of_bitmasks.end(); it2++) {
282 if ((*it1 & *it2) == 0 && set_of_bitmasks.contains(sub_union)) {
283 info(
"PARTITION FOUND! ", *it1,
" ", *it2,
" ", sub_union);
284 partitions.push_back(Partition{ .subset_1 = *it1, .subset_2 = *it2, .union_subset = sub_union });
285 set_of_bitmasks.erase(sub_union);
286 partition_found =
true;
289 partition_found =
false;
291 if (partition_found) {
297 info(
"NUMBER OF SUBSETS AFTER PARTITION REMOVAL: ", set_of_bitmasks.size());
305 info(
"\n#################################");
306 info(
" Precomputed Selectors Table:");
307 info(
"#################################\n");
309 info(
"constexpr size_t NUM_OP_DC_SELECTORS = 18;\n\n");
311 info(
"const std::unordered_map<WireOpCode, std::array<uint8_t, NUM_OP_DC_SELECTORS>> WireOpCode_DC_SELECTORS = "
316 const auto wire_opcode =
static_cast<WireOpCode>(i);
317 if (wire_formats.contains(wire_opcode)) {
318 info(
"{WireOpCode::", wire_opcode,
", ", render_selector_array(wire_opcode, bitmasks_vector),
"},");
324 for (
const auto& partition : partitions) {
325 bitmasks_vector.push_back(partition.union_subset);
330 for (
size_t i = 0; i < bitmasks_vector.size(); i++) {
338 for (
const auto& [op_idx_with_layout, bitmask] : op_idx_with_layout_to_bitmask) {
339 uint8_t op_idx = get_op_idx(op_idx_with_layout);
340 OperandLayout layout = get_op_layout(op_idx_with_layout);
341 size_t sel_idx = bitmask_to_sel_idx.at(bitmask);
342 sel_layout_breakdowns[op_idx].emplace_back(
std::make_pair(sel_idx, layout));
346 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
348 sel_layout_breakdowns[i].begin(),
349 sel_layout_breakdowns[i].end(),
353 info(
"\n##################");
354 info(
"PIL Relations:");
355 info(
"##################\n");
357 info(render_partitions_pil(partitions, bitmask_to_sel_idx));
358 info(render_pil(sel_layout_breakdowns));
std::string format(Args... args)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
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