acvm/compiler/
mod.rs

1use std::collections::HashMap;
2
3use acir::circuit::{AssertionPayload, Circuit, ExpressionWidth, OpcodeLocation};
4
5// The various passes that we can use over ACIR
6mod optimizers;
7mod transformers;
8
9pub use optimizers::optimize;
10use optimizers::optimize_internal;
11pub use transformers::transform;
12use transformers::transform_internal;
13
14/// This module moves and decomposes acir opcodes. The transformation map allows consumers of this module to map
15/// metadata they had about the opcodes to the new opcode structure generated after the transformation.
16#[derive(Debug)]
17pub struct AcirTransformationMap {
18    /// Maps the old acir indices to the new acir indices
19    old_indices_to_new_indices: HashMap<usize, Vec<usize>>,
20}
21
22impl AcirTransformationMap {
23    /// Builds a map from a vector of pointers to the old acir opcodes.
24    /// The index of the vector is the new opcode index.
25    /// The value of the vector is the old opcode index pointed.
26    fn new(acir_opcode_positions: Vec<usize>) -> Self {
27        let mut old_indices_to_new_indices = HashMap::with_capacity(acir_opcode_positions.len());
28        for (new_index, old_index) in acir_opcode_positions.into_iter().enumerate() {
29            old_indices_to_new_indices.entry(old_index).or_insert_with(Vec::new).push(new_index);
30        }
31        AcirTransformationMap { old_indices_to_new_indices }
32    }
33
34    pub fn new_locations(
35        &self,
36        old_location: OpcodeLocation,
37    ) -> impl Iterator<Item = OpcodeLocation> + '_ {
38        let old_acir_index = match old_location {
39            OpcodeLocation::Acir(index) => index,
40            OpcodeLocation::Brillig { acir_index, .. } => acir_index,
41        };
42
43        self.old_indices_to_new_indices.get(&old_acir_index).into_iter().flat_map(
44            move |new_indices| {
45                new_indices.iter().map(move |new_index| match old_location {
46                    OpcodeLocation::Acir(_) => OpcodeLocation::Acir(*new_index),
47                    OpcodeLocation::Brillig { brillig_index, .. } => {
48                        OpcodeLocation::Brillig { acir_index: *new_index, brillig_index }
49                    }
50                })
51            },
52        )
53    }
54}
55
56fn transform_assert_messages(
57    assert_messages: Vec<(OpcodeLocation, AssertionPayload)>,
58    map: &AcirTransformationMap,
59) -> Vec<(OpcodeLocation, AssertionPayload)> {
60    assert_messages
61        .into_iter()
62        .flat_map(|(location, message)| {
63            let new_locations = map.new_locations(location);
64            new_locations.into_iter().map(move |new_location| (new_location, message.clone()))
65        })
66        .collect()
67}
68
69/// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`].
70pub fn compile(
71    acir: Circuit,
72    expression_width: ExpressionWidth,
73) -> (Circuit, AcirTransformationMap) {
74    let (acir, acir_opcode_positions) = optimize_internal(acir);
75
76    let (mut acir, acir_opcode_positions) =
77        transform_internal(acir, expression_width, acir_opcode_positions);
78
79    let transformation_map = AcirTransformationMap::new(acir_opcode_positions);
80
81    acir.assert_messages = transform_assert_messages(acir.assert_messages, &transformation_map);
82
83    (acir, transformation_map)
84}