Skip to content

Commit 4b5e356

Browse files
authored
fix(SSA): disallow using lt with fields (#8585)
1 parent c89efcb commit 4b5e356

File tree

6 files changed

+110
-80
lines changed

6 files changed

+110
-80
lines changed

compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ mod test {
341341
use crate::ssa::ir::function::RuntimeType;
342342
use crate::ssa::ir::instruction::BinaryOp;
343343
use crate::ssa::ir::map::Id;
344-
use crate::ssa::ir::types::Type;
344+
use crate::ssa::ir::types::{NumericType, Type};
345345

346346
#[test]
347347
fn simple_back_propagation() {
@@ -441,11 +441,11 @@ mod test {
441441
#[test]
442442
fn propagation_with_nested_loops() {
443443
// brillig fn main f0 {
444-
// b0(v0: Field, v1: Field):
444+
// b0(v0: u32, v1: u32):
445445
// v3 = allocate
446-
// store Field 0 at v3
447-
// jmp b1(Field 0)
448-
// b1(v4: Field):
446+
// store u32 0 at v3
447+
// jmp b1(u32 0)
448+
// b1(v4: u32):
449449
// v5 = lt v4, v0
450450
// jmpif v5 then: b2, else: b3
451451
// b3():
@@ -454,14 +454,14 @@ mod test {
454454
// b2():
455455
// v6 = mul v4, v4
456456
// jmp b4(v0)
457-
// b4(v7: Field):
457+
// b4(v7: u32):
458458
// v8 = lt v7, v1
459459
// jmpif v8 then: b5, else: b6
460460
// b6():
461-
// v16 = add v4, Field 1
461+
// v16 = add v4, u32 1
462462
// jmp b1(v16)
463463
// b5():
464-
// v10 = eq v7, Field 27
464+
// v10 = eq v7, u32 27
465465
// v11 = not v10
466466
// jmpif v11 then: b7, else: b8
467467
// b7():
@@ -470,7 +470,7 @@ mod test {
470470
// store v13 at v3
471471
// jmp b8()
472472
// b8():
473-
// v15 = add v7, Field 1
473+
// v15 = add v7, u32 1
474474
// jmp b4(v15)
475475
// }
476476

@@ -487,18 +487,18 @@ mod test {
487487
let b7 = builder.insert_block();
488488
let b8 = builder.insert_block();
489489

490-
let v0 = builder.add_parameter(Type::field());
491-
let v1 = builder.add_parameter(Type::field());
490+
let v0 = builder.add_parameter(Type::unsigned(32));
491+
let v1 = builder.add_parameter(Type::unsigned(32));
492492

493-
let v3 = builder.insert_allocate(Type::field());
493+
let v3 = builder.insert_allocate(Type::unsigned(32));
494494

495-
let zero = builder.field_constant(0u128);
495+
let zero = builder.numeric_constant(0u128, NumericType::Unsigned { bit_size: 32 });
496496
builder.insert_store(v3, zero);
497497

498498
builder.terminate_with_jmp(b1, vec![zero]);
499499

500500
builder.switch_to_block(b1);
501-
let v4 = builder.add_block_parameter(b1, Type::field());
501+
let v4 = builder.add_block_parameter(b1, Type::unsigned(32));
502502

503503
let v5 = builder.insert_binary(v4, BinaryOp::Lt, v0);
504504

@@ -512,15 +512,15 @@ mod test {
512512

513513
builder.switch_to_block(b4);
514514

515-
let v7 = builder.add_block_parameter(b4, Type::field());
515+
let v7 = builder.add_block_parameter(b4, Type::unsigned(32));
516516

517517
let v8 = builder.insert_binary(v7, BinaryOp::Lt, v1);
518518

519519
builder.terminate_with_jmpif(v8, b5, b6);
520520

521521
builder.switch_to_block(b5);
522522

523-
let twenty_seven = builder.field_constant(27u128);
523+
let twenty_seven = builder.numeric_constant(27u128, NumericType::Unsigned { bit_size: 32 });
524524
let v10 = builder.insert_binary(v7, BinaryOp::Eq, twenty_seven);
525525

526526
let v11 = builder.insert_not(v10);
@@ -529,7 +529,7 @@ mod test {
529529

530530
builder.switch_to_block(b7);
531531

532-
let v12 = builder.insert_load(v3, Type::field());
532+
let v12 = builder.insert_load(v3, Type::unsigned(32));
533533

534534
let v13 = builder.insert_binary(v12, BinaryOp::Add { unchecked: false }, v6);
535535

@@ -539,7 +539,7 @@ mod test {
539539

540540
builder.switch_to_block(b8);
541541

542-
let one = builder.field_constant(1u128);
542+
let one = builder.numeric_constant(1u128, NumericType::Unsigned { bit_size: 32 });
543543
let v15 = builder.insert_binary(v7, BinaryOp::Add { unchecked: false }, one);
544544

545545
builder.terminate_with_jmp(b4, vec![v15]);
@@ -552,7 +552,7 @@ mod test {
552552

553553
builder.switch_to_block(b3);
554554

555-
let v17 = builder.insert_load(v3, Type::field());
555+
let v17 = builder.insert_load(v3, Type::unsigned(32));
556556

557557
builder.terminate_with_return(vec![v17]);
558558

compiler/noirc_evaluator/src/ssa/ir/dfg.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use super::{
99
basic_block::{BasicBlock, BasicBlockId},
1010
function::{FunctionId, RuntimeType},
1111
instruction::{
12-
Instruction, InstructionId, InstructionResultType, Intrinsic, TerminatorInstruction,
12+
Binary, BinaryOp, Instruction, InstructionId, InstructionResultType, Intrinsic,
13+
TerminatorInstruction,
1314
},
1415
integer::IntegerConstant,
1516
map::DenseMap,
@@ -223,11 +224,23 @@ impl DataFlowGraph {
223224
instruction_data: Instruction,
224225
ctrl_typevars: Option<Vec<Type>>,
225226
) -> InstructionId {
227+
self.validate_instruction(&instruction_data);
228+
226229
let id = self.instructions.insert(instruction_data);
227230
self.make_instruction_results(id, ctrl_typevars);
228231
id
229232
}
230233

234+
fn validate_instruction(&self, instruction: &Instruction) {
235+
if let Instruction::Binary(Binary { lhs, rhs: _, operator: BinaryOp::Lt }) = instruction {
236+
// Assume rhs_type is the same as lhs_type
237+
let lhs_type = self.type_of_value(*lhs);
238+
if matches!(lhs_type, Type::Numeric(NumericType::NativeField)) {
239+
panic!("Cannot use `lt` with field elements");
240+
}
241+
}
242+
}
243+
231244
/// Check if the function runtime would simply ignore this instruction.
232245
pub(crate) fn is_handled_by_runtime(&self, instruction: &Instruction) -> bool {
233246
match self.runtime() {
@@ -901,7 +914,10 @@ impl std::ops::Index<usize> for InsertInstructionResult<'_> {
901914
#[cfg(test)]
902915
mod tests {
903916
use super::DataFlowGraph;
904-
use crate::ssa::ir::{instruction::Instruction, types::Type};
917+
use crate::ssa::{
918+
ir::{instruction::Instruction, types::Type},
919+
ssa_gen::Ssa,
920+
};
905921

906922
#[test]
907923
fn make_instruction() {
@@ -912,4 +928,17 @@ mod tests {
912928
let results = dfg.instruction_results(ins_id);
913929
assert_eq!(results.len(), 1);
914930
}
931+
932+
#[test]
933+
#[should_panic(expected = "Cannot use `lt` with field elements")]
934+
fn disallows_comparing_fields_with_lt() {
935+
let src = "
936+
acir(inline) impure fn main f0 {
937+
b0():
938+
v2 = lt Field 1, Field 2
939+
return
940+
}
941+
";
942+
let _ = Ssa::from_str(src);
943+
}
915944
}

compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ impl BinaryOp {
236236
BinaryOp::Mul { .. } => Some(std::ops::Mul::mul),
237237
BinaryOp::Div => Some(std::ops::Div::div),
238238
BinaryOp::Eq => Some(|x, y| (x == y).into()),
239-
BinaryOp::Lt => Some(|x, y| (x < y).into()),
239+
// "less then" comparison is not supported for Fields
240+
BinaryOp::Lt => None,
240241
// Bitwise operators are unsupported for Fields
241242
BinaryOp::Mod => None,
242243
BinaryOp::And => None,

compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,41 +1511,41 @@ mod test {
15111511
let src = "
15121512
acir(inline) fn main f0 {
15131513
b0():
1514-
v0 = allocate -> &mut Field
1515-
store Field 0 at v0
1516-
v2 = allocate -> &mut Field
1517-
store Field 2 at v2
1518-
v4 = load v2 -> Field
1519-
v5 = lt v4, Field 2
1514+
v0 = allocate -> &mut u32
1515+
store u32 0 at v0
1516+
v2 = allocate -> &mut u32
1517+
store u32 2 at v2
1518+
v4 = load v2 -> u32
1519+
v5 = lt v4, u32 2
15201520
jmpif v5 then: b4, else: b1
15211521
b1():
1522-
v6 = load v2 -> Field
1523-
v8 = lt v6, Field 4
1522+
v6 = load v2 -> u32
1523+
v8 = lt v6, u32 4
15241524
jmpif v8 then: b2, else: b3
15251525
b2():
1526-
v9 = load v0 -> Field
1527-
v10 = load v2 -> Field
1528-
v12 = mul v10, Field 100
1526+
v9 = load v0 -> u32
1527+
v10 = load v2 -> u32
1528+
v12 = mul v10, u32 100
15291529
v13 = add v9, v12
15301530
store v13 at v0
1531-
v14 = load v2 -> Field
1532-
v16 = add v14, Field 1
1531+
v14 = load v2 -> u32
1532+
v16 = add v14, u32 1
15331533
store v16 at v2
15341534
jmp b3()
15351535
b3():
15361536
jmp b5()
15371537
b4():
1538-
v17 = load v0 -> Field
1539-
v18 = load v2 -> Field
1540-
v20 = mul v18, Field 10
1538+
v17 = load v0 -> u32
1539+
v18 = load v2 -> u32
1540+
v20 = mul v18, u32 10
15411541
v21 = add v17, v20
15421542
store v21 at v0
1543-
v22 = load v2 -> Field
1544-
v23 = add v22, Field 1
1543+
v22 = load v2 -> u32
1544+
v23 = add v22, u32 1
15451545
store v23 at v2
15461546
jmp b5()
15471547
b5():
1548-
v24 = load v0 -> Field
1548+
v24 = load v0 -> u32
15491549
return v24
15501550
}";
15511551

@@ -1572,10 +1572,10 @@ mod test {
15721572
assert_ssa_snapshot!(ssa, @r"
15731573
acir(inline) fn main f0 {
15741574
b0():
1575-
v0 = allocate -> &mut Field
1576-
v1 = allocate -> &mut Field
1575+
v0 = allocate -> &mut u32
1576+
v1 = allocate -> &mut u32
15771577
enable_side_effects u1 1
1578-
return Field 200
1578+
return u32 200
15791579
}
15801580
");
15811581
}

compiler/noirc_evaluator/src/ssa/opt/inlining.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -807,19 +807,19 @@ mod test {
807807
let src = "
808808
acir(inline) fn main f0 {
809809
b0():
810-
v2 = call f1(Field 5) -> Field
810+
v2 = call f1(u32 5) -> u32
811811
return v2
812812
}
813813
814814
acir(inline) fn factorial f1 {
815-
b0(v1: Field):
816-
v2 = lt v1, Field 1
815+
b0(v1: u32):
816+
v2 = lt v1, u32 1
817817
jmpif v2 then: b1, else: b2
818818
b1():
819-
return Field 1
819+
return u32 1
820820
b2():
821-
v4 = sub v1, Field 1
822-
v5 = call f1(v4) -> Field
821+
v4 = sub v1, u32 1
822+
v5 = call f1(v4) -> u32
823823
v6 = mul v1, v5
824824
return v6
825825
}
@@ -842,7 +842,7 @@ mod test {
842842
b5():
843843
jmp b6()
844844
b6():
845-
return Field 120
845+
return u32 120
846846
}
847847
");
848848
}

0 commit comments

Comments
 (0)