Skip to content

Commit 4889b79

Browse files
committed
seems to be working for Mega arithmetized Ultra verifier op codes
1 parent d4ee170 commit 4889b79

2 files changed

Lines changed: 394 additions & 58 deletions

File tree

barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp

Lines changed: 123 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,84 @@ void build_constraints_parallel(Builder& builder,
492492
profile_and_collect(constraints.multi_scalar_mul_constraints, msm_handler, msm_key);
493493
profile_and_collect(constraints.ec_add_constraints, ec_add_handler, const_key);
494494

495+
// Recursion constraints are parallelized like other constraint types, but each task also
496+
// captures a HonkRecursionConstraintOutput for post-join merging (needed for pairing point
497+
// propagation and IPA finalization).
498+
struct RecursionTaskInfo {
499+
HonkRecursionConstraintOutput<Builder> output;
500+
bool update_ipa_data = false;
501+
bool is_root_rollup = false;
502+
};
503+
size_t num_rec_tasks = constraints.honk_recursion_constraints.size() +
504+
constraints.chonk_recursion_constraints.size() +
505+
constraints.avm_recursion_constraints.size();
506+
std::vector<RecursionTaskInfo> recursion_task_outputs(num_rec_tasks);
507+
size_t rec_out_idx = 0;
508+
509+
// Helper: execute a single honk recursion constraint based on proof_type
510+
auto execute_honk_recursion = [](Builder& b,
511+
const RecursionConstraint& c) -> HonkRecursionConstraintOutput<Builder> {
512+
if (c.proof_type == HONK_ZK) {
513+
return create_honk_recursion_constraints<UltraZKRecursiveFlavor_<Builder>,
514+
stdlib::recursion::honk::DefaultIO<Builder>>(b, c);
515+
} else if (c.proof_type == HONK) {
516+
return create_honk_recursion_constraints<UltraRecursiveFlavor_<Builder>,
517+
stdlib::recursion::honk::DefaultIO<Builder>>(b, c);
518+
} else {
519+
// Rollup IO is only supported on UltraCircuitBuilder
520+
if constexpr (std::is_same_v<Builder, UltraCircuitBuilder>) {
521+
return create_honk_recursion_constraints<UltraRecursiveFlavor_<Builder>,
522+
stdlib::recursion::honk::RollupIO>(b, c);
523+
} else {
524+
bb::assert_failure("Rollup Honk proof type not supported on MegaBuilder");
525+
return {};
526+
}
527+
}
528+
};
529+
530+
// Profiling handler (discards output — only used for measuring gate counts)
531+
auto honk_rec_handler = [&execute_honk_recursion](Builder& b, const RecursionConstraint& c) {
532+
execute_honk_recursion(b, c);
533+
};
534+
auto honk_rec_key = [](const RecursionConstraint& c) -> uint32_t { return c.proof_type; };
535+
536+
// Profile honk recursion constraints by proof_type
537+
std::map<uint32_t, size_t> honk_rec_profiles;
538+
for (size_t i = 0; i < constraints.honk_recursion_constraints.size(); i++) {
539+
uint32_t k = honk_rec_key(constraints.honk_recursion_constraints[i]);
540+
if (honk_rec_profiles.count(k) == 0) {
541+
auto profile = profile_constraint_type<Builder>(
542+
constraints.honk_recursion_constraints[i], honk_rec_handler, num_witnesses);
543+
honk_rec_profiles[k] = profiles.size();
544+
profiles.push_back(profile);
545+
}
546+
}
547+
// Add honk recursion tasks in vector order with output capture
548+
for (size_t i = 0; i < constraints.honk_recursion_constraints.size(); i++) {
549+
const auto& c = constraints.honk_recursion_constraints[i];
550+
size_t profile_idx = honk_rec_profiles.at(c.proof_type);
551+
const auto& profile = profiles[profile_idx];
552+
auto sizes = profile.block_sizes;
553+
sizes.num_rom_arrays = profile.num_rom_arrays_per_instance;
554+
sizes.num_ram_arrays = profile.num_ram_arrays_per_instance;
555+
556+
size_t out_idx = rec_out_idx++;
557+
recursion_task_outputs[out_idx].update_ipa_data =
558+
(c.proof_type == ROLLUP_HONK || c.proof_type == ROOT_ROLLUP_HONK);
559+
recursion_task_outputs[out_idx].is_root_rollup = (c.proof_type == ROOT_ROLLUP_HONK);
560+
561+
tasks.emplace_back(
562+
[&constraints, i, &execute_honk_recursion, &recursion_task_outputs, out_idx](BaseBuilder& b) {
563+
recursion_task_outputs[out_idx].output =
564+
execute_honk_recursion(static_cast<Builder&>(b), constraints.honk_recursion_constraints[i]);
565+
});
566+
task_sizes.push_back(sizes);
567+
task_profile_indices.push_back(profile_idx);
568+
}
569+
570+
// TODO: Chonk and AVM recursion constraints — same pattern as honk above.
571+
// For now they fall through to Phase 4 sequential processing if present.
572+
495573
// Phase 2: Prepare the builder's caches from profiles (no constraint execution).
496574
prepare_builder_from_profiles(builder, profiles);
497575

@@ -511,32 +589,61 @@ void build_constraints_parallel(Builder& builder,
511589
}
512590
}
513591

514-
// Phase 3: Execute ALL instances in parallel
515-
// execute_parallel will set up per-thread ROM/RAM cursors using the num_rom/ram_arrays in task_sizes
592+
// Phase 3: Execute ALL instances in parallel (including recursion constraints)
516593
if (!tasks.empty()) {
517594
builder.execute_parallel(tasks, task_sizes, num_threads);
518595
}
519596

520-
// Phase 4: Block constraints and recursion constraints are processed sequentially.
597+
// Phase 4: Block constraints (sequential — these reference variables from earlier constraints).
521598
for (const auto& [constraint, opcode_indices] :
522599
zip_view(constraints.block_constraints, constraints.original_opcode_indices.block_constraints)) {
523600
create_block_constraints(builder, constraint);
524601
}
525602

526-
const bool is_hn_recursion_constraints = !constraints.hn_recursion_constraints.empty();
527-
GateCounter gate_counter{ &builder, false };
528-
std::vector<size_t> dummy_gates_per_opcode;
529-
HonkRecursionConstraintsOutput<Builder> output = create_recursion_constraints<Builder>(
530-
builder,
531-
gate_counter,
532-
dummy_gates_per_opcode,
533-
metadata.ivc,
534-
{ constraints.honk_recursion_constraints, constraints.original_opcode_indices.honk_recursion_constraints },
535-
{ constraints.avm_recursion_constraints, constraints.original_opcode_indices.avm_recursion_constraints },
536-
{ constraints.hn_recursion_constraints, constraints.original_opcode_indices.hn_recursion_constraints },
537-
{ constraints.chonk_recursion_constraints, constraints.original_opcode_indices.chonk_recursion_constraints });
603+
// Phase 4b: Merge recursion outputs from parallel tasks and process remaining sequential recursion.
604+
{
605+
HonkRecursionConstraintsOutput<Builder> output;
538606

539-
output.finalize(builder, is_hn_recursion_constraints, metadata.has_ipa_claim);
607+
// Merge outputs from honk recursion tasks that ran in Phase 3
608+
for (size_t i = 0; i < rec_out_idx; i++) {
609+
const auto& rec = recursion_task_outputs[i];
610+
output.update(rec.output, rec.update_ipa_data);
611+
if (rec.is_root_rollup) {
612+
output.is_root_rollup = true;
613+
}
614+
}
615+
616+
// Chonk and AVM recursion constraints — Ultra only, sequential for now (TODO: parallelize)
617+
if constexpr (std::is_same_v<Builder, UltraCircuitBuilder>) {
618+
for (const auto& constraint : constraints.chonk_recursion_constraints) {
619+
auto honk_output = create_chonk_recursion_constraints(builder, constraint);
620+
output.update(honk_output, /*update_ipa_data=*/true);
621+
}
622+
for (const auto& constraint : constraints.avm_recursion_constraints) {
623+
auto honk_output = create_avm2_recursion_constraints_goblin(builder, constraint);
624+
output.update(honk_output, /*update_ipa_data=*/true);
625+
}
626+
}
627+
628+
// HyperNova recursion constraints (Mega only, requires IVC state — always sequential)
629+
const bool is_hn_recursion_constraints = !constraints.hn_recursion_constraints.empty();
630+
if (is_hn_recursion_constraints) {
631+
GateCounter gate_counter{ &builder, false };
632+
std::vector<size_t> dummy_gates_per_opcode;
633+
auto hn_output = create_recursion_constraints<Builder>(
634+
builder,
635+
gate_counter,
636+
dummy_gates_per_opcode,
637+
metadata.ivc,
638+
{ {}, {} },
639+
{ {}, {} },
640+
{ constraints.hn_recursion_constraints, constraints.original_opcode_indices.hn_recursion_constraints },
641+
{ {}, {} });
642+
output.update(hn_output, /*update_ipa_data=*/false);
643+
}
644+
645+
output.finalize(builder, is_hn_recursion_constraints, metadata.has_ipa_claim);
646+
}
540647
}
541648

542649
template void build_constraints_parallel<UltraCircuitBuilder>(UltraCircuitBuilder&,

0 commit comments

Comments
 (0)