From 30e15347b95877294daed13bee38b78a8e4f78bc Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 7 Apr 2026 11:46:17 -0700 Subject: [PATCH 1/3] RIFLA: Support emission of loops over constant arrays This updates the `Adaptive_RIFLA` profile to support emission of loops over arrays with constant, compile-time known content. Where the prior looping support only handled loops with iteration-invariant internals, this updates RCA, Partial Eval, RIR, and QIR codegen to allow for arrays with constant content stored in the global section to be the source of iteration values within a loop. For now, only loops with variable types we already support work with this pattern, specifically loops over constant arrays of `Bool`, `Int`, and `Double`. Arrays of arrays are not supported, due to the lack of QIR compatible mechanism for dynamically querying the length of an array and Q# support for jagged arrays of arrays (ie: `[[1.0], [2.0, 3.0]]`). Follow up PRs will add support for iteration over constant arrays of new types like `Qubit` and `Pauli`. Arrays with dynamic contents will be handled later down the line. --- .../qsc_circuit/src/rir_to_circuit.rs | 19 +- source/compiler/qsc_codegen/src/qir/v1.rs | 60 +- .../src/qir/v1/instruction_tests/bool.rs | 24 +- .../src/qir/v1/instruction_tests/double.rs | 106 ++-- .../src/qir/v1/instruction_tests/int.rs | 140 ++-- .../src/qir/v1/instruction_tests/invalid.rs | 42 +- .../src/qir/v1/instruction_tests/phi.rs | 12 +- .../compiler/qsc_codegen/src/qir/v1/tests.rs | 2 +- source/compiler/qsc_codegen/src/qir/v2.rs | 95 ++- .../src/qir/v2/instruction_tests.rs | 1 + .../src/qir/v2/instruction_tests/bool.rs | 24 +- .../src/qir/v2/instruction_tests/double.rs | 106 ++-- .../src/qir/v2/instruction_tests/index.rs | 61 ++ .../src/qir/v2/instruction_tests/int.rs | 140 ++-- .../src/qir/v2/instruction_tests/invalid.rs | 36 +- .../src/qir/v2/instruction_tests/store.rs | 2 +- .../compiler/qsc_codegen/src/qir/v2/tests.rs | 2 +- source/compiler/qsc_partial_eval/src/lib.rs | 185 ++++-- .../qsc_partial_eval/src/tests/loops.rs | 596 +++++++++++++++++- source/compiler/qsc_rca/src/core.rs | 25 +- source/compiler/qsc_rca/src/errors.rs | 22 + source/compiler/qsc_rca/src/lib.rs | 62 +- source/compiler/qsc_rca/src/tests/loops.rs | 2 +- source/compiler/qsc_rir/src/builder.rs | 52 +- .../src/passes/build_dominator_graph/tests.rs | 36 +- .../qsc_rir/src/passes/defer_meas/tests.rs | 14 +- .../qsc_rir/src/passes/insert_alloca_load.rs | 44 +- .../src/passes/prune_unneeded_stores.rs | 29 +- .../src/passes/reindex_qubits/tests.rs | 6 +- .../src/passes/remap_block_ids/tests.rs | 16 +- .../src/passes/simplify_control_flow/tests.rs | 40 +- .../compiler/qsc_rir/src/passes/ssa_check.rs | 2 +- .../qsc_rir/src/passes/ssa_check/tests.rs | 218 +++---- .../qsc_rir/src/passes/ssa_transform/tests.rs | 434 ++++++------- .../compiler/qsc_rir/src/passes/type_check.rs | 27 +- .../qsc_rir/src/passes/type_check/tests.rs | 64 +- .../passes/unreachable_code_check/tests.rs | 14 +- source/compiler/qsc_rir/src/rir.rs | 95 ++- source/compiler/qsc_rir/src/utils.rs | 6 +- .../adaptive_rifla/input/LoopOverArrays.qs | 17 + .../adaptive_rifla/output/LoopOverArrays.ll | 100 +++ .../adaptive_rifla/output/LoopOverArrays.out | 8 + 42 files changed, 2084 insertions(+), 902 deletions(-) create mode 100644 source/compiler/qsc_codegen/src/qir/v2/instruction_tests/index.rs create mode 100644 source/pip/tests-integration/resources/adaptive_rifla/input/LoopOverArrays.qs create mode 100644 source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.ll create mode 100644 source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.out diff --git a/source/compiler/qsc_circuit/src/rir_to_circuit.rs b/source/compiler/qsc_circuit/src/rir_to_circuit.rs index 6d7eefab03..148090127a 100644 --- a/source/compiler/qsc_circuit/src/rir_to_circuit.rs +++ b/source/compiler/qsc_circuit/src/rir_to_circuit.rs @@ -11,7 +11,7 @@ use qsc_fir::fir::PackageId; use qsc_partial_eval::{ Callable, CallableType, ConditionCode, FcmpConditionCode, Instruction, Literal, Operand, VariableId, - rir::{Block, BlockId, Program, Ty, Variable}, + rir::{Block, BlockId, Prim, Program, Ty, Variable}, }; use qsc_rir::debug::{DbgInfo, DbgLocationId, DbgScope, DbgScopeId}; use std::{fmt::Display, vec}; @@ -372,7 +372,8 @@ fn process_variables( instruction @ (Instruction::Store(..) | Instruction::BitwiseNot(..) | Instruction::Alloca(..) - | Instruction::Load(..)) => { + | Instruction::Load(..) + | Instruction::Index(..)) => { return Err(Error::UnsupportedFeature(format!( "unsupported instruction in block: {instruction:?}" ))); @@ -911,7 +912,7 @@ fn store_expr_in_variable( panic!("variable {variable_id:?} already stored {old_value:?}, cannot store {expr:?}"); } if let Expr::Bool(condition_expr) = &expr { - if let Ty::Boolean = var.ty { + if let Ty::Prim(Prim::Boolean) = var.ty { } else { return Err(Error::UnsupportedFeature(format!( "variable {variable_id:?} has type {var_ty:?} but is being assigned a condition expression: {condition_expr:?}", @@ -1278,17 +1279,23 @@ fn callable_spec<'a>( match o { Operand::Literal(Literal::Integer(_) | Literal::Double(_)) | Operand::Variable(Variable { - ty: Ty::Boolean | Ty::Integer | Ty::Double, + ty: Ty::Prim(Prim::Boolean | Prim::Integer | Prim::Double), .. }) => { operand_types.push(OperandType::Arg); } Operand::Literal(Literal::Qubit(_)) - | Operand::Variable(Variable { ty: Ty::Qubit, .. }) => { + | Operand::Variable(Variable { + ty: Ty::Prim(Prim::Qubit), + .. + }) => { operand_types.push(OperandType::TargetQubit); } Operand::Literal(Literal::Result(_)) - | Operand::Variable(Variable { ty: Ty::Result, .. }) => { + | Operand::Variable(Variable { + ty: Ty::Prim(Prim::Result), + .. + }) => { operand_types.push(OperandType::TargetResult); } o => { diff --git a/source/compiler/qsc_codegen/src/qir/v1.rs b/source/compiler/qsc_codegen/src/qir/v1.rs index 8ed60ba29b..f2cc3040a0 100644 --- a/source/compiler/qsc_codegen/src/qir/v1.rs +++ b/source/compiler/qsc_codegen/src/qir/v1.rs @@ -34,7 +34,7 @@ impl ToQir for rir::Literal { } } rir::Literal::Integer(i) => format!("i64 {i}"), - rir::Literal::Pointer => "i8* null".to_string(), + rir::Literal::NullPointer => "i8* null".to_string(), rir::Literal::Qubit(q) => format!("%Qubit* inttoptr (i64 {q} to %Qubit*)"), rir::Literal::Result(r) => format!("%Result* inttoptr (i64 {r} to %Result*)"), rir::Literal::Tag(idx, len) => { @@ -43,23 +43,30 @@ impl ToQir for rir::Literal { "i8* getelementptr inbounds ([{len} x i8], [{len} x i8]* @{idx}, i64 0, i64 0)" ) } + rir::Literal::Array(_) => { + panic!("array literals are not supported in QIR v1 generation") + } } } } impl ToQir for rir::Ty { - fn to_qir(&self, _program: &rir::Program) -> String { + fn to_qir(&self, program: &rir::Program) -> String { match self { - rir::Ty::Boolean => "i1".to_string(), - rir::Ty::Double => "double".to_string(), - rir::Ty::Integer => "i64".to_string(), - rir::Ty::Pointer => "i8*".to_string(), - rir::Ty::Qubit => "%Qubit*".to_string(), - rir::Ty::Result => "%Result*".to_string(), + rir::Ty::Prim(prim) => ToQir::::to_qir(prim, program), + rir::Ty::Array(..) => { + unimplemented!("array types are not supported in QIR v1 generation") + } } } } +impl ToQir for rir::Prim { + fn to_qir(&self, _program: &rir::Program) -> String { + get_prim_ty(*self).to_owned() + } +} + impl ToQir for Option { fn to_qir(&self, program: &rir::Program) -> String { match self { @@ -213,7 +220,9 @@ impl ToQir for rir::Instruction { rir::Instruction::Sub(lhs, rhs, variable) => { binop_to_qir("sub", lhs, rhs, *variable, program) } - rir::Instruction::Alloca(..) | rir::Instruction::Load(..) => { + rir::Instruction::Alloca(..) + | rir::Instruction::Load(..) + | rir::Instruction::Index(..) => { unimplemented!("advanced instructions are not supported in QIR v1 generation") } } @@ -522,12 +531,15 @@ fn get_value_as_str(value: &rir::Operand, program: &rir::Program) -> String { } } rir::Literal::Integer(i) => format!("{i}"), - rir::Literal::Pointer => "null".to_string(), + rir::Literal::NullPointer => "null".to_string(), rir::Literal::Qubit(q) => format!("{q}"), rir::Literal::Result(r) => format!("{r}"), rir::Literal::Tag(..) => panic!( "tag literals should not be used as string values outside of output recording" ), + rir::Literal::Array(..) => { + panic!("array literals are not supported in QIR v1 generation") + } }, rir::Operand::Variable(var) => ToQir::::to_qir(&var.variable_id, program), } @@ -541,7 +553,10 @@ fn get_value_ty(lhs: &rir::Operand) -> &str { rir::Literal::Double(_) => get_f64_ty(), rir::Literal::Qubit(_) => "%Qubit*", rir::Literal::Result(_) => "%Result*", - rir::Literal::Pointer | rir::Literal::Tag(..) => "i8*", + rir::Literal::NullPointer | rir::Literal::Tag(..) => "i8*", + rir::Literal::Array(_) => { + panic!("array literals are not supported in QIR v1 generation") + } }, rir::Operand::Variable(var) => get_variable_ty(*var), } @@ -549,12 +564,19 @@ fn get_value_ty(lhs: &rir::Operand) -> &str { fn get_variable_ty(variable: rir::Variable) -> &'static str { match variable.ty { - rir::Ty::Integer => "i64", - rir::Ty::Boolean => "i1", - rir::Ty::Double => get_f64_ty(), - rir::Ty::Qubit => "%Qubit*", - rir::Ty::Result => "%Result*", - rir::Ty::Pointer => "i8*", + rir::Ty::Prim(prim) => get_prim_ty(prim), + rir::Ty::Array(..) => unimplemented!("array types are not supported in QIR v1 generation"), + } +} + +fn get_prim_ty(prim: rir::Prim) -> &'static str { + match prim { + rir::Prim::Integer => "i64", + rir::Prim::Boolean => "i1", + rir::Prim::Double => get_f64_ty(), + rir::Prim::Qubit => "%Qubit*", + rir::Prim::Result => "%Result*", + rir::Prim::Pointer => "i8*", } } @@ -646,6 +668,10 @@ impl ToQir for rir::Program { } else { "adaptive_profile" }; + assert!( + self.array_literals.is_empty(), + "array literals are not supported in QIR v1 generation" + ); let mut constants = String::default(); for (idx, tag) in self.tags.iter().enumerate() { // We need to add the tag as a global constant. diff --git a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/bool.rs b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/bool.rs index a2968d9882..823a85f200 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/bool.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/bool.rs @@ -12,7 +12,7 @@ fn logical_and_literals() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = and i1 true, false"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -23,15 +23,15 @@ fn logical_and_variables() { let inst = rir::Instruction::LogicalAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = and i1 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -43,7 +43,7 @@ fn logical_not_true_literal() { rir::Operand::Literal(rir::Literal::Bool(true)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 true, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -54,11 +54,11 @@ fn logical_not_variables() { let inst = rir::Instruction::LogicalNot( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 %var_1, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -70,7 +70,7 @@ fn logical_not_false_literal() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 false, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -83,7 +83,7 @@ fn logical_or_literals() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = or i1 true, false"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -94,15 +94,15 @@ fn logical_or_variables() { let inst = rir::Instruction::LogicalOr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = or i1 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); diff --git a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/double.rs b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/double.rs index 649ce98f6e..110ef24421 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/double.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/double.rs @@ -6,7 +6,7 @@ use core::f64::consts::{E, PI}; use super::super::ToQir; use expect_test::expect; use qsc_rir::rir::{ - FcmpConditionCode, Instruction, Literal, Operand, Program, Ty, Variable, VariableId, + FcmpConditionCode, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId, }; #[test] @@ -17,7 +17,7 @@ fn add_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -31,7 +31,7 @@ fn sub_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -45,7 +45,7 @@ fn mul_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -59,7 +59,7 @@ fn sdiv_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -72,7 +72,7 @@ fn fadd_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fadd double 3.141592653589793, 2.718281828459045"] @@ -87,7 +87,7 @@ fn ashr_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -101,7 +101,7 @@ fn bitwise_and_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -114,7 +114,7 @@ fn bitwise_not_double_literals() { Operand::Literal(Literal::Double(PI)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -128,7 +128,7 @@ fn bitwise_or_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -142,7 +142,7 @@ fn bitwise_xor_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -153,15 +153,15 @@ fn fadd_double_variables() { let inst = Instruction::Fadd( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fadd double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -175,7 +175,7 @@ fn fcmp_oeq_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oeq double 3.141592653589793, 2.718281828459045"] @@ -188,15 +188,15 @@ fn fcmp_oeq_double_variables() { FcmpConditionCode::OrderedAndEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oeq double %var_1, %var_2"] @@ -211,7 +211,7 @@ fn fcmp_one_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp one double 3.141592653589793, 2.718281828459045"] @@ -224,15 +224,15 @@ fn fcmp_one_double_variables() { FcmpConditionCode::OrderedAndNotEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp one double %var_1, %var_2"] @@ -246,7 +246,7 @@ fn fcmp_olt_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp olt double 3.141592653589793, 2.718281828459045"] @@ -259,15 +259,15 @@ fn fcmp_olt_double_variables() { FcmpConditionCode::OrderedAndLessThan, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp olt double %var_1, %var_2"] @@ -281,7 +281,7 @@ fn fcmp_ole_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ole double 3.141592653589793, 2.718281828459045"] @@ -294,15 +294,15 @@ fn fcmp_ole_double_variables() { FcmpConditionCode::OrderedAndLessThanOrEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ole double %var_1, %var_2"] @@ -316,7 +316,7 @@ fn fcmp_ogt_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ogt double 3.141592653589793, 2.718281828459045"] @@ -329,15 +329,15 @@ fn fcmp_ogt_double_variables() { FcmpConditionCode::OrderedAndGreaterThan, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ogt double %var_1, %var_2"] @@ -351,7 +351,7 @@ fn fcmp_oge_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oge double 3.141592653589793, 2.718281828459045"] @@ -364,15 +364,15 @@ fn fcmp_oge_double_variables() { FcmpConditionCode::OrderedAndGreaterThanOrEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oge double %var_1, %var_2"] @@ -386,7 +386,7 @@ fn fmul_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fmul double 3.141592653589793, 2.718281828459045"] @@ -398,15 +398,15 @@ fn fmul_double_variables() { let inst = Instruction::Fmul( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fmul double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -419,7 +419,7 @@ fn fdiv_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fdiv double 3.141592653589793, 2.718281828459045"] @@ -431,15 +431,15 @@ fn fdiv_double_variables() { let inst = Instruction::Fdiv( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fdiv double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -452,7 +452,7 @@ fn fsub_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fsub double 3.141592653589793, 2.718281828459045"] @@ -464,15 +464,15 @@ fn fsub_double_variables() { let inst = Instruction::Fsub( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fsub double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -484,7 +484,7 @@ fn convert_double_literal_to_integer() { Operand::Literal(Literal::Double(PI)), Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }, ); expect![" %var_0 = fptosi double 3.141592653589793 to i64"] @@ -496,11 +496,11 @@ fn convert_double_variable_to_integer() { let inst = Instruction::Convert( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }, ); expect![" %var_0 = fptosi double %var_1 to i64"].assert_eq(&inst.to_qir(&Program::default())); diff --git a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/int.rs b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/int.rs index fe2c725544..a4cdd5d7a4 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/int.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/int.rs @@ -12,7 +12,7 @@ fn add_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = add i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -23,15 +23,15 @@ fn add_integer_variables() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = add i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -44,7 +44,7 @@ fn ashr_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = ashr i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -55,15 +55,15 @@ fn ashr_integer_variables() { let inst = rir::Instruction::Ashr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = ashr i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -76,7 +76,7 @@ fn bitwise_and_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = and i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -87,15 +87,15 @@ fn bitwise_add_integer_variables() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = and i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -107,7 +107,7 @@ fn bitwise_not_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(2)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 2, -1"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -118,11 +118,11 @@ fn bitwise_not_integer_variables() { let inst = rir::Instruction::BitwiseNot( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 %var_1, -1"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -135,7 +135,7 @@ fn bitwise_or_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = or i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -146,15 +146,15 @@ fn bitwise_or_integer_variables() { let inst = rir::Instruction::BitwiseOr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = or i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -167,7 +167,7 @@ fn bitwise_xor_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -178,15 +178,15 @@ fn bitwise_xor_integer_variables() { let inst = rir::Instruction::BitwiseXor( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -200,7 +200,7 @@ fn icmp_eq_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp eq i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -212,15 +212,15 @@ fn icmp_eq_integer_variables() { rir::ConditionCode::Eq, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp eq i64 %var_1, %var_2"] @@ -235,7 +235,7 @@ fn icmp_ne_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp ne i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -247,15 +247,15 @@ fn icmp_ne_integer_variables() { rir::ConditionCode::Ne, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp ne i64 %var_1, %var_2"] @@ -269,7 +269,7 @@ fn icmp_slt_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp slt i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -281,15 +281,15 @@ fn icmp_slt_integer_variables() { rir::ConditionCode::Slt, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp slt i64 %var_1, %var_2"] @@ -303,7 +303,7 @@ fn icmp_sle_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sle i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -315,15 +315,15 @@ fn icmp_sle_integer_variables() { rir::ConditionCode::Sle, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sle i64 %var_1, %var_2"] @@ -337,7 +337,7 @@ fn icmp_sgt_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sgt i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -349,15 +349,15 @@ fn icmp_sgt_integer_variables() { rir::ConditionCode::Sgt, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sgt i64 %var_1, %var_2"] @@ -371,7 +371,7 @@ fn icmp_sge_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sge i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -383,15 +383,15 @@ fn icmp_sge_integer_variables() { rir::ConditionCode::Sge, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sge i64 %var_1, %var_2"] @@ -405,7 +405,7 @@ fn mul_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = mul i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -416,15 +416,15 @@ fn mul_integer_variables() { let inst = rir::Instruction::Mul( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = mul i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -437,7 +437,7 @@ fn sdiv_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sdiv i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -448,15 +448,15 @@ fn sdiv_integer_variables() { let inst = rir::Instruction::Sdiv( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sdiv i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -469,7 +469,7 @@ fn shl_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = shl i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -480,15 +480,15 @@ fn shl_integer_variables() { let inst = rir::Instruction::Shl( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = shl i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -501,7 +501,7 @@ fn srem_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = srem i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -512,15 +512,15 @@ fn srem_integer_variables() { let inst = rir::Instruction::Srem( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = srem i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -533,7 +533,7 @@ fn sub_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sub i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -544,15 +544,15 @@ fn sub_integer_variables() { let inst = rir::Instruction::Sub( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sub i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -564,7 +564,7 @@ fn convert_integer_literal_to_double() { rir::Operand::Literal(rir::Literal::Integer(2)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); expect![" %var_0 = sitofp i64 2 to double"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -575,11 +575,11 @@ fn convert_integer_variable_to_double() { let inst = rir::Instruction::Convert( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); expect![" %var_0 = sitofp i64 %var_1 to double"] diff --git a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/invalid.rs b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/invalid.rs index 62383253c0..0186905e0c 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/invalid.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/invalid.rs @@ -12,7 +12,7 @@ fn add_mismatched_literal_input_tys_should_panic() { rir::Operand::Literal(rir::Literal::Double(1.0)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -26,7 +26,7 @@ fn add_mismatched_literal_input_output_tys_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -38,15 +38,15 @@ fn add_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -58,15 +58,15 @@ fn add_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -80,7 +80,7 @@ fn bitwise_and_mismatched_literal_input_tys_should_panic() { rir::Operand::Literal(rir::Literal::Double(1.0)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -94,7 +94,7 @@ fn bitwise_and_mismatched_literal_input_output_tys_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -106,15 +106,15 @@ fn bitwise_and_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -126,15 +126,15 @@ fn bitwise_and_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -148,7 +148,7 @@ fn add_bool_should_panic() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -161,14 +161,14 @@ fn phi_with_mismatched_args_should_panic() { ( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(13), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::BlockId(3), ), ( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::BlockId(7), ), @@ -177,7 +177,7 @@ fn phi_with_mismatched_args_should_panic() { args.to_vec(), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -192,7 +192,7 @@ fn icmp_with_non_boolean_result_var_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = inst.to_qir(&rir::Program::default()); diff --git a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/phi.rs b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/phi.rs index f06c346d80..8133a85cee 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/phi.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/instruction_tests/phi.rs @@ -13,7 +13,7 @@ fn phi_with_empty_args() { args.to_vec(), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -24,7 +24,7 @@ fn phi_with_single_arg() { let args = [( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(13), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::BlockId(3), )]; @@ -32,7 +32,7 @@ fn phi_with_single_arg() { args.to_vec(), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = phi i64 [%var_13, %block_3]"] @@ -45,14 +45,14 @@ fn phi_with_multiple_args() { ( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(13), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::BlockId(3), ), ( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::BlockId(7), ), @@ -61,7 +61,7 @@ fn phi_with_multiple_args() { args.to_vec(), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = phi i64 [%var_13, %block_3], [%var_2, %block_7]"] diff --git a/source/compiler/qsc_codegen/src/qir/v1/tests.rs b/source/compiler/qsc_codegen/src/qir/v1/tests.rs index 6c18afa9c4..eca475d49a 100644 --- a/source/compiler/qsc_codegen/src/qir/v1/tests.rs +++ b/source/compiler/qsc_codegen/src/qir/v1/tests.rs @@ -115,7 +115,7 @@ fn qubit_rotation_variable_angle_call() { vec![ rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Operand::Literal(rir::Literal::Qubit(0)), ], diff --git a/source/compiler/qsc_codegen/src/qir/v2.rs b/source/compiler/qsc_codegen/src/qir/v2.rs index 9a4a02f833..ba41f88dbf 100644 --- a/source/compiler/qsc_codegen/src/qir/v2.rs +++ b/source/compiler/qsc_codegen/src/qir/v2.rs @@ -34,25 +34,32 @@ impl ToQir for rir::Literal { } } rir::Literal::Integer(i) => format!("i64 {i}"), - rir::Literal::Pointer => "ptr null".to_string(), + rir::Literal::NullPointer => "ptr null".to_string(), rir::Literal::Qubit(q) => format!("ptr inttoptr (i64 {q} to ptr)"), rir::Literal::Result(r) => format!("ptr inttoptr (i64 {r} to ptr)"), rir::Literal::Tag(idx, _) => format!("ptr @{idx}"), + rir::Literal::Array(idx) => format!("ptr @array{idx}"), } } } impl ToQir for rir::Ty { - fn to_qir(&self, _program: &rir::Program) -> String { + fn to_qir(&self, program: &rir::Program) -> String { match self { - rir::Ty::Boolean => "i1".to_string(), - rir::Ty::Double => "double".to_string(), - rir::Ty::Integer => "i64".to_string(), - rir::Ty::Pointer | rir::Ty::Qubit | rir::Ty::Result => "ptr".to_string(), + rir::Ty::Prim(prim) => ToQir::::to_qir(prim, program), + rir::Ty::Array(size, elem_ty) => { + format!("[{size} x {}]", ToQir::::to_qir(elem_ty, program)) + } } } } +impl ToQir for rir::Prim { + fn to_qir(&self, _program: &rir::Program) -> String { + get_prim_ty(*self).to_owned() + } +} + impl ToQir for Option { fn to_qir(&self, program: &rir::Program) -> String { match self { @@ -212,10 +219,30 @@ impl ToQir for rir::Instruction { } rir::Instruction::Alloca(variable) => alloca_to_qir(*variable, program), rir::Instruction::Load(var_from, var_to) => load_to_qir(*var_from, *var_to, program), + rir::Instruction::Index(array_op, index_op, result_var) => { + index_to_qir(array_op, index_op, result_var, program) + } } } } +fn index_to_qir( + array_op: &rir::Operand, + index_op: &rir::Operand, + result_var: &rir::Variable, + program: &rir::Program, +) -> String { + // Only need to emit the getelementptr instruction here, as passes are expected to insert the subsequent load instruction. + format!( + " {} = getelementptr {}, ptr {}, {} {}", + ToQir::::to_qir(&result_var.variable_id, program), + ToQir::::to_qir(&result_var.ty, program), + get_value_as_str(array_op, program), + get_value_ty(index_op), + get_value_as_str(index_op, program) + ) +} + fn convert_to_qir( operand: &rir::Operand, variable: rir::Variable, @@ -228,7 +255,7 @@ fn convert_to_qir( "input/output types ({operand_ty}, {var_ty}) should not match in convert" ); - let convert_instr = match (operand_ty, var_ty) { + let convert_instr = match (operand_ty.as_str(), var_ty.as_str()) { ("i64", "double") => "sitofp i64", ("double", "i64") => "fptosi double", _ => panic!("unsupported conversion from {operand_ty} to {var_ty} in convert instruction"), @@ -511,9 +538,12 @@ fn get_value_as_str(value: &rir::Operand, program: &rir::Program) -> String { } } rir::Literal::Integer(i) => format!("{i}"), - rir::Literal::Pointer => "null".to_string(), + rir::Literal::NullPointer => "null".to_string(), rir::Literal::Qubit(q) => format!("{q}"), rir::Literal::Result(r) => format!("{r}"), + rir::Literal::Array(idx) => { + format!("@array{idx}") + } rir::Literal::Tag(..) => panic!( "tag literals should not be used as string values outside of output recording" ), @@ -522,7 +552,7 @@ fn get_value_as_str(value: &rir::Operand, program: &rir::Program) -> String { } } -fn get_value_ty(lhs: &rir::Operand) -> &str { +fn get_value_ty(lhs: &rir::Operand) -> String { match lhs { rir::Operand::Literal(lit) => match lit { rir::Literal::Integer(_) => "i64", @@ -530,19 +560,28 @@ fn get_value_ty(lhs: &rir::Operand) -> &str { rir::Literal::Double(_) => get_f64_ty(), rir::Literal::Qubit(_) | rir::Literal::Result(_) - | rir::Literal::Pointer - | rir::Literal::Tag(..) => "ptr", - }, + | rir::Literal::NullPointer + | rir::Literal::Tag(..) + | rir::Literal::Array(_) => "ptr", + } + .to_owned(), rir::Operand::Variable(var) => get_variable_ty(*var), } } -fn get_variable_ty(variable: rir::Variable) -> &'static str { +fn get_variable_ty(variable: rir::Variable) -> String { match variable.ty { - rir::Ty::Integer => "i64", - rir::Ty::Boolean => "i1", - rir::Ty::Double => get_f64_ty(), - rir::Ty::Qubit | rir::Ty::Result | rir::Ty::Pointer => "ptr", + rir::Ty::Prim(prim) => get_prim_ty(prim).to_owned(), + rir::Ty::Array(size, elem_ty) => format!("[{size} x {}]", get_prim_ty(elem_ty)), + } +} + +fn get_prim_ty(prim: rir::Prim) -> &'static str { + match prim { + rir::Prim::Integer => "i64", + rir::Prim::Boolean => "i1", + rir::Prim::Double => get_f64_ty(), + rir::Prim::Qubit | rir::Prim::Result | rir::Prim::Pointer => "ptr", } } @@ -621,6 +660,19 @@ impl ToQir for rir::Callable { } } +impl ToQir for rir::ArrayLiteral { + fn to_qir(&self, program: &rir::Program) -> String { + let elem_ty = get_prim_ty(self.ty); + let elems = self + .contents + .iter() + .map(|elem| ToQir::::to_qir(elem, program)) + .collect::>() + .join(", "); + format!("[{} x {}] [{}]", self.contents.len(), elem_ty, elems) + } +} + impl ToQir for rir::Program { fn to_qir(&self, _program: &rir::Program) -> String { let callables = self @@ -639,6 +691,15 @@ impl ToQir for rir::Program { ) .expect("writing to string should succeed"); } + for (idx, array) in self.array_literals.iter().enumerate() { + // We need to add the array as a global constant. + writeln!( + constants, + "@array{idx} = internal constant {}", + ToQir::::to_qir(array, self) + ) + .expect("writing to string should succeed"); + } let body = format!( include_str!("./v2/template.ll"), constants, diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests.rs index 581b070a12..d4f54d19a3 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests.rs @@ -4,6 +4,7 @@ mod alloca; mod bool; mod double; +mod index; mod int; mod invalid; mod load; diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/bool.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/bool.rs index a2968d9882..823a85f200 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/bool.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/bool.rs @@ -12,7 +12,7 @@ fn logical_and_literals() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = and i1 true, false"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -23,15 +23,15 @@ fn logical_and_variables() { let inst = rir::Instruction::LogicalAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = and i1 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -43,7 +43,7 @@ fn logical_not_true_literal() { rir::Operand::Literal(rir::Literal::Bool(true)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 true, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -54,11 +54,11 @@ fn logical_not_variables() { let inst = rir::Instruction::LogicalNot( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 %var_1, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -70,7 +70,7 @@ fn logical_not_false_literal() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = xor i1 false, true"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -83,7 +83,7 @@ fn logical_or_literals() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = or i1 true, false"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -94,15 +94,15 @@ fn logical_or_variables() { let inst = rir::Instruction::LogicalOr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = or i1 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/double.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/double.rs index 649ce98f6e..110ef24421 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/double.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/double.rs @@ -6,7 +6,7 @@ use core::f64::consts::{E, PI}; use super::super::ToQir; use expect_test::expect; use qsc_rir::rir::{ - FcmpConditionCode, Instruction, Literal, Operand, Program, Ty, Variable, VariableId, + FcmpConditionCode, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId, }; #[test] @@ -17,7 +17,7 @@ fn add_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -31,7 +31,7 @@ fn sub_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -45,7 +45,7 @@ fn mul_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -59,7 +59,7 @@ fn sdiv_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -72,7 +72,7 @@ fn fadd_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fadd double 3.141592653589793, 2.718281828459045"] @@ -87,7 +87,7 @@ fn ashr_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -101,7 +101,7 @@ fn bitwise_and_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -114,7 +114,7 @@ fn bitwise_not_double_literals() { Operand::Literal(Literal::Double(PI)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -128,7 +128,7 @@ fn bitwise_or_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -142,7 +142,7 @@ fn bitwise_xor_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); let _ = &inst.to_qir(&Program::default()); @@ -153,15 +153,15 @@ fn fadd_double_variables() { let inst = Instruction::Fadd( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fadd double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -175,7 +175,7 @@ fn fcmp_oeq_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oeq double 3.141592653589793, 2.718281828459045"] @@ -188,15 +188,15 @@ fn fcmp_oeq_double_variables() { FcmpConditionCode::OrderedAndEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oeq double %var_1, %var_2"] @@ -211,7 +211,7 @@ fn fcmp_one_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp one double 3.141592653589793, 2.718281828459045"] @@ -224,15 +224,15 @@ fn fcmp_one_double_variables() { FcmpConditionCode::OrderedAndNotEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp one double %var_1, %var_2"] @@ -246,7 +246,7 @@ fn fcmp_olt_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp olt double 3.141592653589793, 2.718281828459045"] @@ -259,15 +259,15 @@ fn fcmp_olt_double_variables() { FcmpConditionCode::OrderedAndLessThan, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp olt double %var_1, %var_2"] @@ -281,7 +281,7 @@ fn fcmp_ole_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ole double 3.141592653589793, 2.718281828459045"] @@ -294,15 +294,15 @@ fn fcmp_ole_double_variables() { FcmpConditionCode::OrderedAndLessThanOrEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ole double %var_1, %var_2"] @@ -316,7 +316,7 @@ fn fcmp_ogt_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ogt double 3.141592653589793, 2.718281828459045"] @@ -329,15 +329,15 @@ fn fcmp_ogt_double_variables() { FcmpConditionCode::OrderedAndGreaterThan, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp ogt double %var_1, %var_2"] @@ -351,7 +351,7 @@ fn fcmp_oge_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oge double 3.141592653589793, 2.718281828459045"] @@ -364,15 +364,15 @@ fn fcmp_oge_double_variables() { FcmpConditionCode::OrderedAndGreaterThanOrEqual, Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ); expect![" %var_0 = fcmp oge double %var_1, %var_2"] @@ -386,7 +386,7 @@ fn fmul_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fmul double 3.141592653589793, 2.718281828459045"] @@ -398,15 +398,15 @@ fn fmul_double_variables() { let inst = Instruction::Fmul( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fmul double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -419,7 +419,7 @@ fn fdiv_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fdiv double 3.141592653589793, 2.718281828459045"] @@ -431,15 +431,15 @@ fn fdiv_double_variables() { let inst = Instruction::Fdiv( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fdiv double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -452,7 +452,7 @@ fn fsub_double_literals() { Operand::Literal(Literal::Double(E)), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fsub double 3.141592653589793, 2.718281828459045"] @@ -464,15 +464,15 @@ fn fsub_double_variables() { let inst = Instruction::Fsub( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }, ); expect![" %var_0 = fsub double %var_1, %var_2"].assert_eq(&inst.to_qir(&Program::default())); @@ -484,7 +484,7 @@ fn convert_double_literal_to_integer() { Operand::Literal(Literal::Double(PI)), Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }, ); expect![" %var_0 = fptosi double 3.141592653589793 to i64"] @@ -496,11 +496,11 @@ fn convert_double_variable_to_integer() { let inst = Instruction::Convert( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), }), Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }, ); expect![" %var_0 = fptosi double %var_1 to i64"].assert_eq(&inst.to_qir(&Program::default())); diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/index.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/index.rs new file mode 100644 index 0000000000..3eae9456a1 --- /dev/null +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/index.rs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use crate::qir::v2::ToQir; +use expect_test::expect; +use qsc_rir::rir; + +#[test] +fn integer_from_variable_index() { + let inst = rir::Instruction::Index( + rir::Operand::Variable(rir::Variable::new_ptr(rir::VariableId(1))), + rir::Operand::Variable(rir::Variable::new_integer(rir::VariableId(0))), + rir::Variable::new_integer(rir::VariableId(0)), + ); + expect![" %var_0 = getelementptr i64, ptr %var_1, i64 %var_0"] + .assert_eq(&inst.to_qir(&rir::Program::default())); +} + +#[test] +fn integer_from_literal_index() { + let inst = rir::Instruction::Index( + rir::Operand::Variable(rir::Variable::new_ptr(rir::VariableId(1))), + rir::Operand::Literal(rir::Literal::Integer(0)), + rir::Variable::new_integer(rir::VariableId(0)), + ); + expect![" %var_0 = getelementptr i64, ptr %var_1, i64 0"] + .assert_eq(&inst.to_qir(&rir::Program::default())); +} + +#[test] +fn integer_from_literal_index_literal_array() { + let inst = rir::Instruction::Index( + rir::Operand::Literal(rir::Literal::Array(0)), + rir::Operand::Literal(rir::Literal::Integer(0)), + rir::Variable::new_integer(rir::VariableId(0)), + ); + expect![" %var_0 = getelementptr i64, ptr @array0, i64 0"] + .assert_eq(&inst.to_qir(&rir::Program::default())); +} + +#[test] +fn double_from_variable_index() { + let inst = rir::Instruction::Index( + rir::Operand::Variable(rir::Variable::new_ptr(rir::VariableId(1))), + rir::Operand::Variable(rir::Variable::new_integer(rir::VariableId(0))), + rir::Variable::new_double(rir::VariableId(0)), + ); + expect![" %var_0 = getelementptr double, ptr %var_1, i64 %var_0"] + .assert_eq(&inst.to_qir(&rir::Program::default())); +} + +#[test] +fn double_from_literal_index() { + let inst = rir::Instruction::Index( + rir::Operand::Variable(rir::Variable::new_ptr(rir::VariableId(1))), + rir::Operand::Literal(rir::Literal::Integer(0)), + rir::Variable::new_double(rir::VariableId(0)), + ); + expect![" %var_0 = getelementptr double, ptr %var_1, i64 0"] + .assert_eq(&inst.to_qir(&rir::Program::default())); +} diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/int.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/int.rs index fe2c725544..a4cdd5d7a4 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/int.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/int.rs @@ -12,7 +12,7 @@ fn add_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = add i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -23,15 +23,15 @@ fn add_integer_variables() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = add i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -44,7 +44,7 @@ fn ashr_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = ashr i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -55,15 +55,15 @@ fn ashr_integer_variables() { let inst = rir::Instruction::Ashr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = ashr i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -76,7 +76,7 @@ fn bitwise_and_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = and i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -87,15 +87,15 @@ fn bitwise_add_integer_variables() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = and i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -107,7 +107,7 @@ fn bitwise_not_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(2)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 2, -1"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -118,11 +118,11 @@ fn bitwise_not_integer_variables() { let inst = rir::Instruction::BitwiseNot( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 %var_1, -1"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -135,7 +135,7 @@ fn bitwise_or_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = or i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -146,15 +146,15 @@ fn bitwise_or_integer_variables() { let inst = rir::Instruction::BitwiseOr( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = or i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -167,7 +167,7 @@ fn bitwise_xor_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -178,15 +178,15 @@ fn bitwise_xor_integer_variables() { let inst = rir::Instruction::BitwiseXor( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = xor i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -200,7 +200,7 @@ fn icmp_eq_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp eq i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -212,15 +212,15 @@ fn icmp_eq_integer_variables() { rir::ConditionCode::Eq, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp eq i64 %var_1, %var_2"] @@ -235,7 +235,7 @@ fn icmp_ne_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp ne i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -247,15 +247,15 @@ fn icmp_ne_integer_variables() { rir::ConditionCode::Ne, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp ne i64 %var_1, %var_2"] @@ -269,7 +269,7 @@ fn icmp_slt_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp slt i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -281,15 +281,15 @@ fn icmp_slt_integer_variables() { rir::ConditionCode::Slt, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp slt i64 %var_1, %var_2"] @@ -303,7 +303,7 @@ fn icmp_sle_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sle i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -315,15 +315,15 @@ fn icmp_sle_integer_variables() { rir::ConditionCode::Sle, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sle i64 %var_1, %var_2"] @@ -337,7 +337,7 @@ fn icmp_sgt_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sgt i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -349,15 +349,15 @@ fn icmp_sgt_integer_variables() { rir::ConditionCode::Sgt, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sgt i64 %var_1, %var_2"] @@ -371,7 +371,7 @@ fn icmp_sge_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sge i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -383,15 +383,15 @@ fn icmp_sge_integer_variables() { rir::ConditionCode::Sge, rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); expect![" %var_0 = icmp sge i64 %var_1, %var_2"] @@ -405,7 +405,7 @@ fn mul_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = mul i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -416,15 +416,15 @@ fn mul_integer_variables() { let inst = rir::Instruction::Mul( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = mul i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -437,7 +437,7 @@ fn sdiv_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sdiv i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -448,15 +448,15 @@ fn sdiv_integer_variables() { let inst = rir::Instruction::Sdiv( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sdiv i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -469,7 +469,7 @@ fn shl_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = shl i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -480,15 +480,15 @@ fn shl_integer_variables() { let inst = rir::Instruction::Shl( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = shl i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -501,7 +501,7 @@ fn srem_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = srem i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -512,15 +512,15 @@ fn srem_integer_variables() { let inst = rir::Instruction::Srem( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = srem i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -533,7 +533,7 @@ fn sub_integer_literals() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sub i64 2, 5"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -544,15 +544,15 @@ fn sub_integer_variables() { let inst = rir::Instruction::Sub( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); expect![" %var_0 = sub i64 %var_1, %var_2"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -564,7 +564,7 @@ fn convert_integer_literal_to_double() { rir::Operand::Literal(rir::Literal::Integer(2)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); expect![" %var_0 = sitofp i64 2 to double"].assert_eq(&inst.to_qir(&rir::Program::default())); @@ -575,11 +575,11 @@ fn convert_integer_variable_to_double() { let inst = rir::Instruction::Convert( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); expect![" %var_0 = sitofp i64 %var_1 to double"] diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/invalid.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/invalid.rs index 54dd71713d..a7dc4bb85f 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/invalid.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/invalid.rs @@ -12,7 +12,7 @@ fn add_mismatched_literal_input_tys_should_panic() { rir::Operand::Literal(rir::Literal::Double(1.0)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -26,7 +26,7 @@ fn add_mismatched_literal_input_output_tys_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -38,15 +38,15 @@ fn add_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -58,15 +58,15 @@ fn add_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::Add( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -80,7 +80,7 @@ fn bitwise_and_mismatched_literal_input_tys_should_panic() { rir::Operand::Literal(rir::Literal::Double(1.0)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -94,7 +94,7 @@ fn bitwise_and_mismatched_literal_input_output_tys_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -106,15 +106,15 @@ fn bitwise_and_mismatched_variable_input_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -126,15 +126,15 @@ fn bitwise_and_mismatched_variable_input_output_tys_should_panic() { let inst = rir::Instruction::BitwiseAnd( rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(1), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(2), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -148,7 +148,7 @@ fn add_bool_should_panic() { rir::Operand::Literal(rir::Literal::Bool(false)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }, ); let _ = &inst.to_qir(&rir::Program::default()); @@ -163,7 +163,7 @@ fn icmp_with_non_boolean_result_var_should_panic() { rir::Operand::Literal(rir::Literal::Integer(5)), rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Integer, + ty: rir::Ty::Prim(rir::Prim::Integer), }, ); let _ = inst.to_qir(&rir::Program::default()); diff --git a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/store.rs b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/store.rs index 7820f4ac12..d5a07a6226 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/store.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/instruction_tests/store.rs @@ -44,7 +44,7 @@ fn store_double_literal_to_pointer() { #[test] fn store_pointer_literal_to_pointer() { let inst = rir::Instruction::Store( - rir::Operand::Literal(rir::Literal::Pointer), + rir::Operand::Literal(rir::Literal::NullPointer), rir::Variable::new_ptr(rir::VariableId(0)), ); expect![" store ptr null, ptr %var_0"].assert_eq(&inst.to_qir(&rir::Program::default())); diff --git a/source/compiler/qsc_codegen/src/qir/v2/tests.rs b/source/compiler/qsc_codegen/src/qir/v2/tests.rs index 19facf0b9b..a57bbf0948 100644 --- a/source/compiler/qsc_codegen/src/qir/v2/tests.rs +++ b/source/compiler/qsc_codegen/src/qir/v2/tests.rs @@ -113,7 +113,7 @@ fn qubit_rotation_variable_angle_call() { vec![ rir::Operand::Variable(rir::Variable { variable_id: rir::VariableId(0), - ty: rir::Ty::Double, + ty: rir::Ty::Prim(rir::Prim::Double), }), rir::Operand::Literal(rir::Literal::Qubit(0)), ], diff --git a/source/compiler/qsc_partial_eval/src/lib.rs b/source/compiler/qsc_partial_eval/src/lib.rs index c8f912e0c0..00e5f977ec 100644 --- a/source/compiler/qsc_partial_eval/src/lib.rs +++ b/source/compiler/qsc_partial_eval/src/lib.rs @@ -253,7 +253,7 @@ impl<'a> PartialEvaluator<'a> { let entry_point = rir::Callable { name: "main".into(), input_type: Vec::new(), - output_type: Some(rir::Ty::Integer), + output_type: Some(rir::Ty::Prim(rir::Prim::Integer)), body: Some(entry_block_id), call_type: CallableType::Regular, }; @@ -269,7 +269,7 @@ impl<'a> PartialEvaluator<'a> { .0 .push(Instruction::Call( init_id, - vec![Operand::Literal(Literal::Pointer)], + vec![Operand::Literal(Literal::NullPointer)], None, None, )); @@ -741,7 +741,7 @@ impl<'a> PartialEvaluator<'a> { let variable_id = self.resource_manager.next_var(); let rir_variable = rir::Variable { variable_id, - ty: rir::Ty::Boolean, // Binary operations between results are always Boolean. + ty: rir::Ty::Prim(rir::Prim::Boolean), // Binary operations between results are always Boolean. }; // Create the binary operation instruction and add it to the current block. @@ -828,7 +828,7 @@ impl<'a> PartialEvaluator<'a> { let bin_op_variable_id = self.resource_manager.next_var(); let bin_op_rir_variable = rir::Variable { variable_id: bin_op_variable_id, - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }; let bin_op_ins = match bin_op { BinOp::AndL => { @@ -946,7 +946,7 @@ impl<'a> PartialEvaluator<'a> { let result_var_id = self.resource_manager.next_var(); let result_rir_var = rir::Variable { variable_id: result_var_id, - ty: rir::Ty::Boolean, + ty: rir::Ty::Prim(rir::Prim::Boolean), }; let init_var_ins = Instruction::Store( Operand::Literal(Literal::Bool(short_circuit_on_true)), @@ -1020,7 +1020,7 @@ impl<'a> PartialEvaluator<'a> { bin_op_expr_span: PackageSpan, // For diagnostic purposes only. ) -> Result { assert!( - matches!(lhs_operand.get_type(), rir::Ty::Double), + matches!(lhs_operand.get_type(), rir::Ty::Prim(rir::Prim::Double)), "LHS is expected to be of double type" ); @@ -1034,7 +1034,7 @@ impl<'a> PartialEvaluator<'a> { }; let rhs_operand = self.map_eval_value_to_rir_operand(&rhs_value); assert!( - matches!(rhs_operand.get_type(), rir::Ty::Double), + matches!(rhs_operand.get_type(), rir::Ty::Prim(rir::Prim::Double)), "LHS value is expected to be of double type" ); @@ -1076,7 +1076,7 @@ impl<'a> PartialEvaluator<'a> { bin_op_expr_span: PackageSpan, // For diagnostic purposes only. ) -> Result { assert!( - matches!(lhs_operand.get_type(), rir::Ty::Integer), + matches!(lhs_operand.get_type(), rir::Ty::Prim(rir::Prim::Integer)), "LHS is expected to be of integer type" ); @@ -1090,7 +1090,7 @@ impl<'a> PartialEvaluator<'a> { }; let rhs_operand = self.map_eval_value_to_rir_operand(&rhs_value); assert!( - matches!(rhs_operand.get_type(), rir::Ty::Integer), + matches!(rhs_operand.get_type(), rir::Ty::Prim(rir::Prim::Integer)), "LHS value is expected to be of integer type" ); @@ -2097,24 +2097,25 @@ impl<'a> PartialEvaluator<'a> { // Get the value at the specified index. let array = array_value.unwrap_array(); - let index_expr = self.get_expr(index_expr_id); - let hir_package_id = map_fir_package_to_hir(self.get_current_package_id()); - let index_package_span = PackageSpan { - package: hir_package_id, - span: index_expr.span, - }; - let value_result = match index_value { - Value::Int(index) => index_array(&array, index, index_package_span), + let index_package_span = self.get_expr_package_span(index_expr_id); + let array_package_span = self.get_expr_package_span(array_expr_id); + let value = match index_value { + Value::Int(index) => { + index_array(&array, index, index_package_span).map_err(Error::from) + } Value::Range(range) => slice_array( &array, range.start, range.step, range.end, index_package_span, - ), + ) + .map_err(Error::from), + Value::Var(var) => { + self.eval_expr_dynamic_index(&array, var, array_package_span, index_package_span) + } _ => panic!("invalid kind of value for index"), - }; - let value = value_result.map_err(Error::from)?; + }?; Ok(EvalControlFlow::Continue(value)) } @@ -2242,22 +2243,28 @@ impl<'a> PartialEvaluator<'a> { let value_operand = self.map_eval_value_to_rir_operand(&value); let instruction = match un_op { UnOp::Neg => match rir_variable_type { - rir::Ty::Integer => { + rir::Ty::Prim(rir::Prim::Integer) => { let constant = Operand::Literal(Literal::Integer(-1)); Instruction::Mul(constant, value_operand, rir_variable) } - rir::Ty::Double => { + rir::Ty::Prim(rir::Prim::Double) => { let constant = Operand::Literal(Literal::Double(-1.0)); Instruction::Fmul(constant, value_operand, rir_variable) } _ => panic!("invalid type for negation operator {rir_variable_type}"), }, UnOp::NotB => { - assert!(matches!(rir_variable_type, rir::Ty::Integer)); + assert!(matches!( + rir_variable_type, + rir::Ty::Prim(rir::Prim::Integer) + )); Instruction::BitwiseNot(value_operand, rir_variable) } UnOp::NotL => { - assert!(matches!(rir_variable_type, rir::Ty::Boolean)); + assert!(matches!( + rir_variable_type, + rir::Ty::Prim(rir::Prim::Boolean) + )); Instruction::LogicalNot(value_operand, rir_variable) } UnOp::Functor(_) | UnOp::Unwrap => { @@ -2505,7 +2512,7 @@ impl<'a> PartialEvaluator<'a> { let read_result_callable_id = self.get_or_insert_callable(builder::read_result_decl()); let variable_id = self.resource_manager.next_var(); - let variable_ty = rir::Ty::Boolean; + let variable_ty = rir::Ty::Prim(rir::Prim::Boolean); let variable = rir::Variable { variable_id, ty: variable_ty, @@ -2996,7 +3003,7 @@ impl<'a> PartialEvaluator<'a> { match args_value { Value::Qubit(qubit) => { - input_type.push(qsc_rir::rir::Ty::Qubit); + input_type.push(qsc_rir::rir::Ty::Prim(rir::Prim::Qubit)); operands.push(self.map_eval_value_to_rir_operand(&Value::Qubit(qubit))); } Value::Tuple(values, _) => { @@ -3006,7 +3013,7 @@ impl<'a> PartialEvaluator<'a> { "by this point a qsc_pass should have checked that all arguments are Qubits" ) }; - input_type.push(qsc_rir::rir::Ty::Qubit); + input_type.push(qsc_rir::rir::Ty::Prim(rir::Prim::Qubit)); operands.push(self.map_eval_value_to_rir_operand(&Value::Qubit(qubit.clone()))); } } @@ -3017,7 +3024,7 @@ impl<'a> PartialEvaluator<'a> { match &callable_decl.output { qsc_fir::ty::Ty::Prim(qsc_fir::ty::Prim::Result) => { - input_type.push(qsc_rir::rir::Ty::Result); + input_type.push(qsc_rir::rir::Ty::Prim(rir::Prim::Result)); let result_value = Value::Result(self.resource_manager.next_result_register()); let result_operand = self.map_eval_value_to_rir_operand(&result_value); operands.push(result_operand); @@ -3026,7 +3033,7 @@ impl<'a> PartialEvaluator<'a> { qsc_fir::ty::Ty::Tuple(outputs) => { for output in outputs { if matches!(output, qsc_fir::ty::Ty::Prim(qsc_fir::ty::Prim::Result)) { - input_type.push(qsc_rir::rir::Ty::Result); + input_type.push(qsc_rir::rir::Ty::Prim(rir::Prim::Result)); let result_value = Value::Result(self.resource_manager.next_result_register()); let result_operand = self.map_eval_value_to_rir_operand(&result_value); @@ -3955,6 +3962,49 @@ impl<'a> PartialEvaluator<'a> { .iteration_count += 1; } } + + fn eval_expr_dynamic_index( + &mut self, + array: &Rc>, + var: Var, + array_package_span: PackageSpan, + index_package_span: PackageSpan, + ) -> Result { + let array_literal = + convert_to_array_literal(array, array_package_span, index_package_span)?; + let array_elem_ty = array_literal.ty; + + let const_array_id = if let Some(idx) = self + .program + .array_literals + .iter() + .position(|a| a == &array_literal) + { + idx + } else { + let idx = self.program.array_literals.len(); + self.program.array_literals.push(array_literal); + idx + }; + + let variable_id = self.resource_manager.next_var(); + let rir_variable = rir::Variable { + variable_id, + ty: rir::Ty::Prim(array_elem_ty), + }; + + self.get_current_rir_block_mut().0.push(Instruction::Index( + Operand::Literal(Literal::Array(const_array_id)), + Operand::Variable(map_eval_var_to_rir_var(var)), + rir_variable, + )); + + let eval_variable = map_rir_var_to_eval_var(rir_variable).map_err(|()| { + Error::Unimplemented(format!("array of type {array_elem_ty}"), array_package_span) + })?; + + Ok(Value::Var(eval_variable)) + } } #[derive(Default)] @@ -4162,19 +4212,19 @@ fn map_eval_var_to_rir_var(var: Var) -> rir::Variable { fn map_eval_var_type_to_rir_type(var_ty: VarTy) -> rir::Ty { match var_ty { - VarTy::Boolean => rir::Ty::Boolean, - VarTy::Integer => rir::Ty::Integer, - VarTy::Double => rir::Ty::Double, + VarTy::Boolean => rir::Ty::Prim(rir::Prim::Boolean), + VarTy::Integer => rir::Ty::Prim(rir::Prim::Integer), + VarTy::Double => rir::Ty::Prim(rir::Prim::Double), } } fn map_fir_type_to_rir_type(ty: &Ty) -> Result { match ty { - Ty::Prim(Prim::Bool) => Ok(rir::Ty::Boolean), - Ty::Prim(Prim::Double) => Ok(rir::Ty::Double), - Ty::Prim(Prim::Int) => Ok(rir::Ty::Integer), - Ty::Prim(Prim::Qubit) => Ok(rir::Ty::Qubit), - Ty::Prim(Prim::Result) => Ok(rir::Ty::Result), + Ty::Prim(Prim::Bool) => Ok(rir::Ty::Prim(rir::Prim::Boolean)), + Ty::Prim(Prim::Double) => Ok(rir::Ty::Prim(rir::Prim::Double)), + Ty::Prim(Prim::Int) => Ok(rir::Ty::Prim(rir::Prim::Integer)), + Ty::Prim(Prim::Qubit) => Ok(rir::Ty::Prim(rir::Prim::Qubit)), + Ty::Prim(Prim::Result) => Ok(rir::Ty::Prim(rir::Prim::Result)), _ => Err(format!("{ty}")), } } @@ -4197,9 +4247,9 @@ fn map_rir_var_to_eval_var(var: rir::Variable) -> Result { fn map_rir_type_to_eval_var_type(ty: rir::Ty) -> Result { match ty { - rir::Ty::Boolean => Ok(VarTy::Boolean), - rir::Ty::Integer => Ok(VarTy::Integer), - rir::Ty::Double => Ok(VarTy::Double), + rir::Ty::Prim(rir::Prim::Boolean) => Ok(VarTy::Boolean), + rir::Ty::Prim(rir::Prim::Integer) => Ok(VarTy::Integer), + rir::Ty::Prim(rir::Prim::Double) => Ok(VarTy::Double), _ => Err(()), } } @@ -4213,3 +4263,58 @@ fn try_get_eval_var_type(value: &Value) -> Option { _ => None, } } + +fn convert_to_array_literal( + array: &Rc>, + array_package_span: PackageSpan, + index_package_span: PackageSpan, +) -> Result { + if array.is_empty() { + // Even though we don't know what the index value is, we know any index into an empty array is out of range, + // so just return an error with index 0 here. + return Err(EvalError::IndexOutOfRange(0, index_package_span).into()); + } + + let elem_varty = try_get_eval_var_type(&array[0]).ok_or_else(|| { + Error::Unimplemented( + format!("array element type `{}`", array[0].type_name()), + array_package_span, + ) + })?; + let rir::Ty::Prim(elem_rir_prim_ty) = map_eval_var_type_to_rir_type(elem_varty) else { + return Err(Error::Unexpected( + "array with non-primitive RIR type".to_string(), + array_package_span, + )); + }; + + let mut elem_literals = Vec::new(); + for elem in array.iter() { + let elem_literal = match elem { + Value::Bool(b) => rir::Literal::Bool(*b), + Value::Int(i) => rir::Literal::Integer(*i), + Value::Double(d) => rir::Literal::Double(*d), + Value::Qubit(q) => rir::Literal::Qubit( + q.deref() + .0 + .try_into() + .expect("could not convert qubit ID to u32"), + ), + Value::Result(val::Result::Id(r)) => { + rir::Literal::Result((*r).try_into().expect("could not convert result ID to u32")) + } + _ => { + return Err(Error::Unimplemented( + format!("array element type `{}`", elem.type_name()), + array_package_span, + )); + } + }; + elem_literals.push(elem_literal); + } + + Ok(rir::ArrayLiteral { + contents: elem_literals, + ty: elem_rir_prim_ty, + }) +} diff --git a/source/compiler/qsc_partial_eval/src/tests/loops.rs b/source/compiler/qsc_partial_eval/src/tests/loops.rs index efb26b73a6..5f34d3f98b 100644 --- a/source/compiler/qsc_partial_eval/src/tests/loops.rs +++ b/source/compiler/qsc_partial_eval/src/tests/loops.rs @@ -6,7 +6,7 @@ use crate::tests::get_rir_program_with_capabilities; use super::{assert_block_instructions, assert_blocks, assert_callable, get_rir_program}; use expect_test::expect; use indoc::indoc; -use qsc_data_structures::target::TargetCapabilityFlags; +use qsc_data_structures::target::{Profile, TargetCapabilityFlags}; use qsc_rir::rir::{BlockId, CallableId}; #[test] @@ -393,6 +393,87 @@ fn rotation_call_within_a_for_loop_unrolled() { ); } +#[test] +fn rotation_call_within_a_for_loop() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + for theta in [0.0, 1.0, 2.0] { + Rx(theta, q); + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: __quantum__qis__rx__body + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Jump(1) + Block 1: Block: + Variable(1, Boolean) = Icmp Slt, Variable(0, Integer), Integer(3) + Branch Variable(1, Boolean), 3, 2 + Block 2: Block: + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + Block 3: Block: + Variable(2, Double) = Index Array(0), Variable(0, Integer) + Variable(3, Double) = Store Variable(2, Double) + Call id(2), args( Variable(3, Double), Qubit(0), ) + Variable(4, Integer) = Add Variable(0, Integer), Integer(1) + Variable(0, Integer) = Store Variable(4, Integer) + Jump(1) + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 0 + tags: + [0]: 0_t + array_literals: + [0]: [Double(0), Double(1), Double(2)] + "#]].assert_eq(&program.to_string()); +} + #[test] fn rotation_call_within_a_while_loop_unrolled() { let program = get_rir_program(indoc! { @@ -444,6 +525,519 @@ fn rotation_call_within_a_while_loop_unrolled() { ); } +#[test] +fn nested_loops_over_arrays_of_arrays_unroll_outer_loop() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + let arrays = [[0.0, 1.0], [2.0, 3.0]]; + for arr in arrays { + for theta in arr { + Rx(theta, q); + } + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: __quantum__qis__rx__body + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Variable(1, Integer) = Store Integer(0) + Jump(1) + Block 1: Block: + Variable(2, Boolean) = Icmp Slt, Variable(1, Integer), Integer(2) + Branch Variable(2, Boolean), 3, 2 + Block 2: Block: + Variable(0, Integer) = Store Integer(1) + Variable(6, Integer) = Store Integer(0) + Jump(4) + Block 3: Block: + Variable(3, Double) = Index Array(0), Variable(1, Integer) + Variable(4, Double) = Store Variable(3, Double) + Call id(2), args( Variable(4, Double), Qubit(0), ) + Variable(5, Integer) = Add Variable(1, Integer), Integer(1) + Variable(1, Integer) = Store Variable(5, Integer) + Jump(1) + Block 4: Block: + Variable(7, Boolean) = Icmp Slt, Variable(6, Integer), Integer(2) + Branch Variable(7, Boolean), 6, 5 + Block 5: Block: + Variable(0, Integer) = Store Integer(2) + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + Block 6: Block: + Variable(8, Double) = Index Array(1), Variable(6, Integer) + Variable(9, Double) = Store Variable(8, Double) + Call id(2), args( Variable(9, Double), Qubit(0), ) + Variable(10, Integer) = Add Variable(6, Integer), Integer(1) + Variable(6, Integer) = Store Variable(10, Integer) + Jump(4) + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 0 + tags: + [0]: 0_t + array_literals: + [0]: [Double(0), Double(1)] + [1]: [Double(2), Double(3)] + "#]].assert_eq(&program.to_string()); +} + +// For now, loops over qubits are unrolled since we don't support qubit variables. +#[test] +fn for_loop_over_qubits() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + operation op(q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use qs = Qubit[3]; + for q in qs { + op(q); + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: op + call_type: Regular + input_type: + [0]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Variable(0, Integer) = Store Integer(1) + Variable(0, Integer) = Store Integer(2) + Variable(0, Integer) = Store Integer(3) + Variable(1, Integer) = Store Integer(0) + Call id(2), args( Qubit(0), ) + Variable(1, Integer) = Store Integer(1) + Call id(2), args( Qubit(1), ) + Variable(1, Integer) = Store Integer(2) + Call id(2), args( Qubit(2), ) + Variable(1, Integer) = Store Integer(3) + Variable(2, Integer) = Store Integer(0) + Variable(2, Integer) = Store Integer(1) + Variable(2, Integer) = Store Integer(2) + Variable(2, Integer) = Store Integer(3) + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 3 + num_results: 0 + tags: + [0]: 0_t + "#]].assert_eq(&program.to_string()); +} + +#[test] +fn for_loop_over_qubits_unrolled() { + let program = get_rir_program(indoc! { + r#" + namespace Test { + operation op(q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use qs = Qubit[3]; + for q in qs { + op(q); + } + } + } + "#, + }); + + let op_callable_id = CallableId(1); + assert_callable( + &program, + op_callable_id, + &expect![[r#" + Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: "#]], + ); + assert_block_instructions( + &program, + BlockId(0), + &expect![[r#" + Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Variable(0, Integer) = Store Integer(1) + Variable(0, Integer) = Store Integer(2) + Variable(0, Integer) = Store Integer(3) + Variable(1, Integer) = Store Integer(0) + Call id(2), args( Qubit(0), ) + Variable(1, Integer) = Store Integer(1) + Call id(2), args( Qubit(1), ) + Variable(1, Integer) = Store Integer(2) + Call id(2), args( Qubit(2), ) + Variable(1, Integer) = Store Integer(3) + Variable(2, Integer) = Store Integer(0) + Variable(2, Integer) = Store Integer(1) + Variable(2, Integer) = Store Integer(2) + Variable(2, Integer) = Store Integer(3) + Call id(3), args( Integer(0), Tag(0, 3), ) + Return"#]], + ); +} + +#[test] +fn rotation_call_within_a_while_loop() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + operation rotation(theta : Double, q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + let angles = [0.0, 1.0, 2.0]; + mutable idx = 0; + while idx < 3 { + rotation(angles[idx], q); + set idx += 1; + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: rotation + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Jump(1) + Block 1: Block: + Variable(1, Boolean) = Icmp Slt, Variable(0, Integer), Integer(3) + Branch Variable(1, Boolean), 3, 2 + Block 2: Block: + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + Block 3: Block: + Variable(2, Double) = Index Array(0), Variable(0, Integer) + Call id(2), args( Variable(2, Double), Qubit(0), ) + Variable(3, Integer) = Add Variable(0, Integer), Integer(1) + Variable(0, Integer) = Store Variable(3, Integer) + Jump(1) + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 0 + tags: + [0]: 0_t + array_literals: + [0]: [Double(0), Double(1), Double(2)] + "#]].assert_eq(&program.to_string()); +} + +#[test] +fn rotation_call_within_a_while_loop_index_used_twice() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + operation rotation(theta : Double, q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + let angles = [0.0, 1.0, 2.0]; + mutable idx = 0; + while idx < 3 { + rotation(angles[idx] + angles[idx], q); + set idx += 1; + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: rotation + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Jump(1) + Block 1: Block: + Variable(1, Boolean) = Icmp Slt, Variable(0, Integer), Integer(3) + Branch Variable(1, Boolean), 3, 2 + Block 2: Block: + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + Block 3: Block: + Variable(2, Double) = Index Array(0), Variable(0, Integer) + Variable(3, Double) = Index Array(0), Variable(0, Integer) + Variable(4, Double) = Fadd Variable(2, Double), Variable(3, Double) + Call id(2), args( Variable(4, Double), Qubit(0), ) + Variable(5, Integer) = Add Variable(0, Integer), Integer(1) + Variable(0, Integer) = Store Variable(5, Integer) + Jump(1) + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 0 + tags: + [0]: 0_t + array_literals: + [0]: [Double(0), Double(1), Double(2)] + "#]].assert_eq(&program.to_string()); +} + +#[test] +fn rotation_call_within_a_while_loop_over_dynamic_array() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + operation rotation(theta : Double, q : Qubit) : Unit { body intrinsic; } + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + mutable angles = [0.0, 1.0, 2.0]; + angles[1] = MResetZ(q) == One ? 1.5 | 1.0; + mutable idx = 0; + while idx < 3 { + rotation(angles[idx], q); + set idx += 1; + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: __quantum__qis__mresetz__body + call_type: Measurement + input_type: + [0]: Qubit + [1]: Result + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__read_result + call_type: Readout + input_type: + [0]: Result + output_type: Boolean + body: + Callable 4: Callable: + name: rotation + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 5: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Call id(2), args( Qubit(0), Result(0), ) + Variable(0, Boolean) = Call id(3), args( Result(0), ) + Variable(1, Boolean) = Store Variable(0, Boolean) + Branch Variable(1, Boolean), 2, 3 + Block 1: Block: + Variable(3, Integer) = Store Integer(0) + Call id(4), args( Double(0), Qubit(0), ) + Variable(3, Integer) = Store Integer(1) + Call id(4), args( Variable(2, Double), Qubit(0), ) + Variable(3, Integer) = Store Integer(2) + Call id(4), args( Double(2), Qubit(0), ) + Variable(3, Integer) = Store Integer(3) + Call id(5), args( Integer(0), Tag(0, 3), ) + Return + Block 2: Block: + Variable(2, Double) = Store Double(1.5) + Jump(1) + Block 3: Block: + Variable(2, Double) = Store Double(1) + Jump(1) + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 1 + tags: + [0]: 0_t + "#]].assert_eq(&program.to_string()); +} + #[test] fn rotation_call_within_a_repeat_until_loop_unrolled() { let program = get_rir_program(indoc! { diff --git a/source/compiler/qsc_rca/src/core.rs b/source/compiler/qsc_rca/src/core.rs index 52f250f317..b82db7f95d 100644 --- a/source/compiler/qsc_rca/src/core.rs +++ b/source/compiler/qsc_rca/src/core.rs @@ -759,7 +759,30 @@ impl<'a> Analyzer<'a> { if let ComputeKind::Dynamic { value_kind, .. } = &index_expr_compute_kind && *value_kind == ValueKind::Variable { - let dynamic_runtime_features = RuntimeFeatureFlags::UseOfDynamicIndex; + let mut dynamic_runtime_features = RuntimeFeatureFlags::UseOfDynamicIndex; + + // If the array itself is variable, then we additionally need the runtime feature for a dynamic array. + if array_expr_compute_kind.is_variable_value_kind() { + dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicArray; + } + + match expr_type { + Ty::Param(..) => { + // For generic type parameters, we don't know what features they might require later, so we add the + // `UseOfDynamicGeneric` runtime feature to cover all cases. + dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicGeneric; + } + Ty::Array(_) => { + // If the type of the index expression is an array, we need to add the `UseOfDynamicallySizedArray` + // runtime feature since the result of the index expression can be used in a context that requires array-specific runtime features. + dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicallySizedArray; + } + _ => { + // Other dynamic content types are already handled by the `derive_runtime_features_for_value_kind_associated_to_type` function + // called below, so we don't need to do anything else here. + } + } + let dynamic_runtime_kind = ValueKind::new_variable_from_type(expr_type); compute_kind = compute_kind.aggregate(ComputeKind::Dynamic { runtime_features: dynamic_runtime_features, diff --git a/source/compiler/qsc_rca/src/errors.rs b/source/compiler/qsc_rca/src/errors.rs index be02e5e6f0..14b9249adf 100644 --- a/source/compiler/qsc_rca/src/errors.rs +++ b/source/compiler/qsc_rca/src/errors.rs @@ -97,6 +97,14 @@ pub enum Error { #[diagnostic(code("Qsc.CapabilitiesCk.UseOfDynamicExponent"))] UseOfDynamicExponent(#[label] Span), + #[error("cannot use an array with dynamic contents")] + #[diagnostic(help( + "using an array whose contents depend on a measurement result is not supported by the configured target profile" + ))] + #[diagnostic(url("https://aka.ms/qdk.qir#use-of-dynamic-array"))] + #[diagnostic(code("Qsc.CapabilitiesCk.UseOfDynamicArray"))] + UseOfDynamicArray(#[label] Span), + #[error("cannot use a dynamically-sized array")] #[diagnostic(help( "using an array whose size depends on a measurement result is not supported by the configured target profile" @@ -236,6 +244,14 @@ pub enum Error { #[diagnostic(url("https://aka.ms/qdk.qir#use-of-advanced-output"))] #[diagnostic(code("Qsc.CapabilitiesCk.UseOfAdvancedOutput"))] UseOfAdvancedOutput(#[label] Span), + + #[error("cannot use a dynamic generic parameter")] + #[diagnostic(help( + "using a generic parameter whose resolution depends on a measurement result is not supported by the configured target profile" + ))] + #[diagnostic(url("https://aka.ms/qdk.qir#use-of-dynamic-generic"))] + #[diagnostic(code("Qsc.CapabilitiesCk.UseOfDynamicGeneric"))] + UseOfDynamicGeneric(#[label] Span), } #[must_use] @@ -277,6 +293,9 @@ pub fn generate_errors_from_runtime_features( if runtime_features.contains(RuntimeFeatureFlags::UseOfDynamicExponent) { errors.push(Error::UseOfDynamicExponent(span)); } + if runtime_features.contains(RuntimeFeatureFlags::UseOfDynamicArray) { + errors.push(Error::UseOfDynamicArray(span)); + } if runtime_features.contains(RuntimeFeatureFlags::UseOfDynamicallySizedArray) { errors.push(Error::UseOfDynamicallySizedArray(span)); } @@ -334,6 +353,9 @@ pub fn generate_errors_from_runtime_features( if runtime_features.contains(RuntimeFeatureFlags::CallToCustomReset) { errors.push(Error::CallToCustomReset(span)); } + if runtime_features.contains(RuntimeFeatureFlags::UseOfDynamicGeneric) { + errors.push(Error::UseOfDynamicGeneric(span)); + } errors } diff --git a/source/compiler/qsc_rca/src/lib.rs b/source/compiler/qsc_rca/src/lib.rs index cfa86f5372..9782edef7a 100644 --- a/source/compiler/qsc_rca/src/lib.rs +++ b/source/compiler/qsc_rca/src/lib.rs @@ -618,50 +618,54 @@ bitflags! { const UseOfDynamicBigInt = 1 << 6; /// Use of a dynamic `String`. const UseOfDynamicString = 1 << 7; - /// Use of a dynamic array. - const UseOfDynamicallySizedArray = 1 << 8; + /// Use of a dynamic array with static size. + const UseOfDynamicArray = 1 << 8; + /// Use of a dynamic array with dynamic size. + const UseOfDynamicallySizedArray = 1 << 9; /// Use of a dynamic UDT. - const UseOfDynamicUdt = 1 << 9; + const UseOfDynamicUdt = 1 << 10; /// Use of a dynamic arrow function. - const UseOfDynamicArrowFunction = 1 << 10; + const UseOfDynamicArrowFunction = 1 << 11; /// Use of a dynamic arrow operation. - const UseOfDynamicArrowOperation = 1 << 11; + const UseOfDynamicArrowOperation = 1 << 12; /// A function with cycles used with a dynamic argument. - const CallToCyclicFunctionWithDynamicArg = 1 << 12; + const CallToCyclicFunctionWithDynamicArg = 1 << 13; /// An operation specialization with cycles exists. - const CyclicOperationSpec = 1 << 13; + const CyclicOperationSpec = 1 << 14; /// A call to an operation with cycles. - const CallToCyclicOperation = 1 << 14; + const CallToCyclicOperation = 1 << 15; /// A callee expression is dynamic. - const CallToDynamicCallee = 1 << 15; + const CallToDynamicCallee = 1 << 16; /// A callee expression could not be resolved to a specific callable. - const CallToUnresolvedCallee = 1 << 16; + const CallToUnresolvedCallee = 1 << 17; /// Performing a measurement within a dynamic scope. - const MeasurementWithinDynamicScope = 1 << 17; + const MeasurementWithinDynamicScope = 1 << 18; /// Use of a dynamic index to access or update an array. - const UseOfDynamicIndex = 1 << 18; + const UseOfDynamicIndex = 1 << 19; /// A return expression within a dynamic scope. - const ReturnWithinDynamicScope = 1 << 19; + const ReturnWithinDynamicScope = 1 << 20; /// A loop with a dynamic condition. - const LoopWithDynamicCondition = 1 << 20; + const LoopWithDynamicCondition = 1 << 21; /// Use of an advanced type as output of a computation. - const UseOfAdvancedOutput = 1 << 21; + const UseOfAdvancedOutput = 1 << 22; /// Use of a `Bool` as output of a computation. - const UseOfBoolOutput = 1 << 22; + const UseOfBoolOutput = 1 << 23; /// Use of a `Double` as output of a computation. - const UseOfDoubleOutput = 1 << 23; + const UseOfDoubleOutput = 1 << 24; /// Use of an `Int` as output of a computation. - const UseOfIntOutput = 1 << 24; + const UseOfIntOutput = 1 << 25; /// Use of a dynamic exponent in a computation. - const UseOfDynamicExponent = 1 << 25; + const UseOfDynamicExponent = 1 << 26; /// Use of a dynamic `Result` variable in a computation. - const UseOfDynamicResult = 1 << 26; + const UseOfDynamicResult = 1 << 27; /// Use of a dynamic tuple variable. - const UseOfDynamicTuple = 1 << 27; + const UseOfDynamicTuple = 1 << 28; /// A callee expression to a measurement. - const CallToCustomMeasurement = 1 << 28; + const CallToCustomMeasurement = 1 << 29; /// A callee expression to a reset. - const CallToCustomReset = 1 << 29; + const CallToCustomReset = 1 << 30; + /// Use of a dynamic generic parameter. + const UseOfDynamicGeneric = 1 << 31; } } @@ -707,6 +711,13 @@ impl RuntimeFeatureFlags { if self.contains(RuntimeFeatureFlags::UseOfDynamicString) { capabilities |= TargetCapabilityFlags::HigherLevelConstructs; } + if self.contains(RuntimeFeatureFlags::UseOfDynamicArray) { + // capabilities |= TargetCapabilityFlags::StaticSizedArrays; + + // For now, we are treating any dynamic array as requiriing higher level constructs, + // so that we can reject loops over arrays with dynamic contents. + capabilities |= TargetCapabilityFlags::HigherLevelConstructs; + } if self.contains(RuntimeFeatureFlags::UseOfDynamicallySizedArray) { capabilities |= TargetCapabilityFlags::HigherLevelConstructs; } @@ -735,7 +746,7 @@ impl RuntimeFeatureFlags { capabilities |= TargetCapabilityFlags::Adaptive; } if self.contains(RuntimeFeatureFlags::UseOfDynamicIndex) { - capabilities |= TargetCapabilityFlags::HigherLevelConstructs; + capabilities |= TargetCapabilityFlags::StaticSizedArrays; } if self.contains(RuntimeFeatureFlags::ReturnWithinDynamicScope) { capabilities |= TargetCapabilityFlags::HigherLevelConstructs; @@ -774,6 +785,9 @@ impl RuntimeFeatureFlags { if self.contains(RuntimeFeatureFlags::CallToCustomReset) { capabilities |= TargetCapabilityFlags::Adaptive; } + if self.contains(RuntimeFeatureFlags::UseOfDynamicGeneric) { + capabilities |= TargetCapabilityFlags::HigherLevelConstructs; + } capabilities } diff --git a/source/compiler/qsc_rca/src/tests/loops.rs b/source/compiler/qsc_rca/src/tests/loops.rs index 76d743d187..658415ba24 100644 --- a/source/compiler/qsc_rca/src/tests/loops.rs +++ b/source/compiler/qsc_rca/src/tests/loops.rs @@ -398,7 +398,7 @@ fn check_rca_for_static_for_loop_over_array_with_loop_and_array_support() { &expect![[r#" ApplicationsGeneratorSet: inherent: Dynamic: - runtime_features: RuntimeFeatureFlags(0x0) + runtime_features: RuntimeFeatureFlags(UseOfDynamicInt | UseOfDynamicDouble | UseOfDynamicIndex) value_kind: Constant dynamic_param_applications: "#]], ); diff --git a/source/compiler/qsc_rir/src/builder.rs b/source/compiler/qsc_rir/src/builder.rs index 4bcacf05e0..b1bdcf62c0 100644 --- a/source/compiler/qsc_rir/src/builder.rs +++ b/source/compiler/qsc_rir/src/builder.rs @@ -4,15 +4,15 @@ use qsc_data_structures::target::TargetCapabilityFlags; use crate::rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Program, Ty, - Variable, VariableId, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Prim, + Program, Ty, Variable, VariableId, }; #[must_use] pub fn x_decl() -> Callable { Callable { name: "__quantum__qis__x__body".to_string(), - input_type: vec![Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Regular, @@ -23,7 +23,7 @@ pub fn x_decl() -> Callable { pub fn z_decl() -> Callable { Callable { name: "__quantum__qis__z__body".to_string(), - input_type: vec![Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Regular, @@ -34,7 +34,7 @@ pub fn z_decl() -> Callable { pub fn h_decl() -> Callable { Callable { name: "__quantum__qis__h__body".to_string(), - input_type: vec![Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Regular, @@ -45,7 +45,7 @@ pub fn h_decl() -> Callable { pub fn cx_decl() -> Callable { Callable { name: "__quantum__qis__cx__body".to_string(), - input_type: vec![Ty::Qubit, Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Qubit), Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Regular, @@ -56,7 +56,7 @@ pub fn cx_decl() -> Callable { pub fn rx_decl() -> Callable { Callable { name: "__quantum__qis__rx__body".to_string(), - input_type: vec![Ty::Double, Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Double), Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Regular, @@ -67,7 +67,7 @@ pub fn rx_decl() -> Callable { pub fn m_decl() -> Callable { Callable { name: "__quantum__qis__m__body".to_string(), - input_type: vec![Ty::Qubit, Ty::Result], + input_type: vec![Ty::Prim(Prim::Qubit), Ty::Prim(Prim::Result)], output_type: None, body: None, call_type: CallableType::Measurement, @@ -78,7 +78,7 @@ pub fn m_decl() -> Callable { pub fn mresetz_decl() -> Callable { Callable { name: "__quantum__qis__mresetz__body".to_string(), - input_type: vec![Ty::Qubit, Ty::Result], + input_type: vec![Ty::Prim(Prim::Qubit), Ty::Prim(Prim::Result)], output_type: None, body: None, call_type: CallableType::Measurement, @@ -89,7 +89,7 @@ pub fn mresetz_decl() -> Callable { pub fn reset_decl() -> Callable { Callable { name: "__quantum__qis__reset__body".to_string(), - input_type: vec![Ty::Qubit], + input_type: vec![Ty::Prim(Prim::Qubit)], output_type: None, body: None, call_type: CallableType::Reset, @@ -100,8 +100,8 @@ pub fn reset_decl() -> Callable { pub fn read_result_decl() -> Callable { Callable { name: "__quantum__rt__read_result".to_string(), - input_type: vec![Ty::Result], - output_type: Some(Ty::Boolean), + input_type: vec![Ty::Prim(Prim::Result)], + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Readout, } @@ -111,7 +111,7 @@ pub fn read_result_decl() -> Callable { pub fn initialize_decl() -> Callable { Callable { name: "__quantum__rt__initialize".to_string(), - input_type: vec![Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::Regular, @@ -122,7 +122,7 @@ pub fn initialize_decl() -> Callable { pub fn result_record_decl() -> Callable { Callable { name: "__quantum__rt__result_record_output".to_string(), - input_type: vec![Ty::Result, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Result), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -133,7 +133,7 @@ pub fn result_record_decl() -> Callable { pub fn double_record_decl() -> Callable { Callable { name: "__quantum__rt__double_record_output".to_string(), - input_type: vec![Ty::Double, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Double), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -144,7 +144,7 @@ pub fn double_record_decl() -> Callable { pub fn int_record_decl() -> Callable { Callable { name: "__quantum__rt__int_record_output".to_string(), - input_type: vec![Ty::Integer, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Integer), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -155,7 +155,7 @@ pub fn int_record_decl() -> Callable { pub fn bool_record_decl() -> Callable { Callable { name: "__quantum__rt__bool_record_output".to_string(), - input_type: vec![Ty::Boolean, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Boolean), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -166,7 +166,7 @@ pub fn bool_record_decl() -> Callable { pub fn array_record_decl() -> Callable { Callable { name: "__quantum__rt__array_record_output".to_string(), - input_type: vec![Ty::Integer, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Integer), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -177,7 +177,7 @@ pub fn array_record_decl() -> Callable { pub fn tuple_record_decl() -> Callable { Callable { name: "__quantum__rt__tuple_record_output".to_string(), - input_type: vec![Ty::Integer, Ty::Pointer], + input_type: vec![Ty::Prim(Prim::Integer), Ty::Prim(Prim::Pointer)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -194,7 +194,7 @@ pub fn new_program() -> Program { Callable { name: "main".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Integer), + output_type: Some(Ty::Prim(Prim::Integer)), body: Some(BlockId(0)), call_type: CallableType::Regular, }, @@ -217,7 +217,7 @@ pub fn bell_program() -> Program { Callable { name: "main".to_string(), input_type: vec![], - output_type: Some(Ty::Integer), + output_type: Some(Ty::Prim(Prim::Integer)), body: Some(BlockId(0)), call_type: CallableType::Regular, }, @@ -314,7 +314,7 @@ pub fn teleport_program() -> Program { Callable { name: "main".to_string(), input_type: vec![], - output_type: Some(Ty::Integer), + output_type: Some(Ty::Prim(Prim::Integer)), body: Some(BlockId(0)), call_type: CallableType::Regular, }, @@ -374,14 +374,14 @@ pub fn teleport_program() -> Program { vec![Operand::Literal(Literal::Result(0))], Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -418,14 +418,14 @@ pub fn teleport_program() -> Program { vec![Operand::Literal(Literal::Result(1))], Some(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(4), diff --git a/source/compiler/qsc_rir/src/passes/build_dominator_graph/tests.rs b/source/compiler/qsc_rir/src/passes/build_dominator_graph/tests.rs index 2ad7800c20..cd58a77000 100644 --- a/source/compiler/qsc_rir/src/passes/build_dominator_graph/tests.rs +++ b/source/compiler/qsc_rir/src/passes/build_dominator_graph/tests.rs @@ -7,8 +7,8 @@ use crate::{ builder::new_program, passes::remap_block_ids, rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Program, Ty, Variable, - VariableId, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Prim, Program, Ty, + Variable, VariableId, }, utils::build_predecessors_map, }; @@ -79,7 +79,7 @@ fn dominator_graph_branching_blocks_dominated_by_common_predecessor() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -93,7 +93,7 @@ fn dominator_graph_branching_blocks_dominated_by_common_predecessor() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), @@ -105,7 +105,7 @@ fn dominator_graph_branching_blocks_dominated_by_common_predecessor() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(2), BlockId(3), @@ -157,7 +157,7 @@ fn dominator_graph_branch_and_loop() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -170,7 +170,7 @@ fn dominator_graph_branch_and_loop() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), @@ -182,7 +182,7 @@ fn dominator_graph_branch_and_loop() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(2), BlockId(3), @@ -222,7 +222,7 @@ fn dominator_graph_complex_structure_only_dominated_by_entry() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -241,14 +241,14 @@ fn dominator_graph_complex_structure_only_dominated_by_entry() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(5), BlockId(4), @@ -264,7 +264,7 @@ fn dominator_graph_complex_structure_only_dominated_by_entry() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(2), BlockId(3), @@ -279,7 +279,7 @@ fn dominator_graph_complex_structure_only_dominated_by_entry() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(1), @@ -311,7 +311,7 @@ fn dominator_graph_with_node_having_many_predicates() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -325,14 +325,14 @@ fn dominator_graph_with_node_having_many_predicates() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -345,7 +345,7 @@ fn dominator_graph_with_node_having_many_predicates() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(4), @@ -357,7 +357,7 @@ fn dominator_graph_with_node_having_many_predicates() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(5), BlockId(6), diff --git a/source/compiler/qsc_rir/src/passes/defer_meas/tests.rs b/source/compiler/qsc_rir/src/passes/defer_meas/tests.rs index efc8c0932c..5eed497613 100644 --- a/source/compiler/qsc_rir/src/passes/defer_meas/tests.rs +++ b/source/compiler/qsc_rir/src/passes/defer_meas/tests.rs @@ -6,7 +6,7 @@ use crate::{ builder, rir::{ - Block, BlockId, CallableId, Instruction, Literal, Operand, Program, Ty, Variable, + Block, BlockId, CallableId, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId, }, }; @@ -128,7 +128,7 @@ fn add_simple_measurement_block(program: &mut Program) { CallableId(3), vec![ Operand::Literal(Literal::Integer(3)), - Operand::Literal(Literal::Pointer), + Operand::Literal(Literal::NullPointer), ], None, None, @@ -137,7 +137,7 @@ fn add_simple_measurement_block(program: &mut Program) { CallableId(4), vec![ Operand::Literal(Literal::Result(0)), - Operand::Literal(Literal::Pointer), + Operand::Literal(Literal::NullPointer), ], None, None, @@ -146,7 +146,7 @@ fn add_simple_measurement_block(program: &mut Program) { CallableId(4), vec![ Operand::Literal(Literal::Result(1)), - Operand::Literal(Literal::Pointer), + Operand::Literal(Literal::NullPointer), ], None, None, @@ -155,7 +155,7 @@ fn add_simple_measurement_block(program: &mut Program) { CallableId(4), vec![ Operand::Literal(Literal::Result(2)), - Operand::Literal(Literal::Pointer), + Operand::Literal(Literal::NullPointer), ], None, None, @@ -205,14 +205,14 @@ fn add_branching_measurement_block(program: &mut Program) { vec![Operand::Literal(Literal::Result(0))], Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), diff --git a/source/compiler/qsc_rir/src/passes/insert_alloca_load.rs b/source/compiler/qsc_rir/src/passes/insert_alloca_load.rs index 319f1aded4..1ef4077ee8 100644 --- a/source/compiler/qsc_rir/src/passes/insert_alloca_load.rs +++ b/source/compiler/qsc_rir/src/passes/insert_alloca_load.rs @@ -60,6 +60,7 @@ fn process_callable(program: &mut Program, callable_id: CallableId, next_var_id: entry_block.0 = new_instrs; } +#[allow(clippy::too_many_lines)] fn add_alloca_load_to_block( program: &mut Program, block_id: BlockId, @@ -162,6 +163,24 @@ fn add_alloca_load_to_block( ); } + // For array indexing, the array remains a pointer and does not need to be loaded, but we must + // update the index operand, immediately add the updated instruction, and then load the result. + Instruction::Index(array, operand, variable) => { + *operand = map_or_load_operand( + operand, + &mut var_map, + &mut block.0, + next_var_id, + should_load_operand(operand, vars_to_alloca), + ); + block + .0 + .push(Instruction::Index(*array, *operand, *variable)); + load_from_variable(variable, &mut var_map, &mut block.0, next_var_id); + // Continue here to avoid pushing the instruction again below. + continue; + } + // Phi nodes are handled separately in the SSA transformation, but need to be passed through // like the unconditional terminators. Instruction::Phi(..) | Instruction::Jump(..) | Instruction::Return => {} @@ -209,19 +228,28 @@ fn map_or_load_variable_to_operand( if let Some(operand) = var_map.get(&variable.variable_id) { *operand } else if should_load { - let new_var = Variable { - variable_id: *next_var_id, - ty: variable.ty, - }; - instrs.push(Instruction::Load(variable, new_var)); - var_map.insert(variable.variable_id, Operand::Variable(new_var)); - *next_var_id = next_var_id.successor(); - Operand::Variable(new_var) + load_from_variable(&variable, var_map, instrs, next_var_id) } else { Operand::Variable(variable) } } +fn load_from_variable( + variable: &Variable, + var_map: &mut FxHashMap, + instrs: &mut Vec, + next_var_id: &mut VariableId, +) -> Operand { + let new_var = Variable { + variable_id: *next_var_id, + ty: variable.ty, + }; + instrs.push(Instruction::Load(*variable, new_var)); + var_map.insert(variable.variable_id, Operand::Variable(new_var)); + *next_var_id = next_var_id.successor(); + Operand::Variable(new_var) +} + fn map_or_load_variable( variable: Variable, var_map: &mut FxHashMap, diff --git a/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs b/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs index c3e42f1dad..60222d3db4 100644 --- a/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs +++ b/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs @@ -33,11 +33,21 @@ fn process_callable(program: &mut Program, callable_id: CallableId) { while let Some(block_id) = blocks_to_visit.pop() { visited_blocks.insert(block_id); let mut used_vars_in_block = FxHashSet::default(); + let mut gep_vars_in_block = FxHashSet::default(); let stored_vars_before_block = stored_vars.clone(); - check_var_usage(program, block_id, &mut stored_vars, &mut used_vars_in_block); + check_var_usage( + program, + block_id, + &mut stored_vars, + &mut used_vars_in_block, + &mut gep_vars_in_block, + ); for var in used_vars_in_block { - if !used_vars.insert(var) || stored_vars_before_block.contains(&var) { + if !used_vars.insert(var) + || stored_vars_before_block.contains(&var) + || gep_vars_in_block.contains(&var) + { // This variable was already marked as used, which means it is used cross-block. // Alternatively, the variable was stored before this block and is used here. // Either means we shouldn't try to transform stores to this variable away. @@ -94,6 +104,7 @@ fn check_var_usage( block_id: crate::rir::BlockId, stored_vars: &mut FxHashSet, used_vars: &mut FxHashSet, + gep_vars: &mut FxHashSet, ) { let block = program.get_block(block_id); for instr in &block.0 { @@ -161,6 +172,20 @@ fn check_var_usage( ); used_vars.insert(variable.variable_id); } + Instruction::Index(gep_operand, operand, variable2) => { + if let crate::rir::Operand::Variable(var) = operand { + used_vars.insert(var.variable_id); + } + if let crate::rir::Operand::Variable(var) = gep_operand { + used_vars.insert(var.variable_id); + gep_vars.insert(var.variable_id); + } + assert!( + !stored_vars.contains(&variable2.variable_id), + "index instructions should not use stored variables for capturing return values" + ); + used_vars.insert(variable2.variable_id); + } Instruction::Load(..) => { panic!("loads should not be present during store pruning") diff --git a/source/compiler/qsc_rir/src/passes/reindex_qubits/tests.rs b/source/compiler/qsc_rir/src/passes/reindex_qubits/tests.rs index 835aaee41d..aa271e92cf 100644 --- a/source/compiler/qsc_rir/src/passes/reindex_qubits/tests.rs +++ b/source/compiler/qsc_rir/src/passes/reindex_qubits/tests.rs @@ -8,7 +8,7 @@ use expect_test::expect; use crate::{ builder::{cx_decl, h_decl, m_decl, mresetz_decl, read_result_decl, reset_decl, x_decl}, rir::{ - Block, BlockId, CallableId, CallableType, Instruction, Literal, Operand, Program, Ty, + Block, BlockId, CallableId, CallableType, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId, }, }; @@ -394,14 +394,14 @@ fn qubit_reindexed_across_branches() { vec![Operand::Literal(Literal::Result(0))], Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), diff --git a/source/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs b/source/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs index e0618e31ee..71bee0914a 100644 --- a/source/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs +++ b/source/compiler/qsc_rir/src/passes/remap_block_ids/tests.rs @@ -6,7 +6,7 @@ use expect_test::expect; use crate::rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Program, Ty, Variable, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Prim, Program, Ty, Variable, VariableId, }; @@ -182,7 +182,7 @@ fn remap_block_ids_out_of_order_with_one_branch() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(1), @@ -275,7 +275,7 @@ fn remap_block_ids_simple_loop() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(6), BlockId(2), @@ -431,7 +431,7 @@ fn remap_block_ids_nested_branching_loops() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(6), BlockId(2), @@ -443,7 +443,7 @@ fn remap_block_ids_nested_branching_loops() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(4), BlockId(2), @@ -527,7 +527,7 @@ fn remap_block_ids_ensures_acyclic_program_gets_topological_ordering() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(6), BlockId(2), @@ -542,7 +542,7 @@ fn remap_block_ids_ensures_acyclic_program_gets_topological_ordering() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(3), @@ -557,7 +557,7 @@ fn remap_block_ids_ensures_acyclic_program_gets_topological_ordering() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(5), BlockId(0), diff --git a/source/compiler/qsc_rir/src/passes/simplify_control_flow/tests.rs b/source/compiler/qsc_rir/src/passes/simplify_control_flow/tests.rs index bed58f09f9..d4a40577c6 100644 --- a/source/compiler/qsc_rir/src/passes/simplify_control_flow/tests.rs +++ b/source/compiler/qsc_rir/src/passes/simplify_control_flow/tests.rs @@ -7,7 +7,7 @@ use expect_test::expect; use crate::{ builder::{bell_program, teleport_program}, - rir::{Block, BlockId, Instruction, Literal, Operand, Program, Ty, Variable, VariableId}, + rir::{Block, BlockId, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId}, }; use super::simplify_control_flow; @@ -38,7 +38,7 @@ fn simplify_control_flow_removes_single_redundant_block() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(1)), @@ -51,7 +51,7 @@ fn simplify_control_flow_removes_single_redundant_block() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -108,7 +108,7 @@ fn simplify_control_flow_removes_multiple_redundant_blocks() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(1)), @@ -121,7 +121,7 @@ fn simplify_control_flow_removes_multiple_redundant_blocks() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(2)), @@ -134,7 +134,7 @@ fn simplify_control_flow_removes_multiple_redundant_blocks() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -195,13 +195,13 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(6), @@ -216,7 +216,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(2)), @@ -229,7 +229,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(4)), @@ -242,7 +242,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -255,7 +255,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(7)), @@ -268,7 +268,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_branches() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -351,13 +351,13 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(0), BlockId(2), @@ -372,7 +372,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(1)), @@ -385,7 +385,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(4)), @@ -398,7 +398,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(2)), @@ -411,7 +411,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(5)), @@ -424,7 +424,7 @@ fn simplify_control_flow_removes_redundant_blocks_across_out_of_order_branches() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, diff --git a/source/compiler/qsc_rir/src/passes/ssa_check.rs b/source/compiler/qsc_rir/src/passes/ssa_check.rs index efb7b95c52..5f3c453503 100644 --- a/source/compiler/qsc_rir/src/passes/ssa_check.rs +++ b/source/compiler/qsc_rir/src/passes/ssa_check.rs @@ -227,7 +227,7 @@ fn get_variable_uses(program: &Program) -> IndexMap { + Instruction::Alloca(..) | Instruction::Load(..) | Instruction::Index(..) => { panic!("Unexpected advanced instruction at {block_id:?}, instruction {idx}") } } diff --git a/source/compiler/qsc_rir/src/passes/ssa_check/tests.rs b/source/compiler/qsc_rir/src/passes/ssa_check/tests.rs index 428ddb48a9..0c3babf6e0 100644 --- a/source/compiler/qsc_rir/src/passes/ssa_check/tests.rs +++ b/source/compiler/qsc_rir/src/passes/ssa_check/tests.rs @@ -7,8 +7,8 @@ use crate::{ builder::{bell_program, new_program, teleport_program}, passes::{build_dominator_graph, remap_block_ids}, rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Program, - Ty, Variable, VariableId, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Prim, + Program, Ty, Variable, VariableId, }, utils::build_predecessors_map, }; @@ -50,7 +50,7 @@ fn ssa_check_fails_for_instruction_on_literal_values() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -73,21 +73,21 @@ fn ssa_check_fails_for_use_before_assignment_in_single_block() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -108,21 +108,21 @@ fn ssa_check_fails_for_use_without_assignment_in_single_block() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -145,11 +145,11 @@ fn ssa_check_fails_for_use_before_assignment_across_sequential_blocks() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(1)), @@ -162,11 +162,11 @@ fn ssa_check_fails_for_use_before_assignment_across_sequential_blocks() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -187,21 +187,21 @@ fn ssa_check_fails_for_multiple_assignment_in_single_block() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -219,7 +219,7 @@ fn ssa_check_passes_for_variable_that_dominates_usage() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -233,14 +233,14 @@ fn ssa_check_passes_for_variable_that_dominates_usage() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -255,11 +255,11 @@ fn ssa_check_passes_for_variable_that_dominates_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -272,11 +272,11 @@ fn ssa_check_passes_for_variable_that_dominates_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -301,7 +301,7 @@ fn ssa_check_fails_when_definition_does_not_dominates_usage() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -315,14 +315,14 @@ fn ssa_check_fails_when_definition_does_not_dominates_usage() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -337,11 +337,11 @@ fn ssa_check_fails_when_definition_does_not_dominates_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -354,11 +354,11 @@ fn ssa_check_fails_when_definition_does_not_dominates_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -371,11 +371,11 @@ fn ssa_check_fails_when_definition_does_not_dominates_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -393,7 +393,7 @@ fn ssa_check_succeeds_when_phi_handles_multiple_values_from_branches() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -407,14 +407,14 @@ fn ssa_check_succeeds_when_phi_handles_multiple_values_from_branches() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -429,11 +429,11 @@ fn ssa_check_succeeds_when_phi_handles_multiple_values_from_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -446,11 +446,11 @@ fn ssa_check_succeeds_when_phi_handles_multiple_values_from_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -465,31 +465,31 @@ fn ssa_check_succeeds_when_phi_handles_multiple_values_from_branches() { ( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), ), ( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(2), ), ], Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -507,7 +507,7 @@ fn ssa_check_succeeds_when_phi_handles_value_from_dominator_of_predecessor() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -521,14 +521,14 @@ fn ssa_check_succeeds_when_phi_handles_value_from_dominator_of_predecessor() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -543,11 +543,11 @@ fn ssa_check_succeeds_when_phi_handles_value_from_dominator_of_predecessor() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -560,11 +560,11 @@ fn ssa_check_succeeds_when_phi_handles_value_from_dominator_of_predecessor() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(4)), @@ -583,31 +583,31 @@ fn ssa_check_succeeds_when_phi_handles_value_from_dominator_of_predecessor() { ( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), ), ( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(4), ), ], Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -628,7 +628,7 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -642,14 +642,14 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -664,11 +664,11 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -681,17 +681,17 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(4), BlockId(5), @@ -710,11 +710,11 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -733,31 +733,31 @@ fn ssa_check_fails_when_phi_handles_value_from_non_dominator_of_predecessor() { ( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), ), ( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(6), ), ], Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -776,7 +776,7 @@ fn ssa_check_fails_when_phi_lists_non_predecessor_block() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -790,14 +790,14 @@ fn ssa_check_fails_when_phi_lists_non_predecessor_block() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -812,11 +812,11 @@ fn ssa_check_fails_when_phi_lists_non_predecessor_block() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -829,11 +829,11 @@ fn ssa_check_fails_when_phi_lists_non_predecessor_block() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -848,31 +848,31 @@ fn ssa_check_fails_when_phi_lists_non_predecessor_block() { ( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(0), ), ( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), ), ], Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -891,7 +891,7 @@ fn ssa_check_fails_when_phi_assigns_to_itself() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -905,14 +905,14 @@ fn ssa_check_fails_when_phi_assigns_to_itself() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -927,11 +927,11 @@ fn ssa_check_fails_when_phi_assigns_to_itself() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -944,11 +944,11 @@ fn ssa_check_fails_when_phi_assigns_to_itself() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -963,31 +963,31 @@ fn ssa_check_fails_when_phi_assigns_to_itself() { ( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), ), ( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(2), ), ], Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), ]), @@ -1005,7 +1005,7 @@ fn ssa_check_fails_when_phi_blocks_have_different_predecessors() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -1019,14 +1019,14 @@ fn ssa_check_fails_when_phi_blocks_have_different_predecessors() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -1041,11 +1041,11 @@ fn ssa_check_fails_when_phi_blocks_have_different_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -1058,11 +1058,11 @@ fn ssa_check_fails_when_phi_blocks_have_different_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -1076,23 +1076,23 @@ fn ssa_check_fails_when_phi_blocks_have_different_predecessors() { vec![( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), BlockId(1), )], Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, diff --git a/source/compiler/qsc_rir/src/passes/ssa_transform/tests.rs b/source/compiler/qsc_rir/src/passes/ssa_transform/tests.rs index 160b9ee862..cbba46a44e 100644 --- a/source/compiler/qsc_rir/src/passes/ssa_transform/tests.rs +++ b/source/compiler/qsc_rir/src/passes/ssa_transform/tests.rs @@ -10,8 +10,8 @@ use crate::{ builder::{bell_program, new_program, teleport_program}, passes::check_and_transform, rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Program, - Ty, Variable, VariableId, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Prim, + Program, Ty, Variable, VariableId, }, }; fn transform_program(program: &mut Program) { @@ -47,7 +47,7 @@ fn ssa_transform_removes_store_in_single_block_program() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -61,28 +61,28 @@ fn ssa_transform_removes_store_in_single_block_program() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -160,7 +160,7 @@ fn ssa_transform_removes_multiple_stores_in_single_block_program() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -174,68 +174,68 @@ fn ssa_transform_removes_multiple_stores_in_single_block_program() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -319,7 +319,7 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -333,24 +333,24 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -364,11 +364,11 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -380,11 +380,11 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -396,11 +396,11 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -495,7 +495,7 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks_without_i Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -509,24 +509,24 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks_without_i Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -546,11 +546,11 @@ fn ssa_transform_store_dominating_usage_propagates_to_successor_blocks_without_i Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -640,7 +640,7 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -654,24 +654,24 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -685,21 +685,21 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -711,21 +711,21 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -737,11 +737,11 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -837,7 +837,7 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -851,24 +851,24 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -882,21 +882,21 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -911,11 +911,11 @@ fn ssa_transform_inserts_phi_for_store_not_dominating_usage_in_one_branch() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -1008,7 +1008,7 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -1022,24 +1022,24 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -1053,27 +1053,27 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(4), @@ -1087,27 +1087,27 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(5), BlockId(6), @@ -1130,21 +1130,21 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(7)), @@ -1156,11 +1156,11 @@ fn ssa_transform_inserts_phi_for_node_with_many_predecessors() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -1275,7 +1275,7 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -1289,34 +1289,34 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -1330,21 +1330,21 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -1356,21 +1356,21 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -1382,21 +1382,21 @@ fn ssa_transform_inserts_phi_for_multiple_stored_values() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(6), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -1496,7 +1496,7 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -1510,24 +1510,24 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -1541,27 +1541,27 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(4), @@ -1575,21 +1575,21 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(5)), @@ -1601,21 +1601,21 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -1627,21 +1627,21 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -1653,21 +1653,21 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(6), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(6), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(7)), @@ -1679,21 +1679,21 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(7), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(7), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(7)), @@ -1705,11 +1705,11 @@ fn ssa_transform_inserts_phi_nodes_in_successive_blocks_for_chained_branches() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(8), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -1832,7 +1832,7 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -1846,24 +1846,24 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -1877,21 +1877,21 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -1903,27 +1903,27 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(4), BlockId(5), @@ -1937,11 +1937,11 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -1953,21 +1953,21 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -1979,21 +1979,21 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(6), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(6), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(6)), @@ -2005,11 +2005,11 @@ fn ssa_transform_inerts_phi_nodes_for_early_return_graph_pattern() { Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(7), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(3)), @@ -2126,7 +2126,7 @@ fn ssa_transform_propagates_updates_from_multiple_predecessors_to_later_single_s Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -2145,24 +2145,24 @@ fn ssa_transform_propagates_updates_from_multiple_predecessors_to_later_single_s Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -2181,24 +2181,24 @@ fn ssa_transform_propagates_updates_from_multiple_predecessors_to_later_single_s Vec::new(), Some(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(3), BlockId(4), @@ -2300,7 +2300,7 @@ fn ssa_transform_maps_store_instrs_that_use_values_from_other_store_instrs() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -2314,38 +2314,38 @@ fn ssa_transform_maps_store_instrs_that_use_values_from_other_store_instrs() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -2423,7 +2423,7 @@ fn ssa_transform_maps_store_with_variable_from_store_in_conditional_to_phi_node( Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -2437,31 +2437,31 @@ fn ssa_transform_maps_store_with_variable_from_store_in_conditional_to_phi_node( Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -2475,11 +2475,11 @@ fn ssa_transform_maps_store_with_variable_from_store_in_conditional_to_phi_node( Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(2)), @@ -2491,11 +2491,11 @@ fn ssa_transform_maps_store_with_variable_from_store_in_conditional_to_phi_node( Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -2583,7 +2583,7 @@ fn ssa_transform_allows_point_in_time_copy_of_dynamic_variable() { Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -2597,68 +2597,68 @@ fn ssa_transform_allows_point_in_time_copy_of_dynamic_variable() { Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(4), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::LogicalNot( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(5), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -2741,7 +2741,7 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch Callable { name: "dynamic_bool".to_string(), input_type: Vec::new(), - output_type: Some(Ty::Boolean), + output_type: Some(Ty::Prim(Prim::Boolean)), body: None, call_type: CallableType::Regular, }, @@ -2750,7 +2750,7 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch CallableId(2), Callable { name: "record_bool".to_string(), - input_type: vec![Ty::Boolean], + input_type: vec![Ty::Prim(Prim::Boolean)], output_type: None, body: None, call_type: CallableType::OutputRecording, @@ -2765,7 +2765,7 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch Vec::new(), Some(Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), @@ -2773,13 +2773,13 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -2793,17 +2793,17 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Branch( Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(4), BlockId(5), @@ -2819,18 +2819,18 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch Vec::new(), Some(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), Instruction::Store( Operand::Variable(Variable { variable_id: VariableId(2), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Jump(BlockId(1)), @@ -2843,7 +2843,7 @@ fn ssa_transform_propagates_phi_var_to_successor_blocks_across_sequential_branch CallableId(2), vec![Operand::Variable(Variable { variable_id: VariableId(3), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), })], None, None, diff --git a/source/compiler/qsc_rir/src/passes/type_check.rs b/source/compiler/qsc_rir/src/passes/type_check.rs index e5d048ef21..5a7c611617 100644 --- a/source/compiler/qsc_rir/src/passes/type_check.rs +++ b/source/compiler/qsc_rir/src/passes/type_check.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -use crate::rir::{Callable, Instruction, Operand, Program, Ty, Variable}; +use crate::rir::{Callable, Instruction, Literal, Operand, Prim, Program, Ty, Variable}; #[cfg(test)] mod tests; @@ -20,7 +20,7 @@ fn check_instr_types(program: &Program, instr: &Instruction) { check_call_types(program.get_callable(*id), args, *var); } - Instruction::Branch(var, _, _, _) => assert_eq!(var.ty, Ty::Boolean), + Instruction::Branch(var, _, _, _) => assert_eq!(var.ty, Ty::Prim(Prim::Boolean)), Instruction::Add(opr1, opr2, var) | Instruction::Sub(opr1, opr2, var) @@ -44,7 +44,7 @@ fn check_instr_types(program: &Program, instr: &Instruction) { Instruction::Fcmp(_, opr1, opr2, var) | Instruction::Icmp(_, opr1, opr2, var) => { assert_eq!(opr1.get_type(), opr2.get_type()); - assert_eq!(Ty::Boolean, var.ty); + assert_eq!(Ty::Prim(Prim::Boolean), var.ty); } Instruction::Store(opr, var) @@ -59,6 +59,27 @@ fn check_instr_types(program: &Program, instr: &Instruction) { } } + Instruction::Index(array, index, var) => { + match array { + Operand::Literal(Literal::Array(global_idx)) => { + let Some(array_literal) = program.array_literals.get(*global_idx) else { + panic!("array literal index {global_idx} is out of bounds"); + }; + assert_eq!(Ty::Prim(array_literal.ty), var.ty); + } + Operand::Variable(Variable { + ty: Ty::Array(_, elem_ty), + .. + }) => { + assert_eq!(Ty::Prim(*elem_ty), var.ty); + } + _ => panic!( + "expected array operand to be either a global array literal or an array variable" + ), + } + assert_eq!(index.get_type(), Ty::Prim(Prim::Integer)); + } + Instruction::Convert(_, _) | Instruction::Jump(_) | Instruction::Alloca(..) diff --git a/source/compiler/qsc_rir/src/passes/type_check/tests.rs b/source/compiler/qsc_rir/src/passes/type_check/tests.rs index 654e83c9a9..c7415c3ebc 100644 --- a/source/compiler/qsc_rir/src/passes/type_check/tests.rs +++ b/source/compiler/qsc_rir/src/passes/type_check/tests.rs @@ -2,7 +2,7 @@ // Licensed under the MIT License. use crate::rir::{ - BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Program, Ty, + BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Prim, Program, Ty, Variable, VariableId, }; @@ -12,7 +12,7 @@ use super::check_instr_types; fn binop_instr_matching_types_passes_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr1 = Operand::Variable(var); let opr2 = Operand::Literal(Literal::Integer(0)); @@ -25,7 +25,7 @@ fn binop_instr_matching_types_passes_check() { fn binop_instr_mismatching_types_fails_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr1 = Operand::Variable(var); let opr2 = Operand::Literal(Literal::Bool(false)); @@ -37,7 +37,7 @@ fn binop_instr_mismatching_types_fails_check() { fn unop_instr_matching_types_passes_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }; let opr = Operand::Variable(var); @@ -49,7 +49,7 @@ fn unop_instr_matching_types_passes_check() { fn unop_instr_mismatching_types_fails_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -59,7 +59,7 @@ fn unop_instr_mismatching_types_fails_check() { opr, Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), ); @@ -69,7 +69,7 @@ fn unop_instr_mismatching_types_fails_check() { fn phi_instr_matching_types_passes_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -84,7 +84,7 @@ fn phi_instr_matching_types_passes_check() { fn phi_instr_mismatching_types_fails_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -94,7 +94,7 @@ fn phi_instr_mismatching_types_fails_check() { vec![(opr, BlockId(0)), (opr, BlockId(1))], Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), ); @@ -104,7 +104,7 @@ fn phi_instr_mismatching_types_fails_check() { fn call_instr_matching_types_passes_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -113,8 +113,8 @@ fn call_instr_matching_types_passes_check() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], - output_type: Some(Ty::Integer), + input_type: vec![Ty::Prim(Prim::Integer)], + output_type: Some(Ty::Prim(Prim::Integer)), call_type: CallableType::Regular, body: None, }, @@ -127,7 +127,7 @@ fn call_instr_matching_types_passes_check() { vec![opr], Some(Variable { variable_id: VariableId(1), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }), None, ), @@ -139,7 +139,7 @@ fn call_instr_matching_types_passes_check() { fn call_instr_mismatching_output_types_fails_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -148,8 +148,8 @@ fn call_instr_mismatching_output_types_fails_check() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], - output_type: Some(Ty::Integer), + input_type: vec![Ty::Prim(Prim::Integer)], + output_type: Some(Ty::Prim(Prim::Integer)), call_type: CallableType::Regular, body: None, }, @@ -162,7 +162,7 @@ fn call_instr_mismatching_output_types_fails_check() { vec![opr], Some(Variable { variable_id: VariableId(1), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }), None, ), @@ -177,8 +177,8 @@ fn call_instr_mismatching_input_types_fails_check() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], - output_type: Some(Ty::Integer), + input_type: vec![Ty::Prim(Prim::Integer)], + output_type: Some(Ty::Prim(Prim::Integer)), call_type: CallableType::Regular, body: None, }, @@ -191,7 +191,7 @@ fn call_instr_mismatching_input_types_fails_check() { vec![Operand::Literal(Literal::Bool(true))], Some(Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }), None, ), @@ -203,7 +203,7 @@ fn call_instr_mismatching_input_types_fails_check() { fn call_instr_too_many_args_fails_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -212,8 +212,8 @@ fn call_instr_too_many_args_fails_check() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], - output_type: Some(Ty::Integer), + input_type: vec![Ty::Prim(Prim::Integer)], + output_type: Some(Ty::Prim(Prim::Integer)), call_type: CallableType::Regular, body: None, }, @@ -226,7 +226,7 @@ fn call_instr_too_many_args_fails_check() { vec![opr, opr], Some(Variable { variable_id: VariableId(1), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }), None, ), @@ -237,7 +237,7 @@ fn call_instr_too_many_args_fails_check() { fn call_instr_no_return_type_no_output_var_passes_check() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -246,7 +246,7 @@ fn call_instr_no_return_type_no_output_var_passes_check() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], + input_type: vec![Ty::Prim(Prim::Integer)], output_type: None, call_type: CallableType::Regular, body: None, @@ -266,7 +266,7 @@ fn call_instr_no_return_type_no_output_var_passes_check() { fn call_instr_return_type_without_output_var_fails() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -275,8 +275,8 @@ fn call_instr_return_type_without_output_var_fails() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], - output_type: Some(Ty::Integer), + input_type: vec![Ty::Prim(Prim::Integer)], + output_type: Some(Ty::Prim(Prim::Integer)), call_type: CallableType::Regular, body: None, }, @@ -295,7 +295,7 @@ fn call_instr_return_type_without_output_var_fails() { fn call_instr_output_var_without_return_type_fails() { let var = Variable { variable_id: VariableId(0), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }; let opr = Operand::Variable(var); @@ -304,7 +304,7 @@ fn call_instr_output_var_without_return_type_fails() { CallableId(0), Callable { name: "foo".to_string(), - input_type: vec![Ty::Integer], + input_type: vec![Ty::Prim(Prim::Integer)], output_type: None, call_type: CallableType::Regular, body: None, @@ -318,7 +318,7 @@ fn call_instr_output_var_without_return_type_fails() { vec![opr], Some(Variable { variable_id: VariableId(1), - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), }), None, ), diff --git a/source/compiler/qsc_rir/src/passes/unreachable_code_check/tests.rs b/source/compiler/qsc_rir/src/passes/unreachable_code_check/tests.rs index 9ae2d42cba..83e1a279da 100644 --- a/source/compiler/qsc_rir/src/passes/unreachable_code_check/tests.rs +++ b/source/compiler/qsc_rir/src/passes/unreachable_code_check/tests.rs @@ -2,8 +2,8 @@ // Licensed under the MIT License. use crate::rir::{ - Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Program, Ty, - Variable, VariableId, + Block, BlockId, Callable, CallableId, CallableType, Instruction, Literal, Operand, Prim, + Program, Ty, Variable, VariableId, }; use super::{check_unreachable_blocks, check_unreachable_callable, check_unreachable_instrs}; @@ -18,7 +18,7 @@ fn test_check_unreachable_instrs_panics_on_missing_terminator() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, )]), ); @@ -44,7 +44,7 @@ fn test_check_unreachable_instrs_succeeds_on_terminator_after_other_instrs() { Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), Instruction::Return, @@ -65,7 +65,7 @@ fn test_check_unreachable_instrs_panics_on_unreachable_instrs_after_terminator() Operand::Literal(Literal::Bool(true)), Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, ), ]), @@ -133,7 +133,7 @@ fn test_check_unreachable_blocks_succeeds_on_no_unreachable_blocks_with_branch() Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(2), @@ -190,7 +190,7 @@ fn test_check_unreachable_blocks_panics_on_unreachable_block_with_branch() { Block(vec![Instruction::Branch( Variable { variable_id: VariableId(0), - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), }, BlockId(1), BlockId(1), diff --git a/source/compiler/qsc_rir/src/rir.rs b/source/compiler/qsc_rir/src/rir.rs index c2321d7900..1e61e73bda 100644 --- a/source/compiler/qsc_rir/src/rir.rs +++ b/source/compiler/qsc_rir/src/rir.rs @@ -17,6 +17,7 @@ pub struct Program { pub num_results: u32, pub attrs: Attributes, pub tags: Vec, + pub array_literals: Vec, pub dbg_info: DbgInfo, } @@ -49,6 +50,14 @@ impl Display for Program { for (idx, tag) in self.tags.iter().enumerate() { writeln!(indent, "[{idx}]: {tag}")?; } + indent = set_indentation(indent, 1); + if !self.array_literals.is_empty() { + writeln!(indent, "array_literals:")?; + indent = set_indentation(indent, 2); + for (idx, array) in self.array_literals.iter().enumerate() { + writeln!(indent, "[{idx}]: {array}")?; + } + } Ok(()) } } @@ -383,6 +392,7 @@ pub enum Instruction { Convert(Operand, Variable), Load(Variable, Variable), Alloca(Variable), + Index(Operand, Operand, Variable), Return, } @@ -481,6 +491,10 @@ impl Display for Instruction { let mut indent = set_indentation(indented(f), 0); write!(indent, "{variable} = Alloca")?; } + Self::Index(array_var, index_opr, result_var) => { + let mut indent = set_indentation(indented(f), 0); + write!(indent, "{result_var} = Index {array_var}, {index_opr}")?; + } Self::Return => write!(f, "Return")?, } Ok(()) @@ -528,7 +542,7 @@ impl Variable { pub fn new_boolean(id: VariableId) -> Self { Self { variable_id: id, - ty: Ty::Boolean, + ty: Ty::Prim(Prim::Boolean), } } @@ -536,7 +550,7 @@ impl Variable { pub fn new_integer(id: VariableId) -> Self { Self { variable_id: id, - ty: Ty::Integer, + ty: Ty::Prim(Prim::Integer), } } @@ -544,7 +558,7 @@ impl Variable { pub fn new_double(id: VariableId) -> Self { Self { variable_id: id, - ty: Ty::Double, + ty: Ty::Prim(Prim::Double), } } @@ -552,13 +566,29 @@ impl Variable { pub fn new_ptr(id: VariableId) -> Self { Self { variable_id: id, - ty: Ty::Pointer, + ty: Ty::Prim(Prim::Pointer), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Ty { + Prim(Prim), + Array(usize, Prim), +} + +impl Display for Ty { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match &self { + Ty::Prim(prim) => write!(f, "{prim}")?, + Ty::Array(size, prim) => write!(f, "Array({size}, {prim})")?, + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Prim { Qubit, Result, Boolean, @@ -567,7 +597,7 @@ pub enum Ty { Pointer, } -impl Display for Ty { +impl Display for Prim { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match &self { Self::Qubit => write!(f, "Qubit")?, @@ -601,12 +631,14 @@ impl Operand { pub fn get_type(&self) -> Ty { match self { Operand::Literal(lit) => match lit { - Literal::Qubit(_) => Ty::Qubit, - Literal::Result(_) => Ty::Result, - Literal::Bool(_) => Ty::Boolean, - Literal::Integer(_) => Ty::Integer, - Literal::Double(_) => Ty::Double, - Literal::Pointer | Literal::Tag(..) => Ty::Pointer, + Literal::Qubit(_) => Ty::Prim(Prim::Qubit), + Literal::Result(_) => Ty::Prim(Prim::Result), + Literal::Bool(_) => Ty::Prim(Prim::Boolean), + Literal::Integer(_) => Ty::Prim(Prim::Integer), + Literal::Double(_) => Ty::Prim(Prim::Double), + Literal::NullPointer | Literal::Tag(..) | Literal::Array(_) => { + Ty::Prim(Prim::Pointer) + } }, Operand::Variable(var) => var.ty, } @@ -621,7 +653,8 @@ pub enum Literal { Integer(i64), Double(f64), Tag(usize, usize), - Pointer, + Array(usize), + NullPointer, } impl Display for Literal { @@ -633,7 +666,8 @@ impl Display for Literal { Self::Integer(i) => write!(f, "Integer({i})")?, Self::Double(d) => write!(f, "Double({d})")?, Self::Tag(idx, len) => write!(f, "Tag({idx}, {len})")?, - Self::Pointer => write!(f, "Pointer")?, + Self::Array(idx) => write!(f, "Array({idx})")?, + Self::NullPointer => write!(f, "Pointer")?, } Ok(()) } @@ -665,7 +699,7 @@ impl PartialEq for Literal { false } } - Self::Pointer => matches!(other, Self::Pointer), + Self::NullPointer => matches!(other, Self::NullPointer), Self::Qubit(self_qubit) => { if let Self::Qubit(other_qubit) = other { self_qubit == other_qubit @@ -687,12 +721,45 @@ impl PartialEq for Literal { false } } + Self::Array(self_idx) => { + if let Self::Array(other_idx) = other { + self_idx == other_idx + } else { + false + } + } } } } impl Eq for Literal {} +#[derive(Clone, Debug)] +pub struct ArrayLiteral { + pub contents: Vec, + pub ty: Prim, +} + +impl Display for ArrayLiteral { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "[")?; + for (index, literal) in self.contents.iter().enumerate() { + write!(f, "{literal}")?; + if index != self.contents.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, "]")?; + Ok(()) + } +} + +impl PartialEq for ArrayLiteral { + fn eq(&self, other: &Self) -> bool { + self.ty == other.ty && self.contents == other.contents + } +} + fn set_indentation<'a, 'b>( indent: Indented<'a, Formatter<'b>>, level: usize, diff --git a/source/compiler/qsc_rir/src/utils.rs b/source/compiler/qsc_rir/src/utils.rs index f5e2420c15..6c777b8ca9 100644 --- a/source/compiler/qsc_rir/src/utils.rs +++ b/source/compiler/qsc_rir/src/utils.rs @@ -110,7 +110,8 @@ pub fn get_variable_assignments(program: &Program) -> IndexMap { + | Instruction::Load(_, var) + | Instruction::Index(_, _, var) => { has_store = true; assignments.insert(var.variable_id, (block_id, idx)); } @@ -198,7 +199,8 @@ pub(crate) fn map_variable_use_in_block( | Instruction::LogicalOr(lhs, rhs, _) | Instruction::BitwiseAnd(lhs, rhs, _) | Instruction::BitwiseOr(lhs, rhs, _) - | Instruction::BitwiseXor(lhs, rhs, _) => { + | Instruction::BitwiseXor(lhs, rhs, _) + | Instruction::Index(lhs, rhs, _) => { *lhs = lhs.mapped(var_map); *rhs = rhs.mapped(var_map); } diff --git a/source/pip/tests-integration/resources/adaptive_rifla/input/LoopOverArrays.qs b/source/pip/tests-integration/resources/adaptive_rifla/input/LoopOverArrays.qs new file mode 100644 index 0000000000..afc9883dbc --- /dev/null +++ b/source/pip/tests-integration/resources/adaptive_rifla/input/LoopOverArrays.qs @@ -0,0 +1,17 @@ +namespace Test { + import Std.Math.PI; + operation Main() : Result { + use q = Qubit(); + let arr = [2.0 * PI(), PI(), 2.0 * PI()]; + for a in arr { + Rx(a, q); + } + let arrays = [[PI(), PI(), PI()], arr, [2.0 * PI()]]; + for arr in arrays { + for a in arr { + Rx(a, q); + } + } + MResetZ(q) + } +} diff --git a/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.ll b/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.ll new file mode 100644 index 0000000000..9a7f5ad151 --- /dev/null +++ b/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.ll @@ -0,0 +1,100 @@ +@0 = internal constant [4 x i8] c"0_r\00" +@array0 = internal constant [3 x double] [double 6.283185307179586, double 3.141592653589793, double 6.283185307179586] +@array1 = internal constant [3 x double] [double 3.141592653589793, double 3.141592653589793, double 3.141592653589793] +@array2 = internal constant [1 x double] [double 6.283185307179586] + +define i64 @ENTRYPOINT__main() #0 { +block_0: + %var_0 = alloca i64 + %var_6 = alloca i64 + %var_11 = alloca i64 + %var_16 = alloca i64 + call void @__quantum__rt__initialize(ptr null) + store i64 0, ptr %var_0 + br label %block_1 +block_1: + %var_22 = load i64, ptr %var_0 + %var_1 = icmp slt i64 %var_22, 3 + br i1 %var_1, label %block_2, label %block_3 +block_2: + %var_38 = load i64, ptr %var_0 + %var_2 = getelementptr double, ptr @array0, i64 %var_38 + %var_39 = load double, ptr %var_2 + call void @__quantum__qis__rx__body(double %var_39, ptr inttoptr (i64 0 to ptr)) + %var_4 = add i64 %var_38, 1 + store i64 %var_4, ptr %var_0 + br label %block_1 +block_3: + store i64 0, ptr %var_6 + br label %block_4 +block_4: + %var_24 = load i64, ptr %var_6 + %var_7 = icmp slt i64 %var_24, 3 + br i1 %var_7, label %block_5, label %block_6 +block_5: + %var_35 = load i64, ptr %var_6 + %var_8 = getelementptr double, ptr @array1, i64 %var_35 + %var_36 = load double, ptr %var_8 + call void @__quantum__qis__rx__body(double %var_36, ptr inttoptr (i64 0 to ptr)) + %var_10 = add i64 %var_35, 1 + store i64 %var_10, ptr %var_6 + br label %block_4 +block_6: + store i64 0, ptr %var_11 + br label %block_7 +block_7: + %var_26 = load i64, ptr %var_11 + %var_12 = icmp slt i64 %var_26, 3 + br i1 %var_12, label %block_8, label %block_9 +block_8: + %var_32 = load i64, ptr %var_11 + %var_13 = getelementptr double, ptr @array0, i64 %var_32 + %var_33 = load double, ptr %var_13 + call void @__quantum__qis__rx__body(double %var_33, ptr inttoptr (i64 0 to ptr)) + %var_15 = add i64 %var_32, 1 + store i64 %var_15, ptr %var_11 + br label %block_7 +block_9: + store i64 0, ptr %var_16 + br label %block_10 +block_10: + %var_28 = load i64, ptr %var_16 + %var_17 = icmp slt i64 %var_28, 1 + br i1 %var_17, label %block_11, label %block_12 +block_11: + %var_29 = load i64, ptr %var_16 + %var_18 = getelementptr double, ptr @array2, i64 %var_29 + %var_30 = load double, ptr %var_18 + call void @__quantum__qis__rx__body(double %var_30, ptr inttoptr (i64 0 to ptr)) + %var_20 = add i64 %var_29, 1 + store i64 %var_20, ptr %var_16 + br label %block_10 +block_12: + call void @__quantum__qis__mresetz__body(ptr inttoptr (i64 0 to ptr), ptr inttoptr (i64 0 to ptr)) + call void @__quantum__rt__result_record_output(ptr inttoptr (i64 0 to ptr), ptr @0) + ret i64 0 +} + +declare void @__quantum__rt__initialize(ptr) + +declare void @__quantum__qis__rx__body(double, ptr) + +declare void @__quantum__qis__mresetz__body(ptr, ptr) #1 + +declare void @__quantum__rt__result_record_output(ptr, ptr) + +attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" } +attributes #1 = { "irreversible" } + +; module flags + +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7} + +!0 = !{i32 1, !"qir_major_version", i32 2} +!1 = !{i32 7, !"qir_minor_version", i32 1} +!2 = !{i32 1, !"dynamic_qubit_management", i1 false} +!3 = !{i32 1, !"dynamic_result_management", i1 false} +!4 = !{i32 5, !"int_computations", !{!"i64"}} +!5 = !{i32 5, !"float_computations", !{!"double"}} +!6 = !{i32 7, !"backwards_branching", i2 3} +!7 = !{i32 1, !"arrays", i1 true} diff --git a/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.out b/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.out new file mode 100644 index 0000000000..dca66c1887 --- /dev/null +++ b/source/pip/tests-integration/resources/adaptive_rifla/output/LoopOverArrays.out @@ -0,0 +1,8 @@ +START +METADATA entry_point +METADATA output_labeling_schema +METADATA qir_profiles adaptive_profile +METADATA required_num_qubits 1 +METADATA required_num_results 1 +OUTPUT RESULT 1 0_r +END 0 From 5928c37b01f8f75fa6284e28bbf8b8ff78455b99 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Tue, 7 Apr 2026 15:09:03 -0700 Subject: [PATCH 2/3] Reject loops over tuples --- .../qsc_partial_eval/src/tests/loops.rs | 74 +++++++++++++++++++ source/compiler/qsc_rca/src/core.rs | 7 +- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/source/compiler/qsc_partial_eval/src/tests/loops.rs b/source/compiler/qsc_partial_eval/src/tests/loops.rs index 5f34d3f98b..169b6e7623 100644 --- a/source/compiler/qsc_partial_eval/src/tests/loops.rs +++ b/source/compiler/qsc_partial_eval/src/tests/loops.rs @@ -626,6 +626,80 @@ fn nested_loops_over_arrays_of_arrays_unroll_outer_loop() { "#]].assert_eq(&program.to_string()); } +#[test] +fn for_loop_over_arrays_of_tuples_unrolled() { + let program = get_rir_program_with_capabilities( + indoc! { + r#" + namespace Test { + @EntryPoint() + operation Main() : Unit { + use q = Qubit(); + for (idx, theta) in Std.Arrays.Enumerated([0.0, 1.0]) { + Rx(theta, q); + } + } + } + "#, + }, + Profile::AdaptiveRIFLA.into(), + ); + + expect![[r#" + Program: + entry: 0 + callables: + Callable 0: Callable: + name: main + call_type: Regular + input_type: + output_type: Integer + body: 0 + Callable 1: Callable: + name: __quantum__rt__initialize + call_type: Regular + input_type: + [0]: Pointer + output_type: + body: + Callable 2: Callable: + name: __quantum__qis__rx__body + call_type: Regular + input_type: + [0]: Double + [1]: Qubit + output_type: + body: + Callable 3: Callable: + name: __quantum__rt__tuple_record_output + call_type: OutputRecording + input_type: + [0]: Integer + [1]: Pointer + output_type: + body: + blocks: + Block 0: Block: + Call id(1), args( Pointer, ) + Variable(0, Integer) = Store Integer(0) + Variable(0, Integer) = Store Integer(1) + Variable(0, Integer) = Store Integer(2) + Variable(1, Integer) = Store Integer(0) + Call id(2), args( Double(0), Qubit(0), ) + Variable(1, Integer) = Store Integer(1) + Call id(2), args( Double(1), Qubit(0), ) + Variable(1, Integer) = Store Integer(2) + Call id(3), args( Integer(0), Tag(0, 3), ) + Return + config: Config: + capabilities: TargetCapabilityFlags(Adaptive | IntegerComputations | FloatingPointComputations | BackwardsBranching | StaticSizedArrays) + num_qubits: 1 + num_results: 0 + tags: + [0]: 0_t + "#]].assert_eq(&program.to_string()); +} + // For now, loops over qubits are unrolled since we don't support qubit variables. #[test] fn for_loop_over_qubits() { diff --git a/source/compiler/qsc_rca/src/core.rs b/source/compiler/qsc_rca/src/core.rs index b82db7f95d..30f0b7da32 100644 --- a/source/compiler/qsc_rca/src/core.rs +++ b/source/compiler/qsc_rca/src/core.rs @@ -772,11 +772,16 @@ impl<'a> Analyzer<'a> { // `UseOfDynamicGeneric` runtime feature to cover all cases. dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicGeneric; } - Ty::Array(_) => { + Ty::Array(..) => { // If the type of the index expression is an array, we need to add the `UseOfDynamicallySizedArray` // runtime feature since the result of the index expression can be used in a context that requires array-specific runtime features. dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicallySizedArray; } + Ty::Tuple(..) => { + // If the type of the index expression is a tuple, we need to add the `UseOfDynamicTuple` + // runtime feature since the result of the index expression can be used in a context that requires tuple-specific runtime features. + dynamic_runtime_features |= RuntimeFeatureFlags::UseOfDynamicTuple; + } _ => { // Other dynamic content types are already handled by the `derive_runtime_features_for_value_kind_associated_to_type` function // called below, so we don't need to do anything else here. From 0b9c6e73cecce2a2d3bbeb30a90c498e0f6a2856 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Mon, 20 Apr 2026 10:17:13 -0700 Subject: [PATCH 3/3] Rename variable --- .../qsc_rir/src/passes/prune_unneeded_stores.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs b/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs index 60222d3db4..280186cc18 100644 --- a/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs +++ b/source/compiler/qsc_rir/src/passes/prune_unneeded_stores.rs @@ -33,20 +33,20 @@ fn process_callable(program: &mut Program, callable_id: CallableId) { while let Some(block_id) = blocks_to_visit.pop() { visited_blocks.insert(block_id); let mut used_vars_in_block = FxHashSet::default(); - let mut gep_vars_in_block = FxHashSet::default(); + let mut index_vars_in_block = FxHashSet::default(); let stored_vars_before_block = stored_vars.clone(); check_var_usage( program, block_id, &mut stored_vars, &mut used_vars_in_block, - &mut gep_vars_in_block, + &mut index_vars_in_block, ); for var in used_vars_in_block { if !used_vars.insert(var) || stored_vars_before_block.contains(&var) - || gep_vars_in_block.contains(&var) + || index_vars_in_block.contains(&var) { // This variable was already marked as used, which means it is used cross-block. // Alternatively, the variable was stored before this block and is used here. @@ -104,7 +104,7 @@ fn check_var_usage( block_id: crate::rir::BlockId, stored_vars: &mut FxHashSet, used_vars: &mut FxHashSet, - gep_vars: &mut FxHashSet, + index_vars: &mut FxHashSet, ) { let block = program.get_block(block_id); for instr in &block.0 { @@ -172,13 +172,13 @@ fn check_var_usage( ); used_vars.insert(variable.variable_id); } - Instruction::Index(gep_operand, operand, variable2) => { + Instruction::Index(index_operand, operand, variable2) => { if let crate::rir::Operand::Variable(var) = operand { used_vars.insert(var.variable_id); } - if let crate::rir::Operand::Variable(var) = gep_operand { + if let crate::rir::Operand::Variable(var) = index_operand { used_vars.insert(var.variable_id); - gep_vars.insert(var.variable_id); + index_vars.insert(var.variable_id); } assert!( !stored_vars.contains(&variable2.variable_id),