Skip to content

Commit

Permalink
Adding floating-point qir support
Browse files Browse the repository at this point in the history
  • Loading branch information
idavis committed Jan 2, 2025
1 parent 0e3c2d7 commit bcfe36d
Show file tree
Hide file tree
Showing 68 changed files with 4,388 additions and 792 deletions.
1,023 changes: 659 additions & 364 deletions compiler/qsc/src/codegen/tests.rs

Large diffs are not rendered by default.

19 changes: 3 additions & 16 deletions compiler/qsc/src/interpret/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,19 +968,13 @@ mod given_interpreter {
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
!4 = !{i32 1, !"int_computations", !"i64"}
"#]]
.assert_eq(&res);
}
Expand Down Expand Up @@ -1039,19 +1033,12 @@ mod given_interpreter {
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!llvm.module.flags = !{!0, !1, !2, !3}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"qubit_resetting", i1 true}
!5 = !{i32 1, !"classical_ints", i1 false}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
"#]]
.assert_eq(&res);
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/qsc/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum Profile {
Unrestricted,
Base,
AdaptiveRI,
AdaptiveRIF,
}

impl Profile {
Expand All @@ -19,6 +20,7 @@ impl Profile {
Self::Unrestricted => "Unrestricted",
Self::Base => "Base",
Self::AdaptiveRI => "Adaptive_RI",
Self::AdaptiveRIF => "Adaptive_RIF",
}
}
}
Expand All @@ -29,6 +31,12 @@ impl From<Profile> for TargetCapabilityFlags {
Profile::Unrestricted => Self::all(),
Profile::Base => Self::empty(),
Profile::AdaptiveRI => Self::Adaptive | Self::QubitReset | Self::IntegerComputations,
Profile::AdaptiveRIF => {
Self::Adaptive
| Self::QubitReset
| Self::IntegerComputations
| Self::FloatingPointComputations
}
}
}
}
Expand All @@ -39,6 +47,7 @@ impl FromStr for Profile {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Adaptive_RI" | "adaptive_ri" => Ok(Self::AdaptiveRI),
"Adaptive_RIF" | "adaptive_rif" => Ok(Self::AdaptiveRIF),
"Base" | "base" => Ok(Self::Base),
"Unrestricted" | "unrestricted" => Ok(Self::Unrestricted),
_ => Err(()),
Expand Down
174 changes: 127 additions & 47 deletions compiler/qsc_codegen/src/qir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use qsc_partial_eval::{partially_evaluate, ProgramEntry};
use qsc_rca::PackageStoreComputeProperties;
use qsc_rir::{
passes::check_and_transform,
rir::{self, ConditionCode},
rir::{self, ConditionCode, FcmpConditionCode},
utils::get_all_block_successors,
};

Expand Down Expand Up @@ -136,6 +136,29 @@ impl ToQir<String> for rir::Operand {
}
}

impl ToQir<String> for rir::FcmpConditionCode {
fn to_qir(&self, _program: &rir::Program) -> String {
match self {
rir::FcmpConditionCode::False => "false".to_string(),
rir::FcmpConditionCode::OrderedAndEqual => "oeq".to_string(),
rir::FcmpConditionCode::OrderedAndGreaterThan => "ogt".to_string(),
rir::FcmpConditionCode::OrderedAndGreaterThanOrEqual => "oge".to_string(),
rir::FcmpConditionCode::OrderedAndLessThan => "olt".to_string(),
rir::FcmpConditionCode::OrderedAndLessThanOrEqual => "ole".to_string(),
rir::FcmpConditionCode::OrderedAndNotEqual => "one".to_string(),
rir::FcmpConditionCode::Ordered => "ord".to_string(),
rir::FcmpConditionCode::UnorderedOrEqual => "ueq".to_string(),
rir::FcmpConditionCode::UnorderedOrGreaterThan => "ugt".to_string(),
rir::FcmpConditionCode::UnorderedOrGreaterThanOrEqual => "uge".to_string(),
rir::FcmpConditionCode::UnorderedOrLessThan => "ult".to_string(),
rir::FcmpConditionCode::UnorderedOrLessThanOrEqual => "ule".to_string(),
rir::FcmpConditionCode::UnorderedOrNotEqual => "une".to_string(),
rir::FcmpConditionCode::Unordered => "uno".to_string(),
rir::FcmpConditionCode::True => "true".to_string(),
}
}
}

impl ToQir<String> for rir::ConditionCode {
fn to_qir(&self, _program: &rir::Program) -> String {
match self {
Expand Down Expand Up @@ -181,6 +204,18 @@ impl ToQir<String> for rir::Instruction {
rir::Instruction::Call(call_id, args, output) => {
call_to_qir(args, *call_id, *output, program)
}
rir::Instruction::Fadd(lhs, rhs, variable) => {
fbinop_to_qir("fadd", lhs, rhs, *variable, program)
}
rir::Instruction::Fdiv(lhs, rhs, variable) => {
fbinop_to_qir("fdiv", lhs, rhs, *variable, program)
}
rir::Instruction::Fmul(lhs, rhs, variable) => {
fbinop_to_qir("fmul", lhs, rhs, *variable, program)
}
rir::Instruction::Fsub(lhs, rhs, variable) => {
fbinop_to_qir("fsub", lhs, rhs, *variable, program)
}
rir::Instruction::LogicalAnd(lhs, rhs, variable) => {
logical_binop_to_qir("and", lhs, rhs, *variable, program)
}
Expand All @@ -193,6 +228,9 @@ impl ToQir<String> for rir::Instruction {
rir::Instruction::Mul(lhs, rhs, variable) => {
binop_to_qir("mul", lhs, rhs, *variable, program)
}
rir::Instruction::Fcmp(op, lhs, rhs, variable) => {
fcmp_to_qir(*op, lhs, rhs, *variable, program)
}
rir::Instruction::Icmp(op, lhs, rhs, variable) => {
icmp_to_qir(*op, lhs, rhs, *variable, program)
}
Expand Down Expand Up @@ -314,6 +352,31 @@ fn call_to_qir(
}
}

fn fcmp_to_qir(
op: FcmpConditionCode,
lhs: &rir::Operand,
rhs: &rir::Operand,
variable: rir::Variable,
program: &rir::Program,
) -> String {
let lhs_ty = get_value_ty(lhs);
let rhs_ty = get_value_ty(rhs);
let var_ty = get_variable_ty(variable);
assert_eq!(
lhs_ty, rhs_ty,
"mismatched input types ({lhs_ty}, {rhs_ty}) for icmp {op}"
);

assert_eq!(var_ty, "i1", "unsupported output type {var_ty} for icmp");
format!(
" {} = fcmp {} {lhs_ty} {}, {}",
ToQir::<String>::to_qir(&variable.variable_id, program),
ToQir::<String>::to_qir(&op, program),
get_value_as_str(lhs, program),
get_value_as_str(rhs, program)
)
}

fn icmp_to_qir(
op: ConditionCode,
lhs: &rir::Operand,
Expand Down Expand Up @@ -367,6 +430,34 @@ fn binop_to_qir(
)
}

fn fbinop_to_qir(
op: &str,
lhs: &rir::Operand,
rhs: &rir::Operand,
variable: rir::Variable,
program: &rir::Program,
) -> String {
let lhs_ty = get_value_ty(lhs);
let rhs_ty = get_value_ty(rhs);
let var_ty = get_variable_ty(variable);
assert_eq!(
lhs_ty, rhs_ty,
"mismatched input types ({lhs_ty}, {rhs_ty}) for {op}"
);
assert_eq!(
lhs_ty, var_ty,
"mismatched input/output types ({lhs_ty}, {var_ty}) for {op}"
);
assert_eq!(var_ty, "double", "unsupported type {var_ty} for {op}");

format!(
" {} = {op} {var_ty} {}, {}",
ToQir::<String>::to_qir(&variable.variable_id, program),
get_value_as_str(lhs, program),
get_value_as_str(rhs, program)
)
}

fn simple_bitwise_to_qir(
op: &str,
lhs: &rir::Operand,
Expand Down Expand Up @@ -455,7 +546,7 @@ fn get_value_ty(lhs: &rir::Operand) -> &str {
rir::Operand::Literal(lit) => match lit {
rir::Literal::Integer(_) => "i64",
rir::Literal::Bool(_) => "i1",
rir::Literal::Double(_) => "f64",
rir::Literal::Double(_) => get_f64_ty(),
rir::Literal::Qubit(_) => "%Qubit*",
rir::Literal::Result(_) => "%Result*",
rir::Literal::Pointer => "i8*",
Expand All @@ -468,13 +559,28 @@ fn get_variable_ty(variable: rir::Variable) -> &'static str {
match variable.ty {
rir::Ty::Integer => "i64",
rir::Ty::Boolean => "i1",
rir::Ty::Double => "f64",
rir::Ty::Double => get_f64_ty(),
rir::Ty::Qubit => "%Qubit*",
rir::Ty::Result => "%Result*",
rir::Ty::Pointer => "i8*",
}
}

/// phi only supports "Floating-Point Types" which are defined as:
/// - `half` (`f16`)
/// - `bfloat`
/// - `float` (`f32`)
/// - `double` (`f64`)
/// - `fp128`
///
/// We only support `f64`, so we break the pattern used for integers
/// and have to use `double` here.
///
/// This conflicts with the QIR spec which says f64. Need to follow up on this.
fn get_f64_ty() -> &'static str {
"double"
}

impl ToQir<String> for rir::BlockId {
fn to_qir(&self, _program: &rir::Program) -> String {
format!("block_{}", self.0)
Expand Down Expand Up @@ -580,51 +686,25 @@ fn get_module_metadata(program: &rir::Program) -> String {
// loop through the capabilities and add them to the metadata
// for values that we can generate.
for cap in program.config.capabilities.iter() {
let name = match cap {
TargetCapabilityFlags::QubitReset => "qubit_resetting",
TargetCapabilityFlags::IntegerComputations => "classical_ints",
TargetCapabilityFlags::FloatingPointComputations => "classical_floats",
TargetCapabilityFlags::BackwardsBranching => "backwards_branching",
_ => continue,
};
flags.push_str(&format!(
"!{} = !{{i32 {}, !\"{}\", i1 {}}}\n",
index, 1, name, true
));
index += 1;
}

// loop through the capabilities that are missing and add them to the metadata
// as not supported.
let missing = TargetCapabilityFlags::all().difference(program.config.capabilities);
for cap in missing.iter() {
let name = match cap {
TargetCapabilityFlags::QubitReset => "qubit_resetting",
TargetCapabilityFlags::IntegerComputations => "classical_ints",
TargetCapabilityFlags::FloatingPointComputations => "classical_floats",
TargetCapabilityFlags::BackwardsBranching => "backwards_branching",
match cap {
TargetCapabilityFlags::IntegerComputations => {
let name = "int_computations";
flags.push_str(&format!(
"!{} = !{{i32 {}, !\"{}\", !\"i{}\"}}\n",
index, 1, name, 64
));
index += 1;
}
TargetCapabilityFlags::FloatingPointComputations => {
let name = "float_computations";
flags.push_str(&format!(
"!{} = !{{i32 {}, !\"{}\", !\"f{}\"}}\n",
index, 1, name, 64
));
index += 1;
}
_ => continue,
};
flags.push_str(&format!(
"!{} = !{{i32 {}, !\"{}\", i1 {}}}\n",
index, 1, name, false
));
index += 1;
}

// Add the remaining extension capabilities as not supported.
// We can't generate these values yet so we just add them as false.
let unmapped_capabilities = [
"classical_fixed_points",
"user_functions",
"multiple_target_branching",
];
for capability in unmapped_capabilities {
flags.push_str(&format!(
"!{} = !{{i32 {}, !\"{}\", i1 {}}}\n",
index, 1, capability, false
));
index += 1;
}
}
}

Expand Down
Loading

0 comments on commit bcfe36d

Please sign in to comment.