1use std::collections::HashMap;
2
3use acir::circuit::{AssertionPayload, Circuit, ExpressionWidth, OpcodeLocation};
4
5mod optimizers;
7mod transformers;
8
9pub use optimizers::optimize;
10use optimizers::optimize_internal;
11pub use transformers::transform;
12use transformers::transform_internal;
13
14#[derive(Debug)]
17pub struct AcirTransformationMap {
18 old_indices_to_new_indices: HashMap<usize, Vec<usize>>,
20}
21
22impl AcirTransformationMap {
23 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
69pub 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}