Skip to content

Commit ab32365

Browse files
guipublicTomAFrench
andauthoredMar 22, 2023
fix: rationalise witness for constant values (#984)
* rationalise witness for constant values * Resolve issue 770 * Update crates/noirc_evaluator/src/ssa/acir_gen/internal_var_cache.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Update crates/noirc_evaluator/src/ssa/context.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Update crates/noirc_evaluator/src/ssa/acir_gen/internal_var_cache.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Code review * Code review * Code review - styling * clippy --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
1 parent f74e8fa commit ab32365

File tree

9 files changed

+347
-180
lines changed

9 files changed

+347
-180
lines changed
 

‎crates/noirc_evaluator/src/ssa/acir_gen.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl Acir {
6767

6868
let output = match &ins.operation {
6969
Operation::Binary(binary) => {
70-
binary::evaluate(binary, ins.res_type, var_cache, acir_mem, evaluator, ctx)
70+
binary::evaluate(binary, ins.res_type, self, evaluator, ctx)
7171
}
7272
Operation::Constrain(value, ..) => {
7373
constrain::evaluate(value, var_cache, evaluator, ctx)
@@ -89,7 +89,7 @@ impl Acir {
8989
}
9090
_ => *opcode,
9191
};
92-
intrinsics::evaluate(args, ins, opcode, var_cache, acir_mem, ctx, evaluator)
92+
intrinsics::evaluate(args, ins, opcode, self, ctx, evaluator)
9393
}
9494
Operation::Return(node_ids) => {
9595
r#return::evaluate(node_ids, acir_mem, var_cache, evaluator, ctx)?
@@ -118,7 +118,7 @@ impl Acir {
118118
// then we add it to the `InternalVar` cache
119119
if let Some(mut output) = output {
120120
output.set_id(ins.id);
121-
self.var_cache.update(ins.id, output);
121+
self.var_cache.update(output);
122122
}
123123

124124
Ok(())

‎crates/noirc_evaluator/src/ssa/acir_gen/internal_var.rs

+13-50
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{ssa::acir_gen::expression_to_witness, ssa::node::NodeId, Evaluator};
1+
use crate::ssa::node::NodeId;
22
use acvm::{
33
acir::native_types::{Expression, Witness},
44
FieldElement,
@@ -38,9 +38,16 @@ impl InternalVar {
3838
pub(crate) fn set_id(&mut self, id: NodeId) {
3939
self.id = Some(id)
4040
}
41+
pub(crate) fn get_id(&self) -> Option<NodeId> {
42+
self.id
43+
}
4144
pub(crate) fn cached_witness(&self) -> &Option<Witness> {
4245
&self.cached_witness
4346
}
47+
pub(crate) fn set_witness(&mut self, w: Witness) {
48+
debug_assert!(self.cached_witness.is_none() || self.cached_witness == Some(w));
49+
self.cached_witness = Some(w);
50+
}
4451

4552
pub(crate) fn to_expression(&self) -> Expression {
4653
if let Some(w) = self.cached_witness {
@@ -70,7 +77,7 @@ impl InternalVar {
7077
/// Example: f(x,y) = 10
7178
/// `f` is a constant expression because there are no
7279
/// bi-variate or uni-variate terms, just a constant.
73-
fn is_const_expression(&self) -> bool {
80+
pub(crate) fn is_const_expression(&self) -> bool {
7481
self.expression.is_const()
7582
}
7683

@@ -101,32 +108,6 @@ impl InternalVar {
101108
pub(crate) fn from_constant(constant: FieldElement) -> InternalVar {
102109
InternalVar { expression: Expression::from_field(constant), cached_witness: None, id: None }
103110
}
104-
105-
/// Generates a `Witness` that is equal to the `expression`.
106-
/// - If a `Witness` has previously been generated
107-
/// we return that.
108-
/// - If the Expression represents a constant, we return None.
109-
pub(crate) fn get_or_compute_witness(
110-
&mut self,
111-
evaluator: &mut Evaluator,
112-
create_witness_for_const: bool,
113-
) -> Option<Witness> {
114-
// Check if we've already generated a `Witness` which is equal to
115-
// the stored `Expression`
116-
if let Some(witness) = self.cached_witness {
117-
return Some(witness);
118-
}
119-
120-
// There are cases where we need to convert a constant expression
121-
// into a witness.
122-
if !create_witness_for_const && self.is_const_expression() {
123-
return None;
124-
}
125-
126-
self.cached_witness = Some(expression_to_witness(self.expression.clone(), evaluator));
127-
128-
self.cached_witness
129-
}
130111
}
131112

132113
impl PartialEq for InternalVar {
@@ -184,21 +165,18 @@ impl From<FieldElement> for InternalVar {
184165

185166
#[cfg(test)]
186167
mod tests {
187-
use crate::{ssa::acir_gen::InternalVar, Evaluator};
188-
use acvm::{acir::native_types::Witness, FieldElement};
168+
use crate::ssa::acir_gen::InternalVar;
169+
use acvm::FieldElement;
189170

190171
#[test]
191172
fn internal_var_const_expression() {
192-
let mut evaluator = Evaluator::default();
193-
194173
let expected_constant = FieldElement::from(123456789u128);
195174

196175
// Initialize an InternalVar with a FieldElement
197-
let mut internal_var = InternalVar::from_constant(expected_constant);
176+
let internal_var = InternalVar::from_constant(expected_constant);
198177

199178
// We currently do not create witness when the InternalVar was created using a constant
200-
let witness = internal_var.get_or_compute_witness(&mut evaluator, false);
201-
assert!(witness.is_none());
179+
assert!(internal_var.cached_witness().is_none());
202180

203181
match internal_var.to_const() {
204182
Some(got_constant) => assert_eq!(got_constant, expected_constant),
@@ -207,19 +185,4 @@ mod tests {
207185
}
208186
}
209187
}
210-
#[test]
211-
fn internal_var_from_witness() {
212-
let mut evaluator = Evaluator::default();
213-
214-
let expected_witness = Witness(1234);
215-
// Initialize an InternalVar with a `Witness`
216-
let mut internal_var = InternalVar::from_witness(expected_witness);
217-
218-
// We should get back the same `Witness`
219-
let got_witness = internal_var.get_or_compute_witness(&mut evaluator, false);
220-
match got_witness {
221-
Some(got_witness) => assert_eq!(got_witness, expected_witness),
222-
None => panic!("expected a `Witness` value"),
223-
}
224-
}
225188
}

‎crates/noirc_evaluator/src/ssa/acir_gen/internal_var_cache.rs

+207-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@ use crate::{
66
},
77
Evaluator,
88
};
9-
use acvm::FieldElement;
9+
use acvm::{
10+
acir::native_types::{Expression, Witness},
11+
FieldElement,
12+
};
1013
use std::collections::HashMap;
1114

15+
use super::expression_to_witness;
16+
1217
#[derive(Default)]
1318
pub(crate) struct InternalVarCache {
19+
/// Map node id to an InternalVar
1420
inner: HashMap<NodeId, InternalVar>,
21+
/// Map field values to an InternalVar, which lazily gets a witness when required
22+
/// This avoids us to re-create another witness for the same value
23+
/// A witness for a field value should be avoided but can be needed as an opcode input, for example the logic opcode.
24+
constants: HashMap<FieldElement, InternalVar>,
1525
}
1626

1727
impl InternalVarCache {
@@ -31,8 +41,26 @@ impl InternalVarCache {
3141

3242
let mut var = match ctx.try_get_node(id)? {
3343
NodeObject::Const(c) => {
44+
// use the InternalVar from constants if exists
3445
let field_value = FieldElement::from_be_bytes_reduce(&c.value.to_bytes_be());
35-
InternalVar::from_constant(field_value)
46+
let mut result = InternalVar::from_constant(field_value);
47+
if let Some(c_var) = self.constants.get(&field_value) {
48+
result = c_var.clone();
49+
}
50+
51+
//use witness from other nodes if exists
52+
let new_vec = Vec::new();
53+
let constant_ids = ctx.constants.get(&field_value).unwrap_or(&new_vec);
54+
let cached_witness =
55+
constant_ids.iter().find_map(|c_id| match self.inner.get(c_id) {
56+
Some(i_var) => *i_var.cached_witness(),
57+
None => None,
58+
});
59+
if let Some(w) = cached_witness {
60+
result.set_witness(w);
61+
}
62+
63+
result
3664
}
3765
NodeObject::Variable(variable) => {
3866
let variable_type = variable.get_type();
@@ -76,10 +104,184 @@ impl InternalVarCache {
76104
.expect("ICE: `NodeId` type cannot be converted into an `InternalVar`")
77105
}
78106

79-
pub(super) fn update(&mut self, id: NodeId, var: InternalVar) {
80-
self.inner.insert(id, var);
81-
}
82107
pub(super) fn get(&mut self, id: &NodeId) -> Option<&InternalVar> {
83108
self.inner.get(id)
84109
}
110+
111+
// Transform a field element into a witness
112+
// It implements a 'get or create' pattern to ensure only one witness is created per element
113+
fn const_to_witness(
114+
&mut self,
115+
value: FieldElement,
116+
evaluator: &mut Evaluator,
117+
ctx: &SsaContext,
118+
) -> Witness {
119+
if let Some(ids) = ctx.constants.get(&value) {
120+
//we have a constant node object for the value
121+
if let Some(id) = ids.first() {
122+
let var = self.get_or_compute_internal_var_unwrap(*id, evaluator, ctx);
123+
if let Some(w) = var.cached_witness() {
124+
return *w;
125+
}
126+
}
127+
// We generate a witness and assigns it
128+
let w = evaluator.create_intermediate_variable(Expression::from(value));
129+
for &id in ids {
130+
let mut cached_var = self.get_or_compute_internal_var_unwrap(id, evaluator, ctx);
131+
assert!(cached_var.cached_witness().is_none());
132+
cached_var.set_witness(w);
133+
self.update(cached_var);
134+
}
135+
w
136+
} else {
137+
//if not, we use the constants map
138+
let var =
139+
self.constants.entry(value).or_insert_with(|| InternalVar::from_constant(value));
140+
Self::const_to_witness_helper(var, evaluator)
141+
}
142+
}
143+
144+
// Helper function which generates a witness for an InternalVar
145+
// Do not call outside const_to_witness()
146+
fn const_to_witness_helper(var: &mut InternalVar, evaluator: &mut Evaluator) -> Witness {
147+
let w = Self::internal_get_or_compute_witness(var, evaluator);
148+
if w.is_none() {
149+
let witness = expression_to_witness(var.to_expression(), evaluator);
150+
var.set_witness(witness);
151+
}
152+
var.cached_witness().expect("Infallible, the witness is computed before")
153+
}
154+
155+
/// Get or compute a witness for an internal var
156+
/// WARNING: It generates a witness even if the internal var is constant, so it should be used only if the var is an input
157+
/// to some ACIR opcode which requires a witness
158+
pub(crate) fn get_or_compute_witness_unwrap(
159+
&mut self,
160+
mut var: InternalVar,
161+
evaluator: &mut Evaluator,
162+
ctx: &SsaContext,
163+
) -> Witness {
164+
if let Some(v) = var.to_const() {
165+
self.const_to_witness(v, evaluator, ctx)
166+
} else {
167+
let w = Self::internal_get_or_compute_witness(&mut var, evaluator)
168+
.expect("infallible non const expression");
169+
var.set_witness(w);
170+
self.update(var);
171+
w
172+
}
173+
}
174+
175+
/// Get or compute a witness equating the internal var
176+
/// It returns None when the variable is a constant instead of creating a witness
177+
/// because we should not need a witness in that case
178+
/// If you really need one, you can use get_or_compute_witness_unwrap()
179+
pub(crate) fn get_or_compute_witness(
180+
&mut self,
181+
mut var: InternalVar,
182+
evaluator: &mut Evaluator,
183+
) -> Option<Witness> {
184+
let w = Self::internal_get_or_compute_witness(&mut var, evaluator);
185+
if w.is_some() {
186+
assert!(var.cached_witness().is_some());
187+
} else {
188+
return None;
189+
};
190+
self.update(var);
191+
192+
w
193+
}
194+
195+
/// Generates a `Witness` that is equal to the `expression`.
196+
/// - If a `Witness` has previously been generated, we return it.
197+
/// - If the Expression represents a constant, we return None.
198+
fn internal_get_or_compute_witness(
199+
var: &mut InternalVar,
200+
evaluator: &mut Evaluator,
201+
) -> Option<Witness> {
202+
// Check if we've already generated a `Witness` which is equal to
203+
// the stored `Expression`
204+
if let Some(witness) = var.cached_witness() {
205+
return Some(*witness);
206+
}
207+
208+
// We do not generate a witness for constant values. It can only be done at the InternalVarCache level.
209+
if var.is_const_expression() {
210+
return None;
211+
}
212+
213+
var.set_witness(expression_to_witness(var.expression().clone(), evaluator));
214+
215+
*var.cached_witness()
216+
}
217+
218+
pub(super) fn update(&mut self, var: InternalVar) {
219+
if let Some(id) = var.get_id() {
220+
self.inner.insert(id, var);
221+
} else if let Some(value) = var.to_const() {
222+
self.constants.insert(value, var);
223+
}
224+
}
225+
}
226+
227+
#[cfg(test)]
228+
mod test {
229+
230+
use acvm::{acir::native_types::Witness, FieldElement};
231+
232+
use crate::{
233+
ssa::{
234+
acir_gen::internal_var_cache::{InternalVar, InternalVarCache},
235+
context::SsaContext,
236+
},
237+
Evaluator,
238+
};
239+
240+
// Check that only one witness is generated for const values
241+
#[test]
242+
fn test_const_witness() {
243+
let mut eval = Evaluator::default();
244+
let ctx = SsaContext::default();
245+
let mut var_cache = InternalVarCache::default();
246+
let v1 = var_cache.get_or_compute_internal_var_unwrap(ctx.one(), &mut eval, &ctx);
247+
let v2 = var_cache.get_or_compute_internal_var_unwrap(ctx.zero(), &mut eval, &ctx);
248+
let w1 = var_cache.get_or_compute_witness_unwrap(v1, &mut eval, &ctx);
249+
let w2 = var_cache.get_or_compute_witness_unwrap(v2, &mut eval, &ctx);
250+
let w11 = var_cache.get_or_compute_witness_unwrap(
251+
InternalVar::from_constant(FieldElement::one()),
252+
&mut eval,
253+
&ctx,
254+
);
255+
let w21 = var_cache.get_or_compute_witness_unwrap(
256+
InternalVar::from_constant(FieldElement::zero()),
257+
&mut eval,
258+
&ctx,
259+
);
260+
let two = FieldElement::one() + FieldElement::one();
261+
assert!(var_cache.constants.is_empty());
262+
assert_eq!(w1, w11);
263+
assert_eq!(w2, w21);
264+
var_cache.const_to_witness(two, &mut eval, &ctx);
265+
assert!(var_cache.constants.len() == 1);
266+
var_cache.const_to_witness(two, &mut eval, &ctx);
267+
assert!(var_cache.constants.len() == 1);
268+
var_cache.const_to_witness(FieldElement::one(), &mut eval, &ctx);
269+
assert!(var_cache.constants.len() == 1);
270+
}
271+
272+
#[test]
273+
fn internal_var_from_witness() {
274+
let mut evaluator = Evaluator::default();
275+
let expected_witness = Witness(1234);
276+
// Initialize an InternalVar with a `Witness`
277+
let mut internal_var = InternalVar::from_witness(expected_witness);
278+
279+
// We should get back the same `Witness`
280+
let got_witness =
281+
InternalVarCache::internal_get_or_compute_witness(&mut internal_var, &mut evaluator);
282+
match got_witness {
283+
Some(got_witness) => assert_eq!(got_witness, expected_witness),
284+
None => panic!("expected a `Witness` value"),
285+
}
286+
}
85287
}

‎crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs

+39-41
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::{
22
ssa::{
33
acir_gen::{
4-
acir_mem::AcirMem, constraints, internal_var_cache::InternalVarCache, operations,
5-
InternalVar,
4+
constraints, internal_var_cache::InternalVarCache, operations, Acir, InternalVar,
65
},
76
context::SsaContext,
87
node::{self, BinaryOp, Node, ObjectType},
@@ -29,8 +28,7 @@ fn get_predicate(
2928
pub(crate) fn evaluate(
3029
binary: &node::Binary,
3130
res_type: ObjectType,
32-
var_cache: &mut InternalVarCache,
33-
memory_map: &mut AcirMem,
31+
acir_gen: &mut Acir,
3432
evaluator: &mut Evaluator,
3533
ctx: &SsaContext,
3634
) -> Option<InternalVar> {
@@ -43,17 +41,17 @@ pub(crate) fn evaluate(
4341

4442
let binary_output = match &binary.operator {
4543
BinaryOp::Add | BinaryOp::SafeAdd => {
46-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
47-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
44+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
45+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
4846
InternalVar::from(constraints::add(
4947
l_c.expression(),
5048
FieldElement::one(),
5149
r_c.expression(),
5250
))
5351
},
5452
BinaryOp::Sub { max_rhs_value } | BinaryOp::SafeSub { max_rhs_value } => {
55-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
56-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
53+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
54+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
5755
if res_type == ObjectType::NativeField {
5856
InternalVar::from(constraints::subtract(
5957
l_c.expression(),
@@ -92,18 +90,18 @@ pub(crate) fn evaluate(
9290
}
9391
}
9492
BinaryOp::Mul | BinaryOp::SafeMul => {
95-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
96-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
93+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
94+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
9795
InternalVar::from(constraints::mul_with_witness(
9896
evaluator,
9997
l_c.expression(),
10098
r_c.expression(),
10199
))
102100
},
103101
BinaryOp::Udiv(_) => {
104-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
105-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
106-
let predicate = get_predicate(var_cache,binary, evaluator, ctx);
102+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
103+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
104+
let predicate = get_predicate(&mut acir_gen.var_cache,binary, evaluator, ctx);
107105
let (q_wit, _) = constraints::evaluate_udiv(
108106
l_c.expression(),
109107
r_c.expression(),
@@ -114,16 +112,16 @@ pub(crate) fn evaluate(
114112
InternalVar::from(q_wit)
115113
}
116114
BinaryOp::Sdiv(_) => {
117-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
118-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
115+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
116+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
119117
InternalVar::from(
120118
constraints::evaluate_sdiv(l_c.expression(), r_c.expression(), evaluator).0,
121119
)
122120
},
123121
BinaryOp::Urem(_) => {
124-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
125-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
126-
let predicate = get_predicate(var_cache,binary, evaluator, ctx);
122+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
123+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
124+
let predicate = get_predicate(&mut acir_gen.var_cache,binary, evaluator, ctx);
127125
let (_, r_wit) = constraints::evaluate_udiv(
128126
l_c.expression(),
129127
r_c.expression(),
@@ -134,16 +132,16 @@ pub(crate) fn evaluate(
134132
InternalVar::from(r_wit)
135133
}
136134
BinaryOp::Srem(_) => {
137-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
138-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
135+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
136+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
139137
InternalVar::from(
140138
// TODO: we should use variable naming here instead of .1
141139
constraints::evaluate_sdiv(l_c.expression(), r_c.expression(), evaluator).1,
142140
)},
143141
BinaryOp::Div(_) => {
144-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
145-
let mut r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
146-
let predicate = get_predicate(var_cache,binary, evaluator, ctx).expression().clone();
142+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
143+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
144+
let predicate = get_predicate(&mut acir_gen.var_cache,binary, evaluator, ctx).expression().clone();
147145
if let Some(r_value) = r_c.to_const() {
148146
if r_value.is_zero() {
149147
panic!("Panic - division by zero");
@@ -152,7 +150,7 @@ pub(crate) fn evaluate(
152150
}
153151
} else {
154152
//TODO avoid creating witnesses here.
155-
let x_witness = r_c.get_or_compute_witness(evaluator, false).expect("unexpected constant expression");
153+
let x_witness = acir_gen.var_cache.get_or_compute_witness(r_c, evaluator).expect("unexpected constant expression");
156154
let inverse = Expression::from(&constraints::evaluate_inverse(
157155
x_witness, &predicate, evaluator,
158156
));
@@ -164,20 +162,20 @@ pub(crate) fn evaluate(
164162
}
165163
}
166164
BinaryOp::Eq => {
167-
let l_c = var_cache.get_or_compute_internal_var(binary.lhs, evaluator, ctx);
168-
let r_c = var_cache.get_or_compute_internal_var(binary.rhs, evaluator, ctx);
165+
let l_c = acir_gen.var_cache.get_or_compute_internal_var(binary.lhs, evaluator, ctx);
166+
let r_c = acir_gen.var_cache.get_or_compute_internal_var(binary.rhs, evaluator, ctx);
169167
InternalVar::from(
170-
operations::cmp::evaluate_eq(memory_map,binary.lhs, binary.rhs, l_c, r_c, ctx, evaluator),
168+
operations::cmp::evaluate_eq(acir_gen,binary.lhs, binary.rhs, l_c, r_c, ctx, evaluator),
171169
)},
172170
BinaryOp::Ne => {
173-
let l_c = var_cache.get_or_compute_internal_var(binary.lhs, evaluator, ctx);
174-
let r_c = var_cache.get_or_compute_internal_var(binary.rhs, evaluator, ctx);
171+
let l_c = acir_gen.var_cache.get_or_compute_internal_var(binary.lhs, evaluator, ctx);
172+
let r_c = acir_gen.var_cache.get_or_compute_internal_var(binary.rhs, evaluator, ctx);
175173
InternalVar::from(
176-
operations::cmp::evaluate_neq(memory_map,binary.lhs, binary.rhs, l_c, r_c, ctx, evaluator),
174+
operations::cmp::evaluate_neq(acir_gen,binary.lhs, binary.rhs, l_c, r_c, ctx, evaluator),
177175
)},
178176
BinaryOp::Ult => {
179-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
180-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
177+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
178+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
181179
let size = ctx[binary.lhs].get_type().bits();
182180
constraints::evaluate_cmp(
183181
l_c.expression(),
@@ -189,8 +187,8 @@ pub(crate) fn evaluate(
189187
.into()
190188
}
191189
BinaryOp::Ule => {
192-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
193-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
190+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
191+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
194192
let size = ctx[binary.lhs].get_type().bits();
195193
let e = constraints::evaluate_cmp(
196194
r_c.expression(),
@@ -202,15 +200,15 @@ pub(crate) fn evaluate(
202200
constraints::subtract(&Expression::one(), FieldElement::one(), &e).into()
203201
}
204202
BinaryOp::Slt => {
205-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
206-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
203+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
204+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
207205
let s = ctx[binary.lhs].get_type().bits();
208206
constraints::evaluate_cmp(l_c.expression(), r_c.expression(), s, true, evaluator)
209207
.into()
210208
}
211209
BinaryOp::Sle => {
212-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
213-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
210+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
211+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
214212
let s = ctx[binary.lhs].get_type().bits();
215213
let e = constraints::evaluate_cmp(
216214
r_c.expression(),
@@ -230,13 +228,13 @@ pub(crate) fn evaluate(
230228
)
231229
}
232230
BinaryOp::And | BinaryOp::Or | BinaryOp::Xor => {
233-
let l_c = var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
234-
let r_c = var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
231+
let l_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.lhs, evaluator, ctx);
232+
let r_c = acir_gen.var_cache.get_or_compute_internal_var_unwrap(binary.rhs, evaluator, ctx);
235233
let bit_size = res_type.bits();
236234
let opcode = binary.operator.clone();
237235
let bitwise_result = match operations::bitwise::simplify_bitwise(&l_c, &r_c, bit_size, &opcode) {
238236
Some(simplified_internal_var) => simplified_internal_var.expression().clone(),
239-
None => operations::bitwise::evaluate_bitwise(l_c, r_c, bit_size, evaluator, opcode),
237+
None => operations::bitwise::evaluate_bitwise(l_c, r_c, bit_size, evaluator, &mut acir_gen.var_cache, ctx, opcode),
240238
};
241239
InternalVar::from(bitwise_result)
242240
}

‎crates/noirc_evaluator/src/ssa/acir_gen/operations/bitwise.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use acvm::{
88

99
use crate::{
1010
ssa::{
11-
acir_gen::{constraints, InternalVar},
11+
acir_gen::{constraints, internal_var_cache::InternalVarCache, InternalVar},
12+
context::SsaContext,
1213
node::BinaryOp,
1314
},
1415
Evaluator,
@@ -76,10 +77,12 @@ pub(super) fn simplify_bitwise(
7677
}
7778
// Precondition: `lhs` and `rhs` do not represent constant expressions
7879
pub(super) fn evaluate_bitwise(
79-
mut lhs: InternalVar,
80-
mut rhs: InternalVar,
80+
lhs: InternalVar,
81+
rhs: InternalVar,
8182
bit_size: u32,
8283
evaluator: &mut Evaluator,
84+
var_cache: &mut InternalVarCache,
85+
ctx: &SsaContext,
8386
opcode: BinaryOp,
8487
) -> Expression {
8588
// Check precondition
@@ -111,13 +114,8 @@ pub(super) fn evaluate_bitwise(
111114
// If the gate is implemented, it is expected to be better than going through bit decomposition, even if one of the operand is a constant
112115
// If the gate is not implemented, we rely on the ACIR simplification to remove these witnesses
113116
//
114-
115-
let mut a_witness = lhs
116-
.get_or_compute_witness(evaluator, true)
117-
.expect("infallible: `None` can only be returned when we disallow constant Expressions.");
118-
let mut b_witness = rhs
119-
.get_or_compute_witness(evaluator, true)
120-
.expect("infallible: `None` can only be returned when we disallow constant Expressions.");
117+
let mut a_witness = var_cache.get_or_compute_witness_unwrap(lhs, evaluator, ctx);
118+
let mut b_witness = var_cache.get_or_compute_witness_unwrap(rhs, evaluator, ctx);
121119

122120
let result = evaluator.add_witness_to_cs();
123121
let bit_size = if bit_size % 2 == 1 { bit_size + 1 } else { bit_size };
@@ -130,12 +128,12 @@ pub(super) fn evaluate_bitwise(
130128
a_witness = evaluator.create_intermediate_variable(constraints::subtract(
131129
&Expression::from_field(max),
132130
FieldElement::one(),
133-
lhs.expression(),
131+
&Expression::from(a_witness),
134132
));
135133
b_witness = evaluator.create_intermediate_variable(constraints::subtract(
136134
&Expression::from_field(max),
137135
FieldElement::one(),
138-
rhs.expression(),
136+
&Expression::from(b_witness),
139137
));
140138
// We do not have an OR gate yet, so we use the AND gate
141139
acvm::acir::BlackBoxFunc::AND

‎crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
ssa::{
3-
acir_gen::{acir_mem::AcirMem, constraints, InternalVar},
3+
acir_gen::{acir_mem::AcirMem, constraints, Acir, InternalVar},
44
context::SsaContext,
55
mem::{MemArray, Memory},
66
node::NodeId,
@@ -26,7 +26,7 @@ use iter_extended::vecmap;
2626
// so in reality, the NEQ instruction will be done on the fields
2727
// of the struct
2828
pub(super) fn evaluate_neq(
29-
acir_mem: &mut AcirMem,
29+
acir_gen: &mut Acir,
3030
lhs: NodeId,
3131
rhs: NodeId,
3232
l_c: Option<InternalVar>,
@@ -60,20 +60,22 @@ pub(super) fn evaluate_neq(
6060
)
6161
}
6262

63-
let mut x = InternalVar::from(array_eq(acir_mem, array_a, array_b, evaluator));
63+
let x = InternalVar::from(array_eq(&mut acir_gen.memory, array_a, array_b, evaluator));
6464
// TODO we need a witness because of the directive, but we should use an expression
6565
// TODO if we change the Invert directive to take an `Expression`, then we
6666
// TODO can get rid of this extra gate.
67-
let x_witness =
68-
x.get_or_compute_witness(evaluator, false).expect("unexpected constant expression");
67+
let x_witness = acir_gen
68+
.var_cache
69+
.get_or_compute_witness(x, evaluator)
70+
.expect("unexpected constant expression");
6971

7072
return Expression::from(&constraints::evaluate_zero_equality(x_witness, evaluator));
7173
}
7274

7375
// Arriving here means that `lhs` and `rhs` are not Arrays
7476
let l_c = l_c.expect("ICE: unexpected array pointer");
7577
let r_c = r_c.expect("ICE: unexpected array pointer");
76-
let mut x = InternalVar::from(constraints::subtract(
78+
let x = InternalVar::from(constraints::subtract(
7779
l_c.expression(),
7880
FieldElement::one(),
7981
r_c.expression(),
@@ -89,22 +91,24 @@ pub(super) fn evaluate_neq(
8991
}
9092
} else {
9193
//todo we need a witness because of the directive, but we should use an expression
92-
let x_witness =
93-
x.get_or_compute_witness(evaluator, false).expect("unexpected constant expression");
94+
let x_witness = acir_gen
95+
.var_cache
96+
.get_or_compute_witness(x, evaluator)
97+
.expect("unexpected constant expression");
9498
Expression::from(&constraints::evaluate_zero_equality(x_witness, evaluator))
9599
}
96100
}
97101

98102
pub(super) fn evaluate_eq(
99-
memory_map: &mut AcirMem,
103+
acir_gen: &mut Acir,
100104
lhs: NodeId,
101105
rhs: NodeId,
102106
l_c: Option<InternalVar>,
103107
r_c: Option<InternalVar>,
104108
ctx: &SsaContext,
105109
evaluator: &mut Evaluator,
106110
) -> Expression {
107-
let neq = evaluate_neq(memory_map, lhs, rhs, l_c, r_c, ctx, evaluator);
111+
let neq = evaluate_neq(acir_gen, lhs, rhs, l_c, r_c, ctx, evaluator);
108112
constraints::subtract(&Expression::one(), FieldElement::one(), &neq)
109113
}
110114

‎crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs

+40-41
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
acir_gen::{
44
constraints::{bound_constraint_with_offset, to_radix_base},
55
operations::sort::evaluate_permutation,
6-
AcirMem, InternalVar, InternalVarCache,
6+
Acir, AcirMem, InternalVar, InternalVarCache,
77
},
88
builtin,
99
context::SsaContext,
@@ -33,8 +33,7 @@ pub(crate) fn evaluate(
3333
args: &[NodeId],
3434
instruction: &Instruction,
3535
opcode: builtin::Opcode,
36-
var_cache: &mut InternalVarCache,
37-
memory_map: &mut AcirMem,
36+
acir_gen: &mut Acir,
3837
ctx: &SsaContext,
3938
evaluator: &mut Evaluator,
4039
) -> Option<InternalVar> {
@@ -48,28 +47,30 @@ pub(crate) fn evaluate(
4847
Opcode::ToBits(endianess) => {
4948
// TODO: document where `0` and `1` are coming from, for args[0], args[1]
5049
let bit_size = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32;
51-
let l_c = var_cache.get_or_compute_internal_var_unwrap(args[0], evaluator, ctx);
50+
let l_c =
51+
acir_gen.var_cache.get_or_compute_internal_var_unwrap(args[0], evaluator, ctx);
5252
outputs = to_radix_base(l_c.expression(), 2, bit_size, endianess, evaluator);
5353
if let ObjectType::Pointer(a) = res_type {
54-
memory_map.map_array(a, &outputs, ctx);
54+
acir_gen.memory.map_array(a, &outputs, ctx);
5555
}
5656
}
5757
Opcode::ToRadix(endianess) => {
5858
// TODO: document where `0`, `1` and `2` are coming from, for args[0],args[1], args[2]
5959
let radix = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32;
6060
let limb_size = ctx.get_as_constant(args[2]).unwrap().to_u128() as u32;
61-
let l_c = var_cache.get_or_compute_internal_var_unwrap(args[0], evaluator, ctx);
61+
let l_c =
62+
acir_gen.var_cache.get_or_compute_internal_var_unwrap(args[0], evaluator, ctx);
6263
outputs = to_radix_base(l_c.expression(), radix, limb_size, endianess, evaluator);
6364
if let ObjectType::Pointer(a) = res_type {
64-
memory_map.map_array(a, &outputs, ctx);
65+
acir_gen.memory.map_array(a, &outputs, ctx);
6566
}
6667
}
6768
Opcode::Println(print_info) => {
6869
outputs = Vec::new(); // print statements do not output anything
6970
if print_info.show_output {
7071
evaluate_println(
71-
var_cache,
72-
memory_map,
72+
&mut acir_gen.var_cache,
73+
&mut acir_gen.memory,
7374
print_info.is_string_output,
7475
args,
7576
ctx,
@@ -78,9 +79,10 @@ pub(crate) fn evaluate(
7879
}
7980
}
8081
Opcode::LowLevel(op) => {
81-
let inputs = prepare_inputs(var_cache, memory_map, args, ctx, evaluator);
82+
let inputs = prepare_inputs(acir_gen, args, ctx, evaluator);
8283
let output_count = op.definition().output_size.0 as u32;
83-
outputs = prepare_outputs(memory_map, instruction_id, output_count, ctx, evaluator);
84+
outputs =
85+
prepare_outputs(&mut acir_gen.memory, instruction_id, output_count, ctx, evaluator);
8486

8587
let func_call = BlackBoxFuncCall {
8688
name: op,
@@ -96,10 +98,15 @@ pub(crate) fn evaluate(
9698
let num_bits = array.element_type.bits();
9799
for i in 0..array.len {
98100
in_expr.push(
99-
memory_map.load_array_element_constant_index(array, i).unwrap().to_expression(),
101+
acir_gen
102+
.memory
103+
.load_array_element_constant_index(array, i)
104+
.unwrap()
105+
.to_expression(),
100106
);
101107
}
102-
outputs = prepare_outputs(memory_map, instruction_id, array.len, ctx, evaluator);
108+
outputs =
109+
prepare_outputs(&mut acir_gen.memory, instruction_id, array.len, ctx, evaluator);
103110
let out_expr: Vec<Expression> = outputs.iter().map(|w| w.into()).collect();
104111
for i in 0..(out_expr.len() - 1) {
105112
bound_constraint_with_offset(
@@ -119,7 +126,7 @@ pub(crate) fn evaluate(
119126
sort_by: vec![0],
120127
}));
121128
if let node::ObjectType::Pointer(a) = res_type {
122-
memory_map.map_array(a, &outputs, ctx);
129+
acir_gen.memory.map_array(a, &outputs, ctx);
123130
} else {
124131
unreachable!();
125132
}
@@ -134,24 +141,22 @@ pub(crate) fn evaluate(
134141

135142
// Transform the arguments of intrinsic functions into witnesses
136143
fn prepare_inputs(
137-
var_cache: &mut InternalVarCache,
138-
memory_map: &mut AcirMem,
144+
acir_gen: &mut Acir,
139145
arguments: &[NodeId],
140146
cfg: &SsaContext,
141147
evaluator: &mut Evaluator,
142148
) -> Vec<FunctionInput> {
143149
let mut inputs: Vec<FunctionInput> = Vec::new();
144150

145151
for argument in arguments {
146-
inputs.extend(resolve_node_id(argument, var_cache, memory_map, cfg, evaluator))
152+
inputs.extend(resolve_node_id(argument, acir_gen, cfg, evaluator))
147153
}
148154
inputs
149155
}
150156

151157
fn resolve_node_id(
152158
node_id: &NodeId,
153-
var_cache: &mut InternalVarCache,
154-
memory_map: &mut AcirMem,
159+
acir_gen: &mut Acir,
155160
cfg: &SsaContext,
156161
evaluator: &mut Evaluator,
157162
) -> Vec<FunctionInput> {
@@ -162,7 +167,7 @@ fn resolve_node_id(
162167
match node_obj_type {
163168
// If the `Variable` represents a Pointer
164169
// Then we know that it is an `Array`
165-
node::ObjectType::Pointer(a) => resolve_array(a, memory_map, cfg, evaluator),
170+
node::ObjectType::Pointer(a) => resolve_array(a, acir_gen, cfg, evaluator),
166171
// If it is not a pointer, we attempt to fetch the witness associated with it
167172
_ => match v.witness {
168173
Some(w) => {
@@ -176,24 +181,19 @@ fn resolve_node_id(
176181
// Upon the case that the `NodeObject` is not a `Variable`,
177182
// we attempt to fetch an associated `InternalVar`.
178183
// Otherwise, this is a internal compiler error.
179-
let internal_var = var_cache.get(node_id);
180-
match internal_var {
181-
Some(var) => {
182-
let witness = var
183-
.clone()
184-
.get_or_compute_witness(evaluator, false)
185-
.expect("unexpected constant expression");
186-
vec![FunctionInput { witness, num_bits: node_object.size_in_bits() }]
187-
}
188-
None => unreachable!("invalid input: {:?}", node_object),
189-
}
184+
let internal_var = acir_gen.var_cache.get(node_id).expect("invalid input").clone();
185+
let witness = acir_gen
186+
.var_cache
187+
.get_or_compute_witness(internal_var, evaluator)
188+
.expect("unexpected constant expression");
189+
vec![FunctionInput { witness, num_bits: node_object.size_in_bits() }]
190190
}
191191
}
192192
}
193193

194194
fn resolve_array(
195195
array_id: ArrayId,
196-
acir_mem: &mut AcirMem,
196+
acir_gen: &mut Acir,
197197
cfg: &SsaContext,
198198
evaluator: &mut Evaluator,
199199
) -> Vec<FunctionInput> {
@@ -202,16 +202,15 @@ fn resolve_array(
202202
let array = &cfg.mem[array_id];
203203
let num_bits = array.element_type.bits();
204204
for i in 0..array.len {
205-
let mut arr_element = acir_mem
205+
let mut arr_element = acir_gen
206+
.memory
206207
.load_array_element_constant_index(array, i)
207208
.expect("array index out of bounds");
208-
209-
let witness = arr_element.get_or_compute_witness(evaluator, true).expect(
210-
"infallible: `None` can only be returned when we disallow constant Expressions.",
211-
);
209+
let witness =
210+
acir_gen.var_cache.get_or_compute_witness_unwrap(arr_element.clone(), evaluator, cfg);
212211
let func_input = FunctionInput { witness, num_bits };
213-
214-
acir_mem.insert(array.id, i, arr_element);
212+
arr_element.set_witness(witness);
213+
acir_gen.memory.insert(array.id, i, arr_element);
215214

216215
inputs.push(func_input)
217216
}
@@ -287,7 +286,7 @@ fn evaluate_println(
287286
log_string = format_field_string(field);
288287
}
289288
None => {
290-
let mut var = var_cache
289+
let var = var_cache
291290
.get(&node_id)
292291
.unwrap_or_else(|| {
293292
panic!(
@@ -298,7 +297,7 @@ fn evaluate_println(
298297
.clone();
299298
if let Some(field) = var.to_const() {
300299
log_string = format_field_string(field);
301-
} else if let Some(w) = var.get_or_compute_witness(evaluator, false) {
300+
} else if let Some(w) = var_cache.get_or_compute_witness(var, evaluator) {
302301
// We check whether there has already been a cached witness for this node. If not, we generate a new witness and include it in the logs
303302
// TODO we need a witness because of the directive, but we should use an expression
304303
log_witnesses.push(w);

‎crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@ pub(crate) fn evaluate(
4141
};
4242

4343
let mut witnesses: Vec<Witness> = Vec::new();
44-
for mut object in objects {
45-
let witness = object.get_or_compute_witness(evaluator, true).expect(
46-
"infallible: `None` can only be returned when we disallow constant Expressions.",
47-
);
44+
for object in objects {
45+
let witness = var_cache.get_or_compute_witness_unwrap(object, evaluator, ctx);
4846
// Before pushing to the public inputs, we need to check that
4947
// it was not a private ABI input
5048
if evaluator.is_private_abi_input(witness) {

‎crates/noirc_evaluator/src/ssa/context.rs

+19-14
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use iter_extended::vecmap;
1717
use noirc_errors::Location;
1818
use noirc_frontend::monomorphization::ast::{Definition, Expression, FuncId, Literal, Type};
1919
use num_bigint::BigUint;
20-
use num_traits::{One, Zero};
2120
use std::collections::{HashMap, HashSet};
2221

2322
// This is a 'master' class for generating the SSA IR from the AST
@@ -35,6 +34,7 @@ pub(crate) struct SsaContext {
3534

3635
pub(crate) functions: HashMap<FuncId, function::SsaFunction>,
3736
pub(crate) opcode_ids: HashMap<builtin::Opcode, NodeId>,
37+
pub(crate) constants: HashMap<FieldElement, Vec<NodeId>>,
3838

3939
//Adjacency Matrix of the call graph; list of rows where each row indicates the functions called by the function whose FuncIndex is the row number
4040
pub(crate) call_graph: Vec<Vec<u8>>,
@@ -62,6 +62,7 @@ impl Default for SsaContext {
6262
dummy_store: HashMap::new(),
6363
dummy_load: HashMap::new(),
6464
locations: HashMap::new(),
65+
constants: HashMap::new(),
6566
};
6667
block::create_first_block(&mut pc);
6768
pc.one_with_type(node::ObjectType::Boolean);
@@ -72,11 +73,11 @@ impl Default for SsaContext {
7273

7374
impl SsaContext {
7475
pub(crate) fn zero(&self) -> NodeId {
75-
self.find_const_with_type(&BigUint::zero(), node::ObjectType::Boolean).unwrap()
76+
self.find_const_with_type(&FieldElement::zero(), node::ObjectType::Boolean).unwrap()
7677
}
7778

7879
pub(crate) fn one(&self) -> NodeId {
79-
self.find_const_with_type(&BigUint::one(), node::ObjectType::Boolean).unwrap()
80+
self.find_const_with_type(&FieldElement::one(), node::ObjectType::Boolean).unwrap()
8081
}
8182

8283
pub(crate) fn zero_with_type(&mut self, obj_type: ObjectType) -> NodeId {
@@ -92,7 +93,7 @@ impl SsaContext {
9293
return false;
9394
}
9495
let typ = self.object_type(id);
95-
if let Some(one) = self.find_const_with_type(&BigUint::one(), typ) {
96+
if let Some(one) = self.find_const_with_type(&FieldElement::one(), typ) {
9697
id == one
9798
} else {
9899
false
@@ -104,7 +105,7 @@ impl SsaContext {
104105
return false;
105106
}
106107
let typ = self.object_type(id);
107-
if let Some(zero) = self.find_const_with_type(&BigUint::zero(), typ) {
108+
if let Some(zero) = self.find_const_with_type(&FieldElement::zero(), typ) {
108109
id == zero
109110
} else {
110111
false
@@ -571,14 +572,14 @@ impl SsaContext {
571572

572573
pub(crate) fn find_const_with_type(
573574
&self,
574-
value: &BigUint,
575+
value: &FieldElement,
575576
e_type: node::ObjectType,
576577
) -> Option<NodeId> {
577-
//TODO We should map constant values to id
578-
for (idx, o) in &self.nodes {
579-
if let node::NodeObject::Const(c) = o {
580-
if c.value == *value && c.get_type() == e_type {
581-
return Some(NodeId(idx));
578+
// we look for the node in the constants map
579+
if let Some(ids) = self.constants.get(value) {
580+
for &id in ids {
581+
if self[id].get_type() == e_type {
582+
return Some(id);
582583
}
583584
}
584585
}
@@ -589,16 +590,20 @@ impl SsaContext {
589590
// If such object does not exist, we create one
590591
pub(crate) fn get_or_create_const(&mut self, x: FieldElement, t: node::ObjectType) -> NodeId {
591592
let value = BigUint::from_bytes_be(&x.to_be_bytes());
592-
if let Some(prev_const) = self.find_const_with_type(&value, t) {
593+
if let Some(prev_const) = self.find_const_with_type(&x, t) {
593594
return prev_const;
594595
}
595596

596-
self.add_const(node::Constant {
597+
let id = self.add_const(node::Constant {
597598
id: NodeId::dummy(),
598599
value,
599600
value_str: String::new(),
600601
value_type: t,
601-
})
602+
});
603+
// Adds the id into the constants map
604+
let ids = self.constants.entry(x).or_default();
605+
ids.push(id);
606+
id
602607
}
603608

604609
// Return the type of the operation result, based on the left hand type

0 commit comments

Comments
 (0)
Please sign in to comment.