Skip to content

Commit 4f05854

Browse files
authored
Merge 274bdd1 into 66d3275
2 parents 66d3275 + 274bdd1 commit 4f05854

File tree

7 files changed

+514
-31
lines changed

7 files changed

+514
-31
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

acvm-repo/acvm/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ workspace = true
1717
thiserror.workspace = true
1818
tracing.workspace = true
1919
serde.workspace = true
20-
20+
fxhash.workspace = true
2121
acir.workspace = true
2222
brillig_vm.workspace = true
2323
acvm_blackbox_solver.workspace = true

acvm-repo/acvm/src/compiler/mod.rs

+35-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ pub use simulator::CircuitSimulator;
1616
use transformers::transform_internal;
1717
pub use transformers::{transform, MIN_EXPRESSION_WIDTH};
1818

19+
/// We need multiple passes to stabilize the output.
20+
/// The value was determined by running tests.
21+
const MAX_OPTIMIZER_PASSES: usize = 3;
22+
1923
/// This module moves and decomposes acir opcodes. The transformation map allows consumers of this module to map
2024
/// metadata they had about the opcodes to the new opcode structure generated after the transformation.
2125
#[derive(Debug)]
@@ -28,9 +32,9 @@ impl AcirTransformationMap {
2832
/// Builds a map from a vector of pointers to the old acir opcodes.
2933
/// The index of the vector is the new opcode index.
3034
/// The value of the vector is the old opcode index pointed.
31-
fn new(acir_opcode_positions: Vec<usize>) -> Self {
35+
fn new(acir_opcode_positions: &[usize]) -> Self {
3236
let mut old_indices_to_new_indices = HashMap::with_capacity(acir_opcode_positions.len());
33-
for (new_index, old_index) in acir_opcode_positions.into_iter().enumerate() {
37+
for (new_index, old_index) in acir_opcode_positions.iter().copied().enumerate() {
3438
old_indices_to_new_indices.entry(old_index).or_insert_with(Vec::new).push(new_index);
3539
}
3640
AcirTransformationMap { old_indices_to_new_indices }
@@ -72,17 +76,42 @@ fn transform_assert_messages<F: Clone>(
7276
}
7377

7478
/// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`].
79+
///
80+
/// Runs multiple passes until the output stabilizes.
7581
pub fn compile<F: AcirField>(
7682
acir: Circuit<F>,
7783
expression_width: ExpressionWidth,
7884
) -> (Circuit<F>, AcirTransformationMap) {
79-
let (acir, acir_opcode_positions) = optimize_internal(acir);
85+
let mut pass = 0;
86+
let mut prev_opcodes_hash = fxhash::hash64(&acir.opcodes);
87+
let mut prev_acir = acir;
88+
89+
// For most test programs it would be enough to only loop `transform_internal`,
90+
// but some of them don't stabilize unless we also repeat the backend agnostic optimizations.
91+
let (mut acir, acir_opcode_positions) = loop {
92+
let (acir, acir_opcode_positions) = optimize_internal(prev_acir);
93+
94+
// Stop if we have already done at least one transform and an extra optimization changed nothing.
95+
if pass > 0 && prev_opcodes_hash == fxhash::hash64(&acir.opcodes) {
96+
break (acir, acir_opcode_positions);
97+
}
8098

81-
let (mut acir, acir_opcode_positions) =
82-
transform_internal(acir, expression_width, acir_opcode_positions);
99+
let (acir, acir_opcode_positions) =
100+
transform_internal(acir, expression_width, acir_opcode_positions);
101+
102+
let opcodes_hash = fxhash::hash64(&acir.opcodes);
103+
104+
// Stop if the output hasn't change in this loop or we went too long.
105+
if pass == MAX_OPTIMIZER_PASSES - 1 || prev_opcodes_hash == opcodes_hash {
106+
break (acir, acir_opcode_positions);
107+
}
83108

84-
let transformation_map = AcirTransformationMap::new(acir_opcode_positions);
109+
pass += 1;
110+
prev_acir = acir;
111+
prev_opcodes_hash = opcodes_hash;
112+
};
85113

114+
let transformation_map = AcirTransformationMap::new(&acir_opcode_positions);
86115
acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map);
87116

88117
(acir, transformation_map)

acvm-repo/acvm/src/compiler/optimizers/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use super::{transform_assert_messages, AcirTransformationMap};
2323
pub fn optimize<F: AcirField>(acir: Circuit<F>) -> (Circuit<F>, AcirTransformationMap) {
2424
let (mut acir, new_opcode_positions) = optimize_internal(acir);
2525

26-
let transformation_map = AcirTransformationMap::new(new_opcode_positions);
26+
let transformation_map = AcirTransformationMap::new(&new_opcode_positions);
2727

2828
acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map);
2929

0 commit comments

Comments
 (0)