Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub mod ir;
pub(crate) mod opt;
pub mod parser;
pub mod ssa_gen;
pub(crate) mod validation;

#[derive(Debug, Clone)]
pub enum SsaLogging {
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_evaluator/src/ssa/function_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use super::{
},
opt::pure::FunctionPurities,
ssa_gen::Ssa,
validation::validate_function,
};

/// The per-function context for each ssa function being generated.
Expand Down Expand Up @@ -548,7 +549,7 @@ impl FunctionBuilder {

fn validate_ssa(functions: &[Function]) {
for function in functions {
function.assert_valid();
validate_function(function);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ fn mul_signed() {
acir(inline) fn main f0 {
b0():
v0 = mul i64 2, i64 100
return v0
v1 = cast v0 as u128
v2 = truncate v1 to 64 bits, max_bit_size: 128
v3 = cast v2 as i64
return v3
}
",
);
Expand All @@ -237,11 +240,17 @@ fn mul_overflow_unsigned() {

#[test]
fn mul_overflow_signed() {
// We return v0 as we simply want the output from the mul operation in this test.
// However, the valid SSA signed overflow patterns requires that the appropriate
// casts and truncates follow a signed mul.
let value = expect_value(
"
acir(inline) fn main f0 {
b0():
v0 = mul i8 127, i8 2
v1 = cast v0 as u16
v2 = truncate v1 to 8 bits, max_bit_size: 16
v3 = cast v2 as i8
return v0
}
",
Expand Down
113 changes: 2 additions & 111 deletions compiler/noirc_evaluator/src/ssa/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use super::{
basic_block::{BasicBlock, BasicBlockId},
function::{FunctionId, RuntimeType},
instruction::{
Binary, BinaryOp, Instruction, InstructionId, InstructionResultType, Intrinsic,
TerminatorInstruction,
Instruction, InstructionId, InstructionResultType, Intrinsic, TerminatorInstruction,
},
integer::IntegerConstant,
map::DenseMap,
Expand Down Expand Up @@ -224,62 +223,11 @@ impl DataFlowGraph {
instruction_data: Instruction,
ctrl_typevars: Option<Vec<Type>>,
) -> InstructionId {
self.validate_instruction(&instruction_data);

let id = self.instructions.insert(instruction_data);
self.make_instruction_results(id, ctrl_typevars);
id
}

fn validate_instruction(&self, instruction: &Instruction) {
match instruction {
Instruction::Binary(Binary { lhs, rhs, operator }) => {
let lhs_type = self.type_of_value(*lhs);
let rhs_type = self.type_of_value(*rhs);
match operator {
BinaryOp::Lt => {
if lhs_type != rhs_type {
panic!(
"Left-hand side and right-hand side of `lt` must have the same type"
);
}

if matches!(lhs_type, Type::Numeric(NumericType::NativeField)) {
panic!("Cannot use `lt` with field elements");
}
}
BinaryOp::Shl => {
if !matches!(rhs_type, Type::Numeric(NumericType::Unsigned { bit_size: 8 }))
{
panic!("Right-hand side of `shl` must be u8");
}
}
BinaryOp::Shr => {
if !matches!(rhs_type, Type::Numeric(NumericType::Unsigned { bit_size: 8 }))
{
panic!("Right-hand side of `shr` must be u8");
}
}
_ => {
if lhs_type != rhs_type {
panic!(
"Left-hand side and right-hand side of `{}` must have the same type",
operator
);
}
}
}
}
Instruction::ArrayGet { index, .. } | Instruction::ArraySet { index, .. } => {
let index_type = self.type_of_value(*index);
if !matches!(index_type, Type::Numeric(NumericType::Unsigned { bit_size: 32 })) {
panic!("ArrayGet/ArraySet index must be u32");
}
}
_ => (),
}
}

/// Check if the function runtime would simply ignore this instruction.
pub(crate) fn is_handled_by_runtime(&self, instruction: &Instruction) -> bool {
match self.runtime() {
Expand Down Expand Up @@ -953,10 +901,7 @@ impl std::ops::Index<usize> for InsertInstructionResult<'_> {
#[cfg(test)]
mod tests {
use super::DataFlowGraph;
use crate::ssa::{
ir::{instruction::Instruction, types::Type},
ssa_gen::Ssa,
};
use crate::ssa::ir::{instruction::Instruction, types::Type};

#[test]
fn make_instruction() {
Expand All @@ -967,58 +912,4 @@ mod tests {
let results = dfg.instruction_results(ins_id);
assert_eq!(results.len(), 1);
}

#[test]
#[should_panic(expected = "Cannot use `lt` with field elements")]
fn disallows_comparing_fields_with_lt() {
let src = "
acir(inline) impure fn main f0 {
b0():
v2 = lt Field 1, Field 2
return
}
";
let _ = Ssa::from_str(src);
}

#[test]
#[should_panic(
expected = "Left-hand side and right-hand side of `add` must have the same type"
)]
fn disallows_binary_add_with_different_types() {
let src = "
acir(inline) fn main f0 {
b0():
v2 = add Field 1, i32 2
return
}
";
let _ = Ssa::from_str(src);
}

#[test]
#[should_panic(expected = "Right-hand side of `shr` must be u8")]
fn disallows_shr_with_non_u8() {
let src = "
acir(inline) fn main f0 {
b0():
v2 = shr u32 1, u16 1
return
}
";
let _ = Ssa::from_str(src);
}

#[test]
#[should_panic(expected = "Right-hand side of `shl` must be u8")]
fn disallows_shl_with_non_u8() {
let src = "
acir(inline) fn main f0 {
b0():
v2 = shl u32 1, u16 1
return
}
";
let _ = Ssa::from_str(src);
}
}
Loading
Loading