From 586d0b47a1fb3d3928e7f61c6019b88c0bd71fc8 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Tue, 1 Oct 2024 13:13:22 +0100 Subject: [PATCH 1/9] wip --- Cargo.lock | 1 + Cargo.toml | 1 + src/custom.rs | 248 ++++++++++++------------- src/custom/conversions.rs | 255 +++++++++++--------------- src/custom/extension_op.rs | 114 ++++++++++++ src/custom/float.rs | 228 +++++++++-------------- src/custom/int.rs | 256 ++++++++++---------------- src/custom/load_constant.rs | 79 ++++++++ src/custom/logic.rs | 142 +++++++------- src/custom/prelude.rs | 356 +++++++++++++++++------------------- src/custom/prelude/array.rs | 18 +- src/custom/rotation.rs | 340 +++++++++++++++------------------- src/custom/types.rs | 79 ++++++++ src/emit.rs | 54 +++--- src/emit/func.rs | 24 ++- src/emit/ops.rs | 10 +- src/emit/ops/cfg.rs | 4 +- src/emit/test.rs | 4 +- src/sum.rs | 35 ++-- src/test.rs | 76 ++++---- src/types.rs | 159 ++++++---------- src/utils.rs | 1 + src/utils/type_map.rs | 124 +++++++++++++ tests/guppy.rs | 166 ----------------- 24 files changed, 1346 insertions(+), 1428 deletions(-) create mode 100644 src/custom/extension_op.rs create mode 100644 src/custom/load_constant.rs create mode 100644 src/custom/types.rs create mode 100644 src/utils/type_map.rs delete mode 100644 tests/guppy.rs diff --git a/Cargo.lock b/Cargo.lock index 7ec377e..e1a44e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -510,6 +510,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "strum", "tket2", "typetag", ] diff --git a/Cargo.toml b/Cargo.toml index 719f407..29877cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ delegate = "0.12.0" petgraph = "0.6.5" lazy_static = "1.4.0" downcast-rs= "1.2.1" +strum = "0.26.3" [dev-dependencies] insta = "1.39.0" diff --git a/src/custom.rs b/src/custom.rs index 6a9e7c7..57075b9 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -1,24 +1,31 @@ -use std::{ - any::TypeId, - collections::{HashMap, HashSet}, - rc::Rc, -}; +//! Provides an interface for extending `hugr-llvm` to emit [CustomType]s, +//! [CustomConst]s, and [ExtensionOp]s. +use std::rc::Rc; +use self::extension_op::{ExtensionOpFn, ExtensionOpMap}; use hugr::{ - extension::ExtensionId, - ops::{constant::CustomConst, ExtensionOp}, - types::CustomType, + extension::{simple_op::MakeOpDef, ExtensionId}, + ops::{constant::CustomConst, ExtensionOp, OpName}, + types::TypeName, HugrView, }; -use anyhow::{anyhow, Result}; -use inkwell::{types::BasicTypeEnum, values::BasicValueEnum}; +use strum::IntoEnumIterator; + +use anyhow::Result; +use self::load_constant::{LoadConstantFn, LoadConstantsMap}; +use self::types::LLVMCustomTypeFn; use crate::{ emit::{func::EmitFuncContext, EmitOpArgs}, - types::TypingSession, + types::TypeConverter, }; +pub mod extension_op; +pub mod load_constant; +pub mod types; + +// TODO move these extension implementations to crate::extension pub mod conversions; pub mod float; pub mod int; @@ -26,148 +33,119 @@ pub mod logic; pub mod prelude; pub mod rotation; -/// The extension point for lowering HUGR Extensions to LLVM. -pub trait CodegenExtension { - /// The [ExtensionId] for which this extension will lower `ExtensionOp`s and - /// [CustomType]s. - /// - /// Note that a [CodegenExtsMap] will only delegate to a single - /// `CodegenExtension` per [ExtensionId]. - fn extension(&self) -> ExtensionId; - - /// The [TypeId]s for which [dyn CustomConst](CustomConst)s should be passed - /// to [Self::load_constant]. - /// - /// Defaults to an empty set. - fn supported_consts(&self) -> HashSet { - Default::default() - } - /// Return the type of the given [CustomType], which will have an extension - /// that matches `Self`. - fn llvm_type<'c>( - &self, - context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result>; - - /// Return an emitter that will be asked to emit `ExtensionOp`s that have an - /// extension that matches `Self.` - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()>; - - /// Emit instructions to materialise `konst`. `konst` will have a [TypeId] - /// that matches `self.supported_consts`. - /// - /// If the result is `Ok(None)`, [CodegenExtsMap] may try other - /// `CodegenExtension`s. - fn load_constant<'c>( - &self, - #[allow(unused)] context: &mut EmitFuncContext<'c, H>, - #[allow(unused)] konst: &dyn CustomConst, - ) -> Result>> { - Ok(None) - } +/// A helper to register codegen extensions. +/// +/// Types that implement this trait can be registered with a [CodgenExtsBuilder] +/// via [CodegenExtsBuilder::add_extension]. +/// +/// See [prelude::PreludeCodegenExtension] for an example. +pub trait CodegenExtension { + /// Implementers should add each of their handlers to `builder` and return the + /// resulting [CodegenExtsBuilder]. + fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> + where Self: 'a; } -/// A collection of [CodegenExtension]s. +/// A container for a collection of codegen callbacks as they are being +/// assembled. /// -/// Provides methods to delegate operations to appropriate contained -/// [CodegenExtension]s. -pub struct CodegenExtsMap<'a, H> { - supported_consts: HashMap>, - extensions: HashMap>>, +/// We callbacks are registered against several keys: +/// - [CustomType]s, with [CodegenExtsBuilder::custom_type] +/// - [CustomConst]s, with [CodegenExtsBuilder::custom_const] +/// - [ExtensionOp]s, with [CodegenExtsBuilder::extension_op] +/// +/// Each callback may hold references older than `'a`. +/// +/// Registering any callback silently replaces any other callback registered for +/// that same key. +#[derive(Default)] +pub struct CodegenExtsBuilder<'a, H> { + load_constant_handlers: LoadConstantsMap<'a, H>, + extension_op_handlers: ExtensionOpMap<'a, H>, + type_converter: TypeConverter<'a>, } -impl<'c, H> CodegenExtsMap<'c, H> { - /// Create a new, empty, `CodegenExtsMap`. - pub fn new() -> Self { - Self { - supported_consts: Default::default(), - extensions: Default::default(), - } +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { + /// Forwards to [CodegenExtension::add_extension]. + /// + /// ``` + /// use hugr_llvm::custom::{prelude::{PreludeCodegenExtension, DefaultPreludeCodegen}, CodegenExtsBuilder}; + /// let ext = PreludeCodegenExtension::from(DefaultPreludeCodegen); + /// CodegenExtsBuilder::::default().add_extension(ext); + /// ``` + pub fn add_extension(self, ext: impl CodegenExtension + 'a) -> Self { + ext.add_extension(self) } - /// Consumes a `CodegenExtsMap` and returns a new one, with `ext` - /// incorporated. - pub fn add_cge(mut self, ext: impl 'c + CodegenExtension) -> Self { - let extension = ext.extension(); - for k in ext.supported_consts() { - self.supported_consts - .entry(k) - .or_default() - .insert(extension.clone()); - } - self.extensions.insert(extension, Box::new(ext)); + /// Register a callback to map a [hugr::CustomType] to a [BasicTypeEnum]. + pub fn custom_type( + mut self, + custom_type: (ExtensionId, TypeName), + handler: impl LLVMCustomTypeFn<'a>, + ) -> Self { + self.type_converter.custom_type(custom_type, handler); self } - /// Returns the matching inner [CodegenExtension] if it exists. - pub fn get(&self, extension: &ExtensionId) -> Result<&dyn CodegenExtension> { - let b = self - .extensions - .get(extension) - .ok_or(anyhow!("CodegenExtsMap: Unknown extension: {}", extension))?; - Ok(b.as_ref()) + /// Register a callback to emit a [hugr::ExtensionOp], keyed by fully + /// qualified [OpName]. + pub fn extension_op( + mut self, + extension: ExtensionId, + op: OpName, + handler: impl ExtensionOpFn<'a, H>, + ) -> Self { + self.extension_op_handlers + .extension_op(extension, op, handler); + self } - /// Return the type of the given [CustomType] by delegating to the - /// appropriate inner [CodegenExtension]. - pub fn llvm_type( - &self, - ts: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - self.get(hugr_type.extension())?.llvm_type(ts, hugr_type) + /// Register callbacks to emit [hugr::ExtensionOp]s that match the + /// definitions generated by `Op`s impl of [strum::IntoEnumIterator]> + pub fn simple_extension_op( + mut self, + handler: impl 'a + + for<'c> Fn( + &mut EmitFuncContext<'c, H>, + EmitOpArgs<'c, '_, ExtensionOp, H>, + Op, + ) -> Result<()>, + ) -> Self { + self.extension_op_handlers + .simple_extension_op::(handler); + self } - /// Emit instructions for `args` by delegating to the appropriate inner - /// [CodegenExtension]. - pub fn emit<'hugr>( - self: Rc, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, 'hugr, ExtensionOp, H>, - ) -> Result<()> - where - H: HugrView, - { - self.get(args.node().def().extension())? - .emit_extension_op(context, args) + /// Register a callback to materialise a constant implemented by `CC`. + pub fn custom_const( + mut self, + handler: impl LoadConstantFn<'a, H, CC>, + ) -> Self { + self.load_constant_handlers.custom_const(handler); + self } - /// Emit instructions to materialise `konst` by delegating to the - /// appropriate inner [CodegenExtension]s. - pub fn load_constant( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn CustomConst, - ) -> Result> { - let type_id = konst.type_id(); - self.supported_consts - .get(&type_id) - .into_iter() - .flatten() - .filter_map(|ext| { - let cge = self.extensions.get(ext).unwrap(); - match cge.load_constant(context, konst) { - Err(e) => Some(Err(e)), - Ok(None) => None, - Ok(Some(v)) => Some(Ok(v)), - } - }) - .next() - .unwrap_or(Err(anyhow!( - "No extension could load constant name: {} type_id: {type_id:?}", - konst.name() - ))) + /// Consume `self` to return collections of callbacks for each of the + /// supported keys.` + pub fn finish(self) -> CodegenExtsMap<'a, H> { + CodegenExtsMap { + load_constant_handlers: Rc::new(self.load_constant_handlers), + extension_op_handlers: Rc::new(self.extension_op_handlers), + type_converter: Rc::new(self.type_converter), + } } } -impl<'c, H: HugrView> Default for CodegenExtsMap<'c, H> { - fn default() -> Self { - Self::new() - } +/// The result of [CodegenExtsBuilder::finish]. Users are expected to +/// deconstruct this type, and consume the fields independently. +/// We expect to add further collections at a later date, and so this type is +/// marked `non_exhaustive` +#[derive(Default)] +#[non_exhaustive] +pub struct CodegenExtsMap<'a, H> { + pub load_constant_handlers: Rc>, + pub extension_op_handlers: Rc>, + pub type_converter: Rc>, // TODO remove this H } + diff --git a/src/custom/conversions.rs b/src/custom/conversions.rs index c71d253..5f00351 100644 --- a/src/custom/conversions.rs +++ b/src/custom/conversions.rs @@ -1,4 +1,4 @@ -use super::{CodegenExtension, CodegenExtsMap}; +use super::{CodegenExtension, CodegenExtsBuilder}; use anyhow::{anyhow, Result}; @@ -6,18 +6,14 @@ use hugr::{ extension::{ prelude::{sum_with_error, ConstError, BOOL_T}, simple_op::MakeExtensionOp, - ExtensionId, }, ops::{constant::Value, custom::ExtensionOp}, - std_extensions::arithmetic::{ - conversions::{self, ConvertOpDef, ConvertOpType}, - int_types::INT_TYPES, - }, - types::{CustomType, TypeArg, TypeEnum}, + std_extensions::arithmetic::{conversions::ConvertOpDef, int_types::INT_TYPES}, + types::{TypeArg, TypeEnum}, HugrView, }; -use inkwell::{types::BasicTypeEnum, values::BasicValue, FloatPredicate, IntPredicate}; +use inkwell::{values::BasicValue, FloatPredicate, IntPredicate}; use crate::{ emit::{ @@ -26,7 +22,6 @@ use crate::{ EmitOpArgs, }, sum::LLVMSumValue, - types::TypingSession, }; fn build_trunc_op<'c, H: HugrView>( @@ -134,127 +129,107 @@ fn build_trunc_op<'c, H: HugrView>( }) } -pub struct ConversionsCodegenExtension; - -impl CodegenExtension for ConversionsCodegenExtension { - fn extension(&self) -> ExtensionId { - conversions::EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - _context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - Err(anyhow!( - "ConversionEmitter: unsupported type: {}", - hugr_type - )) - } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let conversion_op = - ConvertOpType::from_optype(&args.node().generalise()).ok_or(anyhow!( - "ConversionsEmitter from_optype failed: {:?}", - args.node().as_ref() - ))?; - - match conversion_op.def() { - ConvertOpDef::trunc_u | ConvertOpDef::trunc_s => { - let signed = conversion_op.def() == &ConvertOpDef::trunc_s; - let Some(TypeArg::BoundedNat { n: log_width }) = - conversion_op.type_args().last().cloned() - else { - panic!("This op should have one type arg only: the log-width of the int we're truncating to.") - }; - - build_trunc_op(context, signed, log_width, args) - } +fn emit_conversion_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + conversion_op: ConvertOpDef, +) -> Result<()> { + match conversion_op { + ConvertOpDef::trunc_u | ConvertOpDef::trunc_s => { + let signed = conversion_op == ConvertOpDef::trunc_s; + let Some(TypeArg::BoundedNat { n: log_width }) = args.node().args().last().cloned() + else { + panic!("This op should have one type arg only: the log-width of the int we're truncating to.: {:?}", conversion_op.type_args()) + }; + + build_trunc_op(context, signed, log_width, args) + } - ConvertOpDef::convert_u => emit_custom_unary_op(context, args, |ctx, arg, out_tys| { - let out_ty = out_tys.last().unwrap(); - Ok(vec![ctx - .builder() - .build_unsigned_int_to_float( + ConvertOpDef::convert_u => emit_custom_unary_op(context, args, |ctx, arg, out_tys| { + let out_ty = out_tys.last().unwrap(); + Ok(vec![ctx + .builder() + .build_unsigned_int_to_float(arg.into_int_value(), out_ty.into_float_type(), "")? + .as_basic_value_enum()]) + }), + + ConvertOpDef::convert_s => emit_custom_unary_op(context, args, |ctx, arg, out_tys| { + let out_ty = out_tys.last().unwrap(); + Ok(vec![ctx + .builder() + .build_signed_int_to_float(arg.into_int_value(), out_ty.into_float_type(), "")? + .as_basic_value_enum()]) + }), + // These ops convert between hugr's `USIZE` and u64. The former is + // implementation-dependent and we define them to be the same. + // Hence our implementation is a noop. + ConvertOpDef::itousize | ConvertOpDef::ifromusize => { + emit_custom_unary_op(context, args, |_, arg, _| Ok(vec![arg])) + } + ConvertOpDef::itobool | ConvertOpDef::ifrombool => { + assert!(conversion_op.type_args().is_empty()); // Always 1-bit int <-> bool + let i0_ty = context + .typing_session() + .llvm_type(&INT_TYPES[0])? + .into_int_type(); + let sum_ty = context + .typing_session() + .llvm_sum_type(match BOOL_T.as_type_enum() { + TypeEnum::Sum(st) => st.clone(), + _ => panic!("Hugr prelude BOOL_T not a Sum"), + })?; + + emit_custom_unary_op(context, args, |ctx, arg, _| { + let res = if conversion_op == ConvertOpDef::itobool { + let is1 = ctx.builder().build_int_compare( + IntPredicate::EQ, arg.into_int_value(), - out_ty.into_float_type(), + i0_ty.const_int(1, false), + "eq1", + )?; + let sum_f = sum_ty.build_tag(ctx.builder(), 0, vec![])?; + let sum_t = sum_ty.build_tag(ctx.builder(), 1, vec![])?; + ctx.builder().build_select(is1, sum_t, sum_f, "")? + } else { + let tag_ty = sum_ty.get_tag_type(); + let tag = LLVMSumValue::try_new(arg, sum_ty)?.build_get_tag(ctx.builder())?; + let is_true = ctx.builder().build_int_compare( + IntPredicate::EQ, + tag, + tag_ty.const_int(1, false), + "", + )?; + ctx.builder().build_select( + is_true, + i0_ty.const_int(1, false), + i0_ty.const_int(0, false), "", )? - .as_basic_value_enum()]) - }), - - ConvertOpDef::convert_s => emit_custom_unary_op(context, args, |ctx, arg, out_tys| { - let out_ty = out_tys.last().unwrap(); - Ok(vec![ctx - .builder() - .build_signed_int_to_float(arg.into_int_value(), out_ty.into_float_type(), "")? - .as_basic_value_enum()]) - }), - // These ops convert between hugr's `USIZE` and u64. The former is - // implementation-dependent and we define them to be the same. - // Hence our implementation is a noop. - ConvertOpDef::itousize | ConvertOpDef::ifromusize => { - emit_custom_unary_op(context, args, |_, arg, _| Ok(vec![arg])) - } - ConvertOpDef::itobool | ConvertOpDef::ifrombool => { - assert!(conversion_op.type_args().is_empty()); // Always 1-bit int <-> bool - let i0_ty = context - .typing_session() - .llvm_type(&INT_TYPES[0])? - .into_int_type(); - let sum_ty = - context - .typing_session() - .llvm_sum_type(match BOOL_T.as_type_enum() { - TypeEnum::Sum(st) => st.clone(), - _ => panic!("Hugr prelude BOOL_T not a Sum"), - })?; - - emit_custom_unary_op(context, args, |ctx, arg, _| { - let res = if conversion_op.def() == &ConvertOpDef::itobool { - let is1 = ctx.builder().build_int_compare( - IntPredicate::EQ, - arg.into_int_value(), - i0_ty.const_int(1, false), - "eq1", - )?; - let sum_f = sum_ty.build_tag(ctx.builder(), 0, vec![])?; - let sum_t = sum_ty.build_tag(ctx.builder(), 1, vec![])?; - ctx.builder().build_select(is1, sum_t, sum_f, "")? - } else { - let tag_ty = sum_ty.get_tag_type(); - let tag = - LLVMSumValue::try_new(arg, sum_ty)?.build_get_tag(ctx.builder())?; - let is_true = ctx.builder().build_int_compare( - IntPredicate::EQ, - tag, - tag_ty.const_int(1, false), - "", - )?; - ctx.builder().build_select( - is_true, - i0_ty.const_int(1, false), - i0_ty.const_int(0, false), - "", - )? - }; - Ok(vec![res]) - }) - } - _ => Err(anyhow!( - "Conversion op not implemented: {:?}", - args.node().as_ref() - )), + }; + Ok(vec![res]) + }) } + _ => Err(anyhow!( + "Conversion op not implemented: {:?}", + args.node().as_ref() + )), } } -pub fn add_conversions_extension(cem: CodegenExtsMap<'_, H>) -> CodegenExtsMap<'_, H> { - cem.add_cge(ConversionsCodegenExtension) +#[derive(Clone,Debug)] +pub struct ConversionExtension; + +impl CodegenExtension for ConversionExtension { + fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> + where Self: 'a { + builder.simple_extension_op(emit_conversion_op) + } +} + +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { + pub fn add_conversion_extensions(self) -> Self { + self.add_extension(ConversionExtension) + } } #[cfg(test)] @@ -263,10 +238,6 @@ mod test { use super::*; use crate::check_emission; - use crate::custom::{ - float::add_float_extensions, int::add_int_extensions, - prelude::add_default_prelude_extensions, - }; use crate::emit::test::{SimpleHugrConfig, DFGW}; use crate::test::{exec_ctx, llvm_ctx, TestContext}; use hugr::builder::SubContainer; @@ -315,9 +286,7 @@ mod test { #[case("convert_u", 4)] #[case("convert_s", 5)] fn test_convert(mut llvm_ctx: TestContext, #[case] op_name: &str, #[case] log_width: u8) -> () { - llvm_ctx.add_extensions(add_int_extensions); - llvm_ctx.add_extensions(add_float_extensions); - llvm_ctx.add_extensions(add_conversions_extension); + llvm_ctx.add_extensions(|ceb| ceb.add_int_extensions().add_float_extensions().add_conversion_extensions()); let in_ty = INT_TYPES[log_width as usize].clone(); let out_ty = FLOAT64_TYPE; let hugr = test_conversion_op(op_name, in_ty, out_ty, log_width); @@ -332,10 +301,7 @@ mod test { #[case] op_name: &str, #[case] log_width: u8, ) -> () { - llvm_ctx.add_extensions(add_int_extensions); - llvm_ctx.add_extensions(add_float_extensions); - llvm_ctx.add_extensions(add_conversions_extension); - llvm_ctx.add_extensions(add_default_prelude_extensions); + llvm_ctx.add_extensions(|builder| builder.add_int_extensions().add_float_extensions().add_conversion_extensions().add_default_prelude_extensions()); let in_ty = FLOAT64_TYPE; let out_ty = sum_with_error(INT_TYPES[log_width as usize].clone()); let hugr = test_conversion_op(op_name, in_ty, out_ty.into(), log_width); @@ -355,9 +321,7 @@ mod test { tys.reverse() }; let [in_t, out_t] = tys; - llvm_ctx.add_extensions(add_int_extensions); - llvm_ctx.add_extensions(add_float_extensions); - llvm_ctx.add_extensions(add_conversions_extension); + llvm_ctx.add_extensions(|builder| builder.add_int_extensions().add_float_extensions().add_conversion_extensions()); let hugr = SimpleHugrConfig::new() .with_ins(vec![in_t]) .with_outs(vec![out_t]) @@ -385,7 +349,7 @@ mod test { let konst = builder.add_load_value(ConstUsize::new(42)); builder.finish_with_outputs([konst]).unwrap() }); - exec_ctx.add_extensions(add_default_prelude_extensions); + exec_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); assert_eq!(42, exec_ctx.exec_hugr_u64(hugr, "main")); } @@ -409,9 +373,7 @@ mod test { .outputs_arr(); builder.finish_with_outputs([usize_]).unwrap() }); - exec_ctx.add_extensions(add_int_extensions); - exec_ctx.add_extensions(add_conversions_extension); - exec_ctx.add_extensions(add_default_prelude_extensions); + exec_ctx.add_extensions(|builder| builder.add_int_extensions().add_conversion_extensions().add_default_prelude_extensions()); assert_eq!(val, exec_ctx.exec_hugr_u64(hugr, "main")); } @@ -464,10 +426,7 @@ mod test { } fn add_extensions(ctx: &mut TestContext) { - ctx.add_extensions(add_conversions_extension); - ctx.add_extensions(add_default_prelude_extensions); - ctx.add_extensions(add_float_extensions); - ctx.add_extensions(add_int_extensions); + ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_float_extensions().add_int_extensions()); } #[rstest] @@ -524,9 +483,7 @@ mod test { let res = cond.finish_sub_container().unwrap(); builder.finish_with_outputs(res.outputs()).unwrap() }); - exec_ctx.add_extensions(add_conversions_extension); - exec_ctx.add_extensions(add_default_prelude_extensions); - exec_ctx.add_extensions(add_int_extensions); + exec_ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_int_extensions()); assert_eq!(i * 5 + 1, exec_ctx.exec_hugr_u64(hugr, "main")); } @@ -547,9 +504,7 @@ mod test { let [i] = builder.add_dataflow_op(b2i, [b]).unwrap().outputs_arr(); builder.finish_with_outputs([i]).unwrap() }); - exec_ctx.add_extensions(add_conversions_extension); - exec_ctx.add_extensions(add_default_prelude_extensions); - exec_ctx.add_extensions(add_int_extensions); + exec_ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_int_extensions()); assert_eq!(i, exec_ctx.exec_hugr_u64(hugr, "main")); } } diff --git a/src/custom/extension_op.rs b/src/custom/extension_op.rs new file mode 100644 index 0000000..95340fc --- /dev/null +++ b/src/custom/extension_op.rs @@ -0,0 +1,114 @@ +use std::{collections::HashMap, rc::Rc}; + +use hugr::{ + extension::{ + simple_op::{MakeExtensionOp, MakeOpDef}, + ExtensionId, + }, + ops::{ExtensionOp, OpName}, + HugrView, +}; + +use anyhow::{bail, Result}; + +use strum::IntoEnumIterator; + +use crate::emit::{EmitFuncContext, EmitOpArgs}; + + +/// A helper trait for describing the callback used for emitting [ExtensionOp]s, +/// and for hanging documentation. We have the appropriate `Fn` as a supertrait, +/// and there is a blanket impl for that `Fn`. We do not intend users to impl +/// this trait. +/// +/// `ExtensionOpFn` callbacks are registered against a fully qualified [OpName], +/// i.e. including it's [ExtensionId]. Callbacks can assume that the provided +/// [EmitOpArgs::node] holds an op matching that fully qualified name, and that +/// the signature of that op determinies the length and types of +/// [EmitOpArgs::inputs], and [EmitOpArgs::outputs] via +/// [EmitFuncContext::llvm_type]. +/// +/// Callbacks should use the supplied [EmitFuncContext] to emit LLVM to match +/// the desired semantics of the op. If a callback returns success then the callback must: +/// - ensure that [RowPromise::finish] has been called on the outputs. +/// - ensure that the contexts [Builder] is positioned at the end of a basic +/// block, logically after the execution of the just-emitted op. +/// +/// Callbacks may hold references with lifetimes older than `'a`. +pub trait ExtensionOpFn<'a, H>: + for<'c> Fn(&mut EmitFuncContext<'c, H>, EmitOpArgs<'c, '_, ExtensionOp, H>) -> Result<()> + 'a +{ +} + +impl< + 'a, + H, + F: for<'c> Fn( + &mut EmitFuncContext<'c, H>, + EmitOpArgs<'c, '_, ExtensionOp, H>, + ) -> Result<()> + + ?Sized + + 'a, + > ExtensionOpFn<'a, H> for F +{ +} + +/// A collection of [ExtensionOpFn] callbacks keyed the fully qualified [OpName]. +/// +/// Those callbacks may hold references with lifetimes older than `'a`. +#[derive(Default)] +pub struct ExtensionOpMap<'a, H>(HashMap<(ExtensionId, OpName), Box>>); + +impl<'a, H: HugrView> ExtensionOpMap<'a, H> { + /// Register a callback to emit a [hugr::ExtensionOp], keyed by fully + /// qualified [OpName]. + pub fn extension_op( + &mut self, + extension: ExtensionId, + op: OpName, + handler: impl ExtensionOpFn<'a, H>, + ) { + self.0.insert((extension, op), Box::new(handler)); + } + + /// Register callbacks to emit [hugr::ExtensionOp]s that match the + /// definitions generated by `Op`s impl of [strum::IntoEnumIterator]> + pub fn simple_extension_op( + &mut self, + handler: impl 'a + + for<'c> Fn( + &mut EmitFuncContext<'c, H>, + EmitOpArgs<'c, '_, ExtensionOp, H>, + Op, + ) -> Result<()>, + ) { + let handler = Rc::new(handler); + for op in Op::iter() { + let handler = handler.clone(); + self.extension_op( + op.extension(), + op.name().clone(), + move |context, args| { + let op = Op::from_extension_op(&args.node())?; + handler(context, args, op) + } + ); + } + } + + /// Emit an [ExtensionOp] by delegating to the collected callbacks. + /// + /// If no handler is registered for the op an error will be returned. + pub fn emit_extension_op<'c>( + &self, + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + ) -> Result<()> { + let node = args.node(); + let key = (node.def().extension().clone(), node.def().name().clone()); + let Some(handler) = self.0.get(&key) else { + bail!("No extension could emit extension op: {key:?}") + }; + (handler.as_ref())(context, args) + } +} diff --git a/src/custom/float.rs b/src/custom/float.rs index 9fe9d47..7615154 100644 --- a/src/custom/float.rs +++ b/src/custom/float.rs @@ -1,20 +1,11 @@ -use std::{any::TypeId, collections::HashSet}; - -use anyhow::{anyhow, bail, Result}; -use hugr::extension::simple_op::MakeExtensionOp; -use hugr::extension::ExtensionId; +use anyhow::{anyhow, Result}; use hugr::ops::ExtensionOp; use hugr::ops::{constant::CustomConst, Value}; use hugr::std_extensions::arithmetic::float_ops::FloatOps; -use hugr::types::CustomType; use hugr::{ - std_extensions::arithmetic::{ - float_ops, - float_types::{self, ConstF64, FLOAT64_CUSTOM_TYPE}, - }, + std_extensions::arithmetic::float_types::{self, ConstF64}, HugrView, }; -use inkwell::types::BasicTypeEnum; use inkwell::{ types::{BasicType, FloatType}, values::{BasicValue, BasicValueEnum}, @@ -23,137 +14,8 @@ use inkwell::{ use crate::emit::emit_value; use crate::emit::ops::{emit_custom_binary_op, emit_custom_unary_op}; use crate::emit::{func::EmitFuncContext, EmitOpArgs}; -use crate::types::TypingSession; - -use super::{CodegenExtension, CodegenExtsMap}; - -/// A [CodegenExtension] for the [hugr::std_extensions::arithmetic::float_types] extension. -pub struct FloatTypesCodegenExtension; - -impl CodegenExtension for FloatTypesCodegenExtension { - fn extension(&self) -> ExtensionId { - float_types::EXTENSION_ID - } - fn llvm_type<'c>( - &self, - context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> anyhow::Result> { - if hugr_type == &FLOAT64_CUSTOM_TYPE { - Ok(context.iw_context().f64_type().as_basic_type_enum()) - } else { - Err(anyhow!( - "FloatCodegenExtension: Unsupported type: {}", - hugr_type - )) - } - } - - fn emit_extension_op<'c>( - &self, - _: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - bail!("FloatTypesCodegenExtension does not implement any extension ops, try FloatOpsCodegenExtension for: {:?}", args.node().as_ref()) - } - fn supported_consts(&self) -> HashSet { - [TypeId::of::()].into_iter().collect() - } - - fn load_constant<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn hugr::ops::constant::CustomConst, - ) -> Result>> { - let Some(k) = konst.downcast_ref::() else { - return Ok(None); - }; - let ty: FloatType<'c> = context.llvm_type(&k.get_type())?.try_into().unwrap(); - Ok(Some(ty.const_float(k.value()).as_basic_value_enum())) - } -} - -struct FloatOpsCodegenExtension; - -impl CodegenExtension for FloatOpsCodegenExtension { - fn extension(&self) -> hugr::extension::ExtensionId { - float_ops::EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - _context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> anyhow::Result> { - Err(anyhow!( - "FloatOpsCodegenExtension: unsupported type: {hugr_type}" - )) - } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let op = FloatOps::from_optype(&args.node().generalise()).ok_or(anyhow!( - "FloatOpEmitter: from_optype_failed: {:?}", - args.node().as_ref() - ))?; - // We emit the float comparison variants where NaN is an absorbing value. - // Any comparison with NaN is always false. - #[allow(clippy::wildcard_in_or_patterns)] - match op { - FloatOps::feq => emit_fcmp(context, args, inkwell::FloatPredicate::OEQ), - FloatOps::fne => emit_fcmp(context, args, inkwell::FloatPredicate::ONE), - FloatOps::flt => emit_fcmp(context, args, inkwell::FloatPredicate::OLT), - FloatOps::fgt => emit_fcmp(context, args, inkwell::FloatPredicate::OGT), - FloatOps::fle => emit_fcmp(context, args, inkwell::FloatPredicate::OLE), - FloatOps::fge => emit_fcmp(context, args, inkwell::FloatPredicate::OGE), - FloatOps::fadd => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_float_add(lhs.into_float_value(), rhs.into_float_value(), "")? - .as_basic_value_enum()]) - }), - FloatOps::fsub => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_float_sub(lhs.into_float_value(), rhs.into_float_value(), "")? - .as_basic_value_enum()]) - }), - FloatOps::fneg => emit_custom_unary_op(context, args, |ctx, v, _| { - Ok(vec![ctx - .builder() - .build_float_neg(v.into_float_value(), "")? - .as_basic_value_enum()]) - }), - FloatOps::fmul => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_float_mul(lhs.into_float_value(), rhs.into_float_value(), "")? - .as_basic_value_enum()]) - }), - FloatOps::fdiv => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_float_div(lhs.into_float_value(), rhs.into_float_value(), "")? - .as_basic_value_enum()]) - }), - // Missing ops, not supported by inkwell - FloatOps::fmax - | FloatOps::fmin - | FloatOps::fabs - | FloatOps::ffloor - | FloatOps::fceil - | FloatOps::ftostring - | _ => { - let name: &str = op.into(); - Err(anyhow!("FloatOpEmitter: unimplemented op: {name}")) - } - } - } -} +use super::CodegenExtsBuilder; /// Emit a float comparison operation. fn emit_fcmp<'c, H: HugrView>( @@ -179,12 +41,88 @@ fn emit_fcmp<'c, H: HugrView>( }) } -pub fn add_float_extensions(cem: CodegenExtsMap<'_, H>) -> CodegenExtsMap<'_, H> { - cem.add_cge(FloatTypesCodegenExtension) - .add_cge(FloatOpsCodegenExtension) +fn emit_float_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + op: FloatOps, +) -> Result<()> { + // We emit the float comparison variants where NaN is an absorbing value. + // Any comparison with NaN is always false. + #[allow(clippy::wildcard_in_or_patterns)] + match op { + FloatOps::feq => emit_fcmp(context, args, inkwell::FloatPredicate::OEQ), + FloatOps::fne => emit_fcmp(context, args, inkwell::FloatPredicate::ONE), + FloatOps::flt => emit_fcmp(context, args, inkwell::FloatPredicate::OLT), + FloatOps::fgt => emit_fcmp(context, args, inkwell::FloatPredicate::OGT), + FloatOps::fle => emit_fcmp(context, args, inkwell::FloatPredicate::OLE), + FloatOps::fge => emit_fcmp(context, args, inkwell::FloatPredicate::OGE), + FloatOps::fadd => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_float_add(lhs.into_float_value(), rhs.into_float_value(), "")? + .as_basic_value_enum()]) + }), + FloatOps::fsub => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_float_sub(lhs.into_float_value(), rhs.into_float_value(), "")? + .as_basic_value_enum()]) + }), + FloatOps::fneg => emit_custom_unary_op(context, args, |ctx, v, _| { + Ok(vec![ctx + .builder() + .build_float_neg(v.into_float_value(), "")? + .as_basic_value_enum()]) + }), + FloatOps::fmul => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_float_mul(lhs.into_float_value(), rhs.into_float_value(), "")? + .as_basic_value_enum()]) + }), + FloatOps::fdiv => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_float_div(lhs.into_float_value(), rhs.into_float_value(), "")? + .as_basic_value_enum()]) + }), + // Missing ops, not supported by inkwell + FloatOps::fmax + | FloatOps::fmin + | FloatOps::fabs + | FloatOps::ffloor + | FloatOps::fceil + | FloatOps::ftostring + | _ => { + let name: &str = op.into(); + Err(anyhow!("FloatOpEmitter: unimplemented op: {name}")) + } + } +} + +fn emit_constf64<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + k: &ConstF64, +) -> Result> { + let ty: FloatType = context.llvm_type(&k.get_type())?.try_into().unwrap(); + Ok(ty.const_float(k.value()).as_basic_value_enum()) +} + +pub fn add_float_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, +) -> CodegenExtsBuilder<'a, H> { + cem.custom_type( + ( + float_types::EXTENSION_ID, + float_types::FLOAT64_CUSTOM_TYPE.name().clone(), + ), + |ts, _custom_type| Ok(ts.iw_context().f64_type().as_basic_type_enum()), + ) + .custom_const(emit_constf64) + .simple_extension_op::(emit_float_op) } -impl CodegenExtsMap<'_, H> { +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { pub fn add_float_extensions(self) -> Self { add_float_extensions(self) } diff --git a/src/custom/int.rs b/src/custom/int.rs index cb4ed9e..98903f1 100644 --- a/src/custom/int.rs +++ b/src/custom/int.rs @@ -1,10 +1,7 @@ -use std::{any::TypeId, collections::HashSet}; - use hugr::{ - extension::{simple_op::MakeExtensionOp, ExtensionId}, ops::{constant::CustomConst, ExtensionOp, NamedOp, Value}, std_extensions::arithmetic::{ - int_ops::{self, ConcreteIntOp, IntOpDef}, + int_ops::IntOpDef, int_types::{self, ConstInt}, }, types::{CustomType, TypeArg}, @@ -21,8 +18,8 @@ use crate::emit::{ }; use crate::types::TypingSession; -use super::{CodegenExtension, CodegenExtsMap}; -use anyhow::{anyhow, bail, Result}; +use super::CodegenExtsBuilder; +use anyhow::{anyhow, Result}; /// Emit an integer comparison operation. fn emit_icmp<'c, H: HugrView>( @@ -48,170 +45,115 @@ fn emit_icmp<'c, H: HugrView>( }) } -/// A [CodegenExtension] for the [hugr::std_extensions::arithmetic::int_ops] -/// extension. -/// -/// TODO: very incomplete -pub struct IntOpsCodegenExtension; - -impl CodegenExtension for IntOpsCodegenExtension { - fn extension(&self) -> ExtensionId { - int_ops::EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - _context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - Err(anyhow!( - "IntOpsCodegenExtension: unsupported type: {}", - hugr_type - )) - } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let iot = ConcreteIntOp::from_optype(&args.node().generalise()).ok_or(anyhow!( - "IntOpEmitter from_optype failed: {:?}", - args.node().as_ref() - ))?; - match iot.def { - IntOpDef::iadd => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_add(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::imul => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_mul(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::isub => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_sub(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::idiv_s => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_signed_div(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::idiv_u => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_unsigned_div(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::imod_s => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { - Ok(vec![ctx - .builder() - .build_int_signed_rem(lhs.into_int_value(), rhs.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::ineg => emit_custom_unary_op(context, args, |ctx, arg, _| { - Ok(vec![ctx - .builder() - .build_int_neg(arg.into_int_value(), "")? - .as_basic_value_enum()]) - }), - IntOpDef::ieq => emit_icmp(context, args, inkwell::IntPredicate::EQ), - IntOpDef::ilt_s => emit_icmp(context, args, inkwell::IntPredicate::SLT), - IntOpDef::igt_s => emit_icmp(context, args, inkwell::IntPredicate::SGT), - IntOpDef::ile_s => emit_icmp(context, args, inkwell::IntPredicate::SLE), - IntOpDef::ige_s => emit_icmp(context, args, inkwell::IntPredicate::SGE), - IntOpDef::ilt_u => emit_icmp(context, args, inkwell::IntPredicate::ULT), - IntOpDef::igt_u => emit_icmp(context, args, inkwell::IntPredicate::UGT), - IntOpDef::ile_u => emit_icmp(context, args, inkwell::IntPredicate::ULE), - IntOpDef::ige_u => emit_icmp(context, args, inkwell::IntPredicate::UGE), - _ => Err(anyhow!("IntOpEmitter: unimplemented op: {}", iot.name())), - } +fn emit_int_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + op: IntOpDef, +) -> Result<()> { + match op { + IntOpDef::iadd => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_add(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::imul => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_mul(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::isub => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_sub(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::idiv_s => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_signed_div(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::idiv_u => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_unsigned_div(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::imod_s => emit_custom_binary_op(context, args, |ctx, (lhs, rhs), _| { + Ok(vec![ctx + .builder() + .build_int_signed_rem(lhs.into_int_value(), rhs.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::ineg => emit_custom_unary_op(context, args, |ctx, arg, _| { + Ok(vec![ctx + .builder() + .build_int_neg(arg.into_int_value(), "")? + .as_basic_value_enum()]) + }), + IntOpDef::ieq => emit_icmp(context, args, inkwell::IntPredicate::EQ), + IntOpDef::ilt_s => emit_icmp(context, args, inkwell::IntPredicate::SLT), + IntOpDef::igt_s => emit_icmp(context, args, inkwell::IntPredicate::SGT), + IntOpDef::ile_s => emit_icmp(context, args, inkwell::IntPredicate::SLE), + IntOpDef::ige_s => emit_icmp(context, args, inkwell::IntPredicate::SGE), + IntOpDef::ilt_u => emit_icmp(context, args, inkwell::IntPredicate::ULT), + IntOpDef::igt_u => emit_icmp(context, args, inkwell::IntPredicate::UGT), + IntOpDef::ile_u => emit_icmp(context, args, inkwell::IntPredicate::ULE), + IntOpDef::ige_u => emit_icmp(context, args, inkwell::IntPredicate::UGE), + _ => Err(anyhow!("IntOpEmitter: unimplemented op: {}", op.name())), } } -/// A [CodegenExtension] for the [hugr::std_extensions::arithmetic::int_types] -/// extension. -pub struct IntTypesCodegenExtension; - -impl CodegenExtension for IntTypesCodegenExtension { - fn extension(&self) -> ExtensionId { - int_types::EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - if let [TypeArg::BoundedNat { n }] = hugr_type.args() { - let m = *n as usize; - if m < int_types::INT_TYPES.len() && int_types::INT_TYPES[m] == hugr_type.clone().into() - { - return Ok(match m { - 0..=3 => context.iw_context().i8_type(), - 4 => context.iw_context().i16_type(), - 5 => context.iw_context().i32_type(), - 6 => context.iw_context().i64_type(), - _ => Err(anyhow!( - "IntTypesCodegenExtension: unsupported log_width: {}", - m - ))?, - } - .into()); +fn llvm_type<'c>( + context: TypingSession<'c>, + hugr_type: &CustomType, +) -> Result> { + if let [TypeArg::BoundedNat { n }] = hugr_type.args() { + let m = *n as usize; + if m < int_types::INT_TYPES.len() && int_types::INT_TYPES[m] == hugr_type.clone().into() { + return Ok(match m { + 0..=3 => context.iw_context().i8_type(), + 4 => context.iw_context().i16_type(), + 5 => context.iw_context().i32_type(), + 6 => context.iw_context().i64_type(), + _ => Err(anyhow!( + "IntTypesCodegenExtension: unsupported log_width: {}", + m + ))?, } + .into()); } - Err(anyhow!( - "IntTypesCodegenExtension: unsupported type: {}", - hugr_type - )) - } - - fn emit_extension_op<'c>( - &self, - _: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - bail!("Unsupported op: {:?}", args.node().as_ref()) - } - - fn supported_consts(&self) -> HashSet { - [TypeId::of::()].into_iter().collect() } + Err(anyhow!( + "IntTypesCodegenExtension: unsupported type: {}", + hugr_type + )) +} - fn load_constant<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn CustomConst, - ) -> Result>> { - let Some(k) = konst.downcast_ref::() else { - return Ok(None); - }; - let ty: IntType<'c> = context - .llvm_type(&k.get_type())? - .try_into() - .map_err(|_| anyhow!("Failed to get ConstInt as IntType"))?; - // k.value_u() is in two's complement representation of the exactly - // correct bit width, so we are safe to unconditionally retrieve the - // unsigned value and do no sign extension. - Ok(Some(ty.const_int(k.value_u(), false).into())) - } +fn emit_const_int<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + k: &ConstInt, +) -> Result> { + let ty: IntType = context.llvm_type(&k.get_type())?.try_into().unwrap(); + // k.value_u() is in two's complement representation of the exactly + // correct bit width, so we are safe to unconditionally retrieve the + // unsigned value and do no sign extension. + Ok(ty.const_int(k.value_u(), false).as_basic_value_enum()) } /// Populates a [CodegenExtsMap] with all extensions needed to lower int ops, /// types, and constants. -pub fn add_int_extensions(cem: CodegenExtsMap<'_, H>) -> CodegenExtsMap<'_, H> { - cem.add_cge(IntOpsCodegenExtension) - .add_cge(IntTypesCodegenExtension) +pub fn add_int_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, +) -> CodegenExtsBuilder<'a, H> { + cem.custom_const(emit_const_int) + .custom_type((int_types::EXTENSION_ID, "int".into()), llvm_type) + .simple_extension_op::(emit_int_op) } -impl CodegenExtsMap<'_, H> { +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { /// Populates a [CodegenExtsMap] with all extensions needed to lower int ops, /// types, and constants. pub fn add_int_extensions(self) -> Self { diff --git a/src/custom/load_constant.rs b/src/custom/load_constant.rs new file mode 100644 index 0000000..2314c5c --- /dev/null +++ b/src/custom/load_constant.rs @@ -0,0 +1,79 @@ +//! Provides the implementation for a collection of [CustomConst] callbacks. +use std::{any::TypeId, collections::HashMap}; + +use hugr::{ops::constant::CustomConst, HugrView}; +use inkwell::values::BasicValueEnum; + +use anyhow::{anyhow, bail, ensure, Result}; + +use crate::emit::EmitFuncContext; + +/// A helper trait for describing the callback used for emitting [CustomConst]s, +/// and for hanging documentation. We have the appropriate `Fn` as a supertrait, +/// and there is a blanket impl for that `Fn`. We do not intend users to impl +/// this trait. +/// +/// `LoadConstantFn` callbacks for `CC`, which must impl [CustomConst], should +/// materialise an appropriate [BasicValueEnum]. The type of this value must +/// match the result of [EmitFuncContext::llvm_type] on [CustomConst::get_type]. +/// +/// Callbacks may hold references with lifetimes older than `'a`. +pub trait LoadConstantFn<'a, H: ?Sized, CC: CustomConst + ?Sized>: + for<'c> Fn(&mut EmitFuncContext<'c, H>, &CC) -> Result> + 'a +{ +} + +impl< + 'a, + H: ?Sized, + CC: ?Sized + CustomConst, + F: 'a + ?Sized + for<'c> Fn(&mut EmitFuncContext<'c, H>, &CC) -> Result>, + > LoadConstantFn<'a, H, CC> for F +{ +} + +/// A collection of [LoadConstantFn] callbacks registered for various impls of [CustomConst]. +/// The callbacks are keyed by the [TypeId] of those impls. +#[derive(Default)] +pub struct LoadConstantsMap<'a, H>( + HashMap>>, +); + +impl<'a, H: HugrView> LoadConstantsMap<'a, H> { + /// Register a callback to emit a `CC` value. + /// + /// If a callback is already registered for that type, we will replace it. + pub fn custom_const( + &mut self, + handler: impl LoadConstantFn<'a, H, CC>, + ) { + self.0 + .insert(TypeId::of::(), Box::new(move |context, konst: &dyn CustomConst| { + let cc = konst + .downcast_ref::() + .ok_or(anyhow!("impossible! Failed to downcast in LoadConstantsMap::custom_const"))?; + handler(context, cc)} + )); + } + + /// Emit instructions to materialise `konst` by delegating to the + /// appropriate inner callbacks. + pub fn emit_load_constant<'c>( + &self, + context: &mut EmitFuncContext<'c, H>, + konst: &dyn CustomConst, + ) -> Result> { + let type_id = konst.type_id(); + let Some(handler) = self.0.get(&type_id) else { + bail!( + "No extension could load constant name: {} type_id: {type_id:?}", + konst.name() + ) + }; + let r = handler(context, konst)?; + let r_type = r.get_type(); + let konst_type = context.llvm_type(&konst.get_type())?; + ensure!(r_type == konst_type, "CustomConst handler returned a value of the wrong type. Expected: {konst_type} Actual: {r_type}"); + Ok(r) + } +} diff --git a/src/custom/logic.rs b/src/custom/logic.rs index 325e6f1..47116f7 100644 --- a/src/custom/logic.rs +++ b/src/custom/logic.rs @@ -1,105 +1,87 @@ use hugr::{ - extension::{simple_op::MakeExtensionOp, ExtensionId}, - ops::{ExtensionOp, Value}, + extension::simple_op::MakeExtensionOp, + ops::{ExtensionOp, NamedOp, Value}, std_extensions::logic::{self, LogicOp}, - types::{CustomType, SumType}, + types::SumType, HugrView, }; -use inkwell::{types::BasicTypeEnum, IntPredicate}; +use inkwell::IntPredicate; use crate::{ emit::{emit_value, func::EmitFuncContext, EmitOpArgs}, sum::LLVMSumValue, - types::TypingSession, }; -use super::{CodegenExtension, CodegenExtsMap}; +use super::CodegenExtsBuilder; use anyhow::{anyhow, Result}; -/// A [CodegenExtension] for the [hugr::std_extensions::logic] -/// extension. -pub struct LogicCodegenExtension; - -impl CodegenExtension for LogicCodegenExtension { - fn extension(&self) -> ExtensionId { - logic::EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - _context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - Err(anyhow!( - "LogicCodegenExtension: unsupported type: {}", - hugr_type - )) +fn emit_logic_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, +) -> Result<()> { + let lot = LogicOp::from_optype(&args.node().generalise()).ok_or(anyhow!( + "LogicOpEmitter: from_optype_failed: {:?}", + args.node().as_ref() + ))?; + let builder = context.builder(); + // Turn bool sum inputs into i1's + let mut inputs = vec![]; + for inp in args.inputs { + let bool_ty = context.llvm_sum_type(SumType::new_unary(2))?; + let bool_val = LLVMSumValue::try_new(inp, bool_ty)?; + inputs.push(bool_val.build_get_tag(builder)?); } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let lot = LogicOp::from_optype(&args.node().generalise()).ok_or(anyhow!( - "LogicOpEmitter: from_optype_failed: {:?}", - args.node().as_ref() - ))?; - let builder = context.builder(); - // Turn bool sum inputs into i1's - let mut inputs = vec![]; - for inp in args.inputs { - let bool_ty = context.llvm_sum_type(SumType::Unit { size: 2 })?; - let bool_val = LLVMSumValue::try_new(inp, bool_ty)?; - inputs.push(bool_val.build_get_tag(builder)?); - } - let res = match lot { - LogicOp::And => { - let mut acc = inputs[0]; - for inp in inputs.into_iter().skip(1) { - acc = builder.build_and(acc, inp, "")?; - } - acc - } - LogicOp::Or => { - let mut acc = inputs[0]; - for inp in inputs.into_iter().skip(1) { - acc = builder.build_or(acc, inp, "")?; - } - acc + let res = match lot { + LogicOp::And => { + let mut acc = inputs[0]; + for inp in inputs.into_iter().skip(1) { + acc = builder.build_and(acc, inp, "")?; } - LogicOp::Eq => { - let x = inputs.pop().unwrap(); - let y = inputs.pop().unwrap(); - let mut acc = builder.build_int_compare(IntPredicate::EQ, x, y, "")?; - for inp in inputs { - let eq = builder.build_int_compare(IntPredicate::EQ, inp, x, "")?; - acc = builder.build_and(acc, eq, "")?; - } - acc + acc + } + LogicOp::Or => { + let mut acc = inputs[0]; + for inp in inputs.into_iter().skip(1) { + acc = builder.build_or(acc, inp, "")?; } - op => { - return Err(anyhow!("LogicOpEmitter: Unknown op: {op:?}")); + acc + } + LogicOp::Eq => { + let x = inputs.pop().unwrap(); + let y = inputs.pop().unwrap(); + let mut acc = builder.build_int_compare(IntPredicate::EQ, x, y, "")?; + for inp in inputs { + let eq = builder.build_int_compare(IntPredicate::EQ, inp, x, "")?; + acc = builder.build_and(acc, eq, "")?; } - }; - // Turn result back into sum - let res = builder.build_int_cast(res, context.iw_context().bool_type(), "")?; - let true_val = emit_value(context, &Value::true_val())?; - let false_val = emit_value(context, &Value::false_val())?; - let res = context - .builder() - .build_select(res, true_val, false_val, "")?; - args.outputs.finish(context.builder(), vec![res]) - } + acc + } + op => { + return Err(anyhow!("LogicOpEmitter: Unknown op: {op:?}")); + } + }; + // Turn result back into sum + let res = builder.build_int_cast(res, context.iw_context().bool_type(), "")?; + let true_val = emit_value(context, &Value::true_val())?; + let false_val = emit_value(context, &Value::false_val())?; + let res = context + .builder() + .build_select(res, true_val, false_val, "")?; + args.outputs.finish(context.builder(), vec![res]) } /// Populates a [CodegenExtsMap] with all extensions needed to lower logic ops, /// types, and constants. -pub fn add_logic_extensions(cem: CodegenExtsMap<'_, H>) -> CodegenExtsMap<'_, H> { - cem.add_cge(LogicCodegenExtension) +pub fn add_logic_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, +) -> CodegenExtsBuilder<'a, H> { + cem.extension_op(logic::EXTENSION_ID, LogicOp::Eq.name(), emit_logic_op) + .extension_op(logic::EXTENSION_ID, LogicOp::And.name(), emit_logic_op) + .extension_op(logic::EXTENSION_ID, LogicOp::Or.name(), emit_logic_op) + .extension_op(logic::EXTENSION_ID, LogicOp::Not.name(), emit_logic_op) } -impl CodegenExtsMap<'_, H> { +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { /// Populates a [CodegenExtsMap] with all extensions needed to lower logic ops, /// types, and constants. pub fn add_logic_extensions(self) -> Self { diff --git a/src/custom/prelude.rs b/src/custom/prelude.rs index c5f001f..8d02552 100644 --- a/src/custom/prelude.rs +++ b/src/custom/prelude.rs @@ -1,17 +1,15 @@ -use std::{any::TypeId, collections::HashSet}; - use anyhow::{anyhow, Ok, Result}; use hugr::{ extension::{ prelude::{ - self, ArrayOp, ConstError, ConstExternalSymbol, ConstString, ConstUsize, MakeTuple, - UnpackTuple, ERROR_CUSTOM_TYPE, ERROR_TYPE, PANIC_OP_ID, PRINT_OP_ID, QB_T, - STRING_CUSTOM_TYPE, USIZE_T, + self, ArrayOp, ArrayOpDef, ConstError, ConstExternalSymbol, ConstString, ConstUsize, + MakeTuple, TupleOpDef, UnpackTuple, ARRAY_TYPE_NAME, ERROR_CUSTOM_TYPE, ERROR_TYPE, + STRING_CUSTOM_TYPE, }, simple_op::MakeExtensionOp as _, }, - ops::{constant::CustomConst, ExtensionOp}, - types::{CustomType, SumType, TypeArg, TypeEnum}, + ops::constant::CustomConst, + types::{SumType, TypeArg}, HugrView, }; use inkwell::{ @@ -25,13 +23,13 @@ use crate::{ emit::{ func::EmitFuncContext, libc::{emit_libc_abort, emit_libc_printf}, - EmitOpArgs, RowPromise, + RowPromise, }, sum::LLVMSumValue, types::TypingSession, }; -use super::{CodegenExtension, CodegenExtsMap}; +use super::{CodegenExtension, CodegenExtsBuilder}; pub mod array; @@ -52,19 +50,19 @@ pub mod array; pub trait PreludeCodegen: Clone { /// Return the llvm type of [hugr::extension::prelude::USIZE_T]. That type /// must be an [IntType]. - fn usize_type<'c, H: HugrView>(&self, session: &TypingSession<'c, H>) -> IntType<'c> { + fn usize_type<'c>(&self, session: &TypingSession<'c>) -> IntType<'c> { session.iw_context().i64_type() } /// Return the llvm type of [hugr::extension::prelude::QB_T]. - fn qubit_type<'c, H: HugrView>(&self, session: &TypingSession<'c, H>) -> impl BasicType<'c> { + fn qubit_type<'c>(&self, session: &TypingSession<'c>) -> impl BasicType<'c> { session.iw_context().i16_type() } /// Return the llvm type of [hugr::extension::prelude::array_type]. - fn array_type<'c, H: HugrView>( + fn array_type<'c>( &self, - _session: &TypingSession<'c, H>, + _session: &TypingSession<'c>, elem_ty: BasicTypeEnum<'c>, size: u64, ) -> impl BasicType<'c> { @@ -136,62 +134,105 @@ impl From for PreludeCodegenExtension { } } -impl CodegenExtension for PreludeCodegenExtension { - fn extension(&self) -> hugr::extension::ExtensionId { - prelude::PRELUDE_ID +impl CodegenExtension for PreludeCodegenExtension { + fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> where Self: 'a { + add_prelude_extensions(builder, self.0) } +} - fn llvm_type<'c>( - &self, - ts: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> anyhow::Result> { - let TypeEnum::Extension(qubit_custom_type) = QB_T.as_type_enum().clone() else { - panic!("Qubit is not a custom type: {QB_T:?}"); - }; - let TypeEnum::Extension(usize_custom_type) = USIZE_T.as_type_enum().clone() else { - panic!("usize is not a custom type: {USIZE_T:?}"); - }; - if &qubit_custom_type == hugr_type { - Ok(self.0.qubit_type(ts).as_basic_type_enum()) - } else if &usize_custom_type == hugr_type { - Ok(self.0.usize_type(ts).as_basic_type_enum()) - } else if &STRING_CUSTOM_TYPE == hugr_type { +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { + /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using `pcg` + /// as the implementation. + pub fn add_default_prelude_extensions(self) -> Self { + self.add_prelude_extensions(DefaultPreludeCodegen) + } + + /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using + /// [DefaultPreludeCodegen] as the implementation. + pub fn add_prelude_extensions(self, pcg: impl PreludeCodegen + 'a) -> Self { + self.add_extension(PreludeCodegenExtension::from(pcg)) + } +} + +/// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using `pcg` +/// as the implementation. +fn add_prelude_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, + pcg: impl PreludeCodegen + 'a, +) -> CodegenExtsBuilder<'a, H> { + cem.custom_type((prelude::PRELUDE_ID, "qubit".into()), { + let pcg = pcg.clone(); + move |ts, _| Ok(pcg.qubit_type(&ts).as_basic_type_enum()) + }) + .custom_type((prelude::PRELUDE_ID, "usize".into()), { + let pcg = pcg.clone(); + move |ts, _| Ok(pcg.usize_type(&ts).as_basic_type_enum()) + }) + .custom_type((prelude::PRELUDE_ID, STRING_CUSTOM_TYPE.name().clone()), { + move |ts, _| { + // TODO allow customising string type Ok(ts .iw_context() .i8_type() .ptr_type(AddressSpace::default()) .into()) - } else if &ERROR_CUSTOM_TYPE == hugr_type { + } + }) + .custom_type((prelude::PRELUDE_ID, ERROR_CUSTOM_TYPE.name().clone()), { + move |ts, _| { let ctx: &inkwell::context::Context = ts.iw_context(); let signal_ty = ctx.i32_type().into(); let message_ty = ctx.i8_type().ptr_type(AddressSpace::default()).into(); Ok(ctx.struct_type(&[signal_ty, message_ty], false).into()) - } else if hugr_type.name() == "array" { + } + }) + .custom_type((prelude::PRELUDE_ID, ARRAY_TYPE_NAME.into()), { + let pcg = pcg.clone(); + move |ts, hugr_type| { let [TypeArg::BoundedNat { n }, TypeArg::Type { ty }] = hugr_type.args() else { return Err(anyhow!("Invalid type args for array type")); }; let elem_ty = ts.llvm_type(ty)?; - Ok(self.0.array_type(ts, elem_ty, *n).as_basic_type_enum()) - } else { - Err(anyhow::anyhow!( - "Type not supported by prelude extension: {hugr_type:?}" - )) + Ok(pcg.array_type(&ts, elem_ty, *n).as_basic_type_enum()) } - } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let node = args.node(); - let name = node.def().name(); - if let Result::Ok(make_tuple) = MakeTuple::from_extension_op(&node) { - let llvm_sum_type = context.llvm_sum_type(SumType::new([make_tuple.0]))?; - let r = llvm_sum_type.build_tag(context.builder(), 0, args.inputs)?; - args.outputs.finish(context.builder(), [r]) - } else if let Result::Ok(unpack_tuple) = UnpackTuple::from_extension_op(&node) { + }) + .custom_const::(|context, k| { + let ty: IntType = context + .llvm_type(&k.get_type())? + .try_into() + .map_err(|_| anyhow!("Failed to get ConstUsize as IntType"))?; + Ok(ty.const_int(k.value(), false).into()) + }) + .custom_const::(|context, k| { + // TODO we should namespace these symbols + let llvm_type = context.llvm_type(&k.get_type())?; + let global = context.get_global(&k.symbol, llvm_type, k.constant)?; + Ok(context + .builder() + .build_load(global.as_pointer_value(), &k.symbol)?) + }) + .custom_const::(|context, k| { + // TODO we should allow overriding the representation of strings + let s = context.builder().build_global_string_ptr(k.value(), "")?; + Ok(s.as_basic_value_enum()) + }) + .custom_const::(|context, k| { + let builder = context.builder(); + let err_ty = context.llvm_type(&ERROR_TYPE)?.into_struct_type(); + let signal = err_ty + .get_field_type_at_index(0) + .unwrap() + .into_int_type() + .const_int(k.signal as u64, false); + let message = builder + .build_global_string_ptr(&k.message, "")? + .as_basic_value_enum(); + let err = err_ty.const_named_struct(&[signal.into(), message]); + Ok(err.into()) + }) + .simple_extension_op::(|context, args, op| match op { + TupleOpDef::UnpackTuple => { + let unpack_tuple = UnpackTuple::from_extension_op(args.node().as_ref())?; let llvm_sum_type = context.llvm_sum_type(SumType::new([unpack_tuple.0]))?; let llvm_sum_value = args .inputs @@ -201,108 +242,50 @@ impl CodegenExtension for PreludeCodegenExt .and_then(|v| LLVMSumValue::try_new(v, llvm_sum_type))?; let rs = llvm_sum_value.build_untag(context.builder(), 0)?; args.outputs.finish(context.builder(), rs) - } else if let Result::Ok(op) = ArrayOp::from_extension_op(&node) { - self.0.emit_array_op(context, op, args.inputs, args.outputs) - } else if *name == PRINT_OP_ID { + } + TupleOpDef::MakeTuple => { + let make_tuple = MakeTuple::from_extension_op(args.node().as_ref())?; + let llvm_sum_type = context.llvm_sum_type(SumType::new([make_tuple.0]))?; + let r = llvm_sum_type.build_tag(context.builder(), 0, args.inputs)?; + args.outputs.finish(context.builder(), [r]) + } + _ => Err(anyhow!("Unsupported TupleOpDef")), + }) + .simple_extension_op::({ + let pcg = pcg.clone(); + move |context, args, _| { + pcg.emit_array_op( + context, + ArrayOp::from_extension_op(args.node().as_ref())?, + args.inputs, + args.outputs, + ) + } + }) + .extension_op(prelude::PRELUDE_ID, prelude::PRINT_OP_ID, { + let pcg = pcg.clone(); + move |context, args| { let text = args.inputs[0]; - self.0.emit_print(context, text)?; + pcg.emit_print(context, text)?; args.outputs.finish(context.builder(), []) - } else if *name == PANIC_OP_ID { + } + }) + .extension_op(prelude::PRELUDE_ID, prelude::PANIC_OP_ID, { + let pcg = pcg.clone(); + move |context, args| { let builder = context.builder(); let err = args.inputs[0].into_struct_value(); let signal = builder.build_extract_value(err, 0, "")?.into_int_value(); let msg = builder.build_extract_value(err, 1, "")?; - self.0.emit_panic(context, signal, msg)?; + pcg.emit_panic(context, signal, msg)?; let returns = args .outputs .get_types() .map(|ty| ty.const_zero()) .collect_vec(); args.outputs.finish(context.builder(), returns) - } else { - Err(anyhow!("PreludeEmitter: Unknown op: {}", name)) - } - } - - fn supported_consts(&self) -> HashSet { - [ - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - ] - .into_iter() - .collect() - } - - fn load_constant<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn CustomConst, - ) -> Result>> { - if let Some(k) = konst.downcast_ref::() { - let ty: IntType<'c> = context - .llvm_type(&k.get_type())? - .try_into() - .map_err(|_| anyhow!("Failed to get ConstUsize as IntType"))?; - Ok(Some(ty.const_int(k.value(), false).into())) - } else if let Some(k) = konst.downcast_ref::() { - let llvm_type = context.llvm_type(&k.get_type())?; - let global = context.get_global(&k.symbol, llvm_type, k.constant)?; - Ok(Some( - context - .builder() - .build_load(global.as_pointer_value(), &k.symbol)?, - )) - } else if let Some(k) = konst.downcast_ref::() { - let s = context.builder().build_global_string_ptr(k.value(), "")?; - Ok(Some(s.as_basic_value_enum())) - } else if let Some(k) = konst.downcast_ref::() { - let builder = context.builder(); - let err_ty = context.llvm_type(&ERROR_TYPE)?.into_struct_type(); - let signal = err_ty - .get_field_type_at_index(0) - .unwrap() - .into_int_type() - .const_int(k.signal as u64, false); - let message = builder - .build_global_string_ptr(&k.message, "")? - .as_basic_value_enum(); - let err = err_ty.const_named_struct(&[signal.into(), message]); - Ok(Some(err.into())) - } else { - Ok(None) } - } -} - -/// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using `pcg` -/// as the implementation. -pub fn add_prelude_extensions<'c, H: HugrView>( - cem: CodegenExtsMap<'c, H>, - pcg: impl PreludeCodegen + 'c, -) -> CodegenExtsMap<'c, H> { - cem.add_cge(PreludeCodegenExtension(pcg)) -} - -/// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using -/// [DefaultPreludeCodegen] as the implementation. -pub fn add_default_prelude_extensions(cem: CodegenExtsMap) -> CodegenExtsMap { - cem.add_cge(PreludeCodegenExtension::from(DefaultPreludeCodegen)) -} - -impl<'c, H: HugrView> CodegenExtsMap<'c, H> { - /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using `pcg` - /// as the implementation. - pub fn add_default_prelude_extensions(self) -> Self { - add_default_prelude_extensions(self) - } - - /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using - /// [DefaultPreludeCodegen] as the implementation. - pub fn add_prelude_extensions(self, builder: impl PreludeCodegen + 'c) -> Self { - add_prelude_extensions(self, builder) - } + }) } #[cfg(test)] @@ -311,7 +294,7 @@ mod test { use hugr::extension::{PRELUDE, PRELUDE_REGISTRY}; use hugr::type_row; use hugr::types::{Type, TypeArg}; - use prelude::BOOL_T; + use prelude::{BOOL_T, PANIC_OP_ID, PRINT_OP_ID, QB_T, USIZE_T}; use rstest::rstest; use crate::check_emission; @@ -324,40 +307,40 @@ mod test { #[derive(Clone)] struct TestPreludeCodegen; impl PreludeCodegen for TestPreludeCodegen { - fn usize_type<'c, H: HugrView>(&self, session: &TypingSession<'c, H>) -> IntType<'c> { + fn usize_type<'c>(&self, session: &TypingSession<'c>) -> IntType<'c> { session.iw_context().i32_type() } - fn qubit_type<'c, H: HugrView>( + fn qubit_type<'c>( &self, - session: &TypingSession<'c, H>, + session: &TypingSession<'c>, ) -> impl BasicType<'c> { session.iw_context().f64_type() } } - #[rstest] - fn prelude_extension_types(llvm_ctx: TestContext) { - let ctx = llvm_ctx.iw_context(); - let ext: PreludeCodegenExtension = TestPreludeCodegen.into(); - let tc = llvm_ctx.get_typing_session(); - - let TypeEnum::Extension(qb_ct) = QB_T.as_type_enum().clone() else { - unreachable!() - }; - let TypeEnum::Extension(usize_ct) = USIZE_T.as_type_enum().clone() else { - unreachable!() - }; - - assert_eq!( - ctx.i32_type().as_basic_type_enum(), - ext.llvm_type(&tc, &usize_ct).unwrap() - ); - assert_eq!( - ctx.f64_type().as_basic_type_enum(), - ext.llvm_type(&tc, &qb_ct).unwrap() - ); - } + // #[rstest] + // fn prelude_extension_types(llvm_ctx: TestContext) { + // let ctx = llvm_ctx.iw_context(); + // let ext: PreludeCodegenExtension = TestPreludeCodegen.into(); + // let tc = llvm_ctx.get_typing_session(); + + // let TypeEnum::Extension(qb_ct) = QB_T.as_type_enum().clone() else { + // unreachable!() + // }; + // let TypeEnum::Extension(usize_ct) = USIZE_T.as_type_enum().clone() else { + // unreachable!() + // }; + + // assert_eq!( + // ctx.i32_type().as_basic_type_enum(), + // ext.llvm_type(&tc, &usize_ct).unwrap() + // ); + // assert_eq!( + // ctx.f64_type().as_basic_type_enum(), + // ext.llvm_type(&tc, &qb_ct).unwrap() + // ); + // } #[rstest] fn prelude_extension_types_in_test_context(mut llvm_ctx: TestContext) { @@ -373,10 +356,14 @@ mod test { ); } - #[rstest] - fn prelude_const_usize(mut llvm_ctx: TestContext) { - llvm_ctx.add_extensions(add_default_prelude_extensions); + #[rstest::fixture] + fn prelude_llvm_ctx(mut llvm_ctx: TestContext) -> TestContext { + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); + llvm_ctx + } + #[rstest] + fn prelude_const_usize(prelude_llvm_ctx: TestContext) { let hugr = SimpleHugrConfig::new() .with_outs(USIZE_T) .with_extensions(prelude::PRELUDE_REGISTRY.to_owned()) @@ -384,12 +371,11 @@ mod test { let k = builder.add_load_value(ConstUsize::new(17)); builder.finish_with_outputs([k]).unwrap() }); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } #[rstest] - fn prelude_const_external_symbol(mut llvm_ctx: TestContext) { - llvm_ctx.add_extensions(add_default_prelude_extensions); + fn prelude_const_external_symbol(prelude_llvm_ctx: TestContext) { let konst1 = ConstExternalSymbol::new("sym1", USIZE_T, true); let konst2 = ConstExternalSymbol::new( "sym2", @@ -405,11 +391,11 @@ mod test { let k2 = builder.add_load_value(konst2); builder.finish_with_outputs([k1, k2]).unwrap() }); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } #[rstest] - fn prelude_make_tuple(mut llvm_ctx: TestContext) { + fn prelude_make_tuple(prelude_llvm_ctx: TestContext) { let hugr = SimpleHugrConfig::new() .with_ins(vec![BOOL_T, BOOL_T]) .with_outs(Type::new_tuple(vec![BOOL_T, BOOL_T])) @@ -419,12 +405,11 @@ mod test { let r = builder.make_tuple(in_wires).unwrap(); builder.finish_with_outputs([r]).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } #[rstest] - fn prelude_unpack_tuple(mut llvm_ctx: TestContext) { + fn prelude_unpack_tuple(prelude_llvm_ctx: TestContext) { let hugr = SimpleHugrConfig::new() .with_ins(Type::new_tuple(vec![BOOL_T, BOOL_T])) .with_outs(vec![BOOL_T, BOOL_T]) @@ -438,12 +423,11 @@ mod test { .unwrap(); builder.finish_with_outputs(unpack.outputs()).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } #[rstest] - fn prelude_panic(mut llvm_ctx: TestContext) { + fn prelude_panic(prelude_llvm_ctx: TestContext) { let error_val = ConstError::new(42, "PANIC"); const TYPE_ARG_Q: TypeArg = TypeArg::Type { ty: QB_T }; let type_arg_2q: TypeArg = TypeArg::Sequence { @@ -471,12 +455,11 @@ mod test { builder.finish_with_outputs([q0, q1]).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } #[rstest] - fn prelude_print(mut llvm_ctx: TestContext) { + fn prelude_print(prelude_llvm_ctx: TestContext) { let greeting: ConstString = ConstString::new("Hello, world!".into()); let print_op = PRELUDE .instantiate_extension_op(&PRINT_OP_ID, [], &PRELUDE_REGISTRY) @@ -490,7 +473,6 @@ mod test { builder.finish_with_outputs([]).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); - check_emission!(hugr, llvm_ctx); + check_emission!(hugr, prelude_llvm_ctx); } } diff --git a/src/custom/prelude/array.rs b/src/custom/prelude/array.rs index af4c6c5..4551097 100644 --- a/src/custom/prelude/array.rs +++ b/src/custom/prelude/array.rs @@ -338,9 +338,9 @@ pub fn emit_array_op<'c, H: HugrView>( } /// Helper function to emit the pop operations. -fn emit_pop_op<'c, H: HugrView>( +fn emit_pop_op<'c>( builder: &Builder<'c>, - ts: &TypingSession<'c, H>, + ts: &TypingSession<'c>, elem_ty: HugrType, size: u64, array_v: ArrayValue<'c>, @@ -406,13 +406,9 @@ mod test { use rstest::rstest; use crate::{ - check_emission, - custom::prelude::add_default_prelude_extensions, - emit::test::SimpleHugrConfig, - test::{exec_ctx, llvm_ctx, TestContext}, - utils::{ + check_emission, custom::CodegenExtsBuilder, emit::test::SimpleHugrConfig, test::{exec_ctx, llvm_ctx, TestContext}, utils::{ array_op_builder, ArrayOpBuilder, IntOpBuilder, LogicOpBuilder, UnwrapBuilder as _, - }, + } }; #[rstest] @@ -425,7 +421,7 @@ mod test { .unwrap(); builder.finish_sub_container().unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); check_emission!(hugr, llvm_ctx); } @@ -440,7 +436,7 @@ mod test { builder.add_array_get(USIZE_T, 2, arr, us1).unwrap(); builder.finish_with_outputs([]).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); check_emission!(hugr, llvm_ctx); } @@ -495,7 +491,7 @@ mod test { }; builder.finish_with_outputs([r]).unwrap() }); - exec_ctx.add_extensions(add_default_prelude_extensions); + exec_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); assert_eq!(expected, exec_ctx.exec_hugr_u64(hugr, "main")); } diff --git a/src/custom/rotation.rs b/src/custom/rotation.rs index 85fc2ff..1316bc0 100644 --- a/src/custom/rotation.rs +++ b/src/custom/rotation.rs @@ -1,24 +1,18 @@ use anyhow::{anyhow, bail, Result}; -use std::any::TypeId; use hugr::{ - extension::{prelude::option_type, simple_op::MakeOpDef, ExtensionId}, - ops::{constant::CustomConst, ExtensionOp}, - types::CustomType, + extension::prelude::option_type, + ops::ExtensionOp, HugrView, }; -use inkwell::{ - types::{BasicTypeEnum, FloatType}, - values::BasicValueEnum, - FloatPredicate, -}; +use inkwell::{types::FloatType, values::BasicValueEnum, FloatPredicate}; use crate::{ emit::{get_intrinsic, EmitFuncContext, EmitOpArgs}, types::TypingSession, }; -use super::{CodegenExtension, CodegenExtsMap}; +use super::CodegenExtsBuilder; use tket2::extension::rotation::{ ConstRotation, RotationOp, ROTATION_CUSTOM_TYPE, ROTATION_EXTENSION_ID, ROTATION_TYPE, @@ -29,167 +23,142 @@ use tket2::extension::rotation::{ /// We lower [ROTATION_CUSTOM_TYPE] to an `f64`, representing a number of half-turns. pub struct RotationCodegenExtension; -fn llvm_angle_type<'c, H: HugrView>(ts: &TypingSession<'c, H>) -> FloatType<'c> { +fn llvm_angle_type<'c>(ts: &TypingSession<'c>) -> FloatType<'c> { ts.iw_context().f64_type() } -impl CodegenExtension for RotationCodegenExtension { - fn extension(&self) -> ExtensionId { - ROTATION_EXTENSION_ID - } - - fn llvm_type<'c>( - &self, - context: &TypingSession<'c, H>, - hugr_type: &CustomType, - ) -> Result> { - if hugr_type == &ROTATION_CUSTOM_TYPE { - Ok(llvm_angle_type(context).into()) - } else { - bail!("Unsupported type: {hugr_type}") +fn emit_rotation_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + op: RotationOp, +) -> Result<()> { + let ts = context.typing_session(); + let module = context.get_current_module(); + let builder = context.builder(); + let angle_ty = llvm_angle_type(&ts); + + match op { + RotationOp::radd => { + let [lhs, rhs] = args + .inputs + .try_into() + .map_err(|_| anyhow!("RotationOp::radd expects two arguments"))?; + let (lhs, rhs) = (lhs.into_float_value(), rhs.into_float_value()); + let r = builder.build_float_add(lhs, rhs, "")?; + args.outputs.finish(builder, [r.into()]) } - } - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - let ts = context.typing_session(); - let module = context.get_current_module(); - let builder = context.builder(); - let angle_ty = llvm_angle_type(&ts); - - match RotationOp::from_op(&args.node())? { - RotationOp::radd => { - let [lhs, rhs] = args - .inputs - .try_into() - .map_err(|_| anyhow!("RotationOp::radd expects two arguments"))?; - let (lhs, rhs) = (lhs.into_float_value(), rhs.into_float_value()); - let r = builder.build_float_add(lhs, rhs, "")?; - args.outputs.finish(builder, [r.into()]) - } - RotationOp::from_halfturns => { - let [half_turns] = args - .inputs - .try_into() - .map_err(|_| anyhow!("RotationOp::from_halfturns expects one arguments"))?; - let half_turns = half_turns.into_float_value(); - - // We must distinguish {NaNs, infinities} from finite - // values. The `llvm.is.fpclass` intrinsic was introduced in llvm 15 - // and is the best way to do so. For now we are using llvm - // 14, and so we use 3 `feq`s. - // Below is commented code that we can use once we support llvm 15. - #[cfg(feature = "llvm14-0")] - let half_turns_ok = { - let is_pos_inf = builder.build_float_compare( - FloatPredicate::OEQ, - half_turns, - angle_ty.const_float(f64::INFINITY), - "", - )?; - let is_neg_inf = builder.build_float_compare( - FloatPredicate::OEQ, - half_turns, - angle_ty.const_float(f64::NEG_INFINITY), - "", - )?; - let is_nan = builder.build_float_compare( - FloatPredicate::UNO, - half_turns, - angle_ty.const_zero(), - "", - )?; - builder.build_not( - builder.build_or( - builder.build_or(is_pos_inf, is_neg_inf, "")?, - is_nan, - "", - )?, - "", - )? - }; - // let rads_ok = { - // let i32_ty = self.0.iw_context().i32_type(); - // let builder = self.0.builder(); - // let is_fpclass = get_intrinsic(module, "llvm.is.fpclass", [float_ty.as_basic_type_enum(), i32_ty.as_basic_type_enum()])?; - // // Here we pick out the following floats: - // // - bit 0: Signalling Nan - // // - bit 3: Negative normal - // // - bit 8: Positive normal - // let test = i32_ty.const_int((1 << 0) | (1 << 3) | (1 << 8), false); - // builder - // .build_call(is_fpclass, &[rads.into(), test.into()], "")? - // .try_as_basic_value() - // .left() - // .ok_or(anyhow!("llvm.is.fpclass has no return value"))? - // .into_int_value() - // }; - - let result_sum_type = ts.llvm_sum_type(option_type(ROTATION_TYPE))?; - let rads_success = - result_sum_type.build_tag(builder, 1, vec![half_turns.into()])?; - let rads_failure = result_sum_type.build_tag(builder, 0, vec![])?; - let result = builder.build_select(half_turns_ok, rads_success, rads_failure, "")?; - args.outputs.finish(builder, [result]) - } - RotationOp::to_halfturns => { - let [half_turns] = args - .inputs - .try_into() - .map_err(|_| anyhow!("RotationOp::tohalfturns expects one argument"))?; - let half_turns = half_turns.into_float_value(); - - // normalised_half_turns is in the interval 0..2 - let normalised_half_turns = { - // normalised_rads = (half_turns/2 - floor(half_turns/2)) * 2 - // note that floor(x) gives the largest integral value less - // than or equal to x so this deals with both positive and - // negative rads. - let turns = - builder.build_float_div(half_turns, angle_ty.const_float(2.0), "")?; - let floor_turns = { - let floor = get_intrinsic(module, "llvm.floor", [angle_ty.into()])?; - builder - .build_call(floor, &[turns.into()], "")? - .try_as_basic_value() - .left() - .ok_or(anyhow!("llvm.floor has no return value"))? - .into_float_value() - }; - let normalised_turns = builder.build_float_sub(turns, floor_turns, "")?; - builder.build_float_mul(normalised_turns, angle_ty.const_float(2.0), "")? + RotationOp::from_halfturns => { + let [half_turns] = args + .inputs + .try_into() + .map_err(|_| anyhow!("RotationOp::from_halfturns expects one arguments"))?; + let half_turns = half_turns.into_float_value(); + + // We must distinguish {NaNs, infinities} from finite + // values. The `llvm.is.fpclass` intrinsic was introduced in llvm 15 + // and is the best way to do so. For now we are using llvm + // 14, and so we use 3 `feq`s. + // Below is commented code that we can use once we support llvm 15. + #[cfg(feature = "llvm14-0")] + let half_turns_ok = { + let is_pos_inf = builder.build_float_compare( + FloatPredicate::OEQ, + half_turns, + angle_ty.const_float(f64::INFINITY), + "", + )?; + let is_neg_inf = builder.build_float_compare( + FloatPredicate::OEQ, + half_turns, + angle_ty.const_float(f64::NEG_INFINITY), + "", + )?; + let is_nan = builder.build_float_compare( + FloatPredicate::UNO, + half_turns, + angle_ty.const_zero(), + "", + )?; + builder.build_not( + builder.build_or(builder.build_or(is_pos_inf, is_neg_inf, "")?, is_nan, "")?, + "", + )? + }; + // let rads_ok = { + // let i32_ty = self.0.iw_context().i32_type(); + // let builder = self.0.builder(); + // let is_fpclass = get_intrinsic(module, "llvm.is.fpclass", [float_ty.as_basic_type_enum(), i32_ty.as_basic_type_enum()])?; + // // Here we pick out the following floats: + // // - bit 0: Signalling Nan + // // - bit 3: Negative normal + // // - bit 8: Positive normal + // let test = i32_ty.const_int((1 << 0) | (1 << 3) | (1 << 8), false); + // builder + // .build_call(is_fpclass, &[rads.into(), test.into()], "")? + // .try_as_basic_value() + // .left() + // .ok_or(anyhow!("llvm.is.fpclass has no return value"))? + // .into_int_value() + // }; + + let result_sum_type = ts.llvm_sum_type(option_type(ROTATION_TYPE))?; + let rads_success = result_sum_type.build_tag(builder, 1, vec![half_turns.into()])?; + let rads_failure = result_sum_type.build_tag(builder, 0, vec![])?; + let result = builder.build_select(half_turns_ok, rads_success, rads_failure, "")?; + args.outputs.finish(builder, [result]) + } + RotationOp::to_halfturns => { + let [half_turns] = args + .inputs + .try_into() + .map_err(|_| anyhow!("RotationOp::tohalfturns expects one argument"))?; + let half_turns = half_turns.into_float_value(); + + // normalised_half_turns is in the interval 0..2 + let normalised_half_turns = { + // normalised_rads = (half_turns/2 - floor(half_turns/2)) * 2 + // note that floor(x) gives the largest integral value less + // than or equal to x so this deals with both positive and + // negative rads. + let turns = builder.build_float_div(half_turns, angle_ty.const_float(2.0), "")?; + let floor_turns = { + let floor = get_intrinsic(module, "llvm.floor", [angle_ty.into()])?; + builder + .build_call(floor, &[turns.into()], "")? + .try_as_basic_value() + .left() + .ok_or(anyhow!("llvm.floor has no return value"))? + .into_float_value() }; - args.outputs.finish(builder, [normalised_half_turns.into()]) - } - op => bail!("Unsupported op: {op:?}"), + let normalised_turns = builder.build_float_sub(turns, floor_turns, "")?; + builder.build_float_mul(normalised_turns, angle_ty.const_float(2.0), "")? + }; + args.outputs.finish(builder, [normalised_half_turns.into()]) } + op => bail!("Unsupported op: {op:?}"), } +} - fn supported_consts(&self) -> std::collections::HashSet { - let of = TypeId::of::(); - [of].into_iter().collect() - } - - fn load_constant<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn CustomConst, - ) -> Result>> { - let Some(rotation) = konst.downcast_ref::() else { - return Ok(None); - }; - let angle_type = llvm_angle_type(&context.typing_session()); - Ok(Some(angle_type.const_float(rotation.half_turns()).into())) - } +fn emit_const_rotation<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + rotation: &ConstRotation, +) -> Result> { + let angle_ty = llvm_angle_type(&context.typing_session()); + Ok(angle_ty.const_float(rotation.half_turns()).into()) } -pub fn add_rotation_extensions(cge: CodegenExtsMap<'_, H>) -> CodegenExtsMap<'_, H> { - cge.add_cge(RotationCodegenExtension) +pub fn add_rotation_extensions<'a, H: HugrView + 'a>( + cge: CodegenExtsBuilder<'a, H>, +) -> CodegenExtsBuilder<'a, H> { + cge.custom_type( + (ROTATION_EXTENSION_ID, ROTATION_CUSTOM_TYPE.name().clone()), + |ts, _| Ok(llvm_angle_type(&ts).into()), + ) + .custom_const(emit_const_rotation) + .simple_extension_op(emit_rotation_op) } -impl<'c, H: HugrView> CodegenExtsMap<'c, H> { +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { pub fn add_rotation_extensions(self) -> Self { add_rotation_extensions(self) } @@ -197,12 +166,11 @@ impl<'c, H: HugrView> CodegenExtsMap<'c, H> { #[cfg(test)] mod test { - use std::collections::HashSet; use hugr::{ builder::{Dataflow, DataflowSubContainer as _, SubContainer}, extension::ExtensionSet, - ops::OpName, + ops::{constant::CustomConst, OpName}, std_extensions::arithmetic::float_types::{self, ConstF64, FLOAT64_TYPE}, }; use rstest::rstest; @@ -331,43 +299,21 @@ mod test { } } - struct NonFiniteConst64CodegenExtension; - - impl CodegenExtension for NonFiniteConst64CodegenExtension { - fn extension(&self) -> ExtensionId { - ExtensionId::new_unchecked("NonFiniteConst64") - } - - fn llvm_type<'c>( - &self, - _: &TypingSession<'c, H>, - _: &CustomType, - ) -> Result> { - panic!("no types") - } - - fn emit_extension_op<'c>( - &self, - _: &mut EmitFuncContext<'c, H>, - _: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - panic!("no ops") - } - - fn supported_consts(&self) -> HashSet { - let of = TypeId::of::(); - [of].into_iter().collect() + fn add_nonfinite_const_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, + ) -> CodegenExtsBuilder<'a, H> { + fn emit_nonfinite_const<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, H>, + konst: &NonFiniteConst64, + ) -> Result> { + Ok(context.iw_context().f64_type().const_float(konst.0).into()) } + cem.custom_const(emit_nonfinite_const) + } - fn load_constant<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - konst: &dyn CustomConst, - ) -> Result>> { - let Some(NonFiniteConst64(f)) = konst.downcast_ref::() else { - panic!("load_constant") - }; - Ok(Some(context.iw_context().f64_type().const_float(*f).into())) + impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { + fn add_nonfinite_const_extensions(self) -> Self { + add_nonfinite_const_extensions(self) } } @@ -428,7 +374,7 @@ mod test { cge.add_rotation_extensions() .add_default_prelude_extensions() .add_float_extensions() - .add_cge(NonFiniteConst64CodegenExtension) + .add_nonfinite_const_extensions() }); let r = exec_ctx.exec_hugr_f64(hugr, "main"); diff --git a/src/custom/types.rs b/src/custom/types.rs new file mode 100644 index 0000000..5eba67b --- /dev/null +++ b/src/custom/types.rs @@ -0,0 +1,79 @@ +use itertools::Itertools as _; + +use hugr::types::CustomType; + +use anyhow::{bail, Result}; +use inkwell::types::{BasicMetadataTypeEnum, BasicType as _, BasicTypeEnum, FunctionType}; + +use crate::{ + sum::LLVMSumType, + types::{HugrFuncType, HugrSumType, HugrType, TypingSession}, + utils::type_map::TypeMapping, +}; + +pub trait LLVMCustomTypeFn<'a>: + for<'c> Fn(TypingSession<'c>, &CustomType) -> Result> + 'a +{ +} + +impl< + 'a, + F: for<'c> Fn(TypingSession<'c>, &CustomType) -> Result> + 'a + ?Sized, + > LLVMCustomTypeFn<'a> for F +{ +} + +#[derive(Default, Clone)] +pub struct LLVMTypeMapping; + +impl TypeMapping for LLVMTypeMapping { + type InV<'c> = TypingSession<'c>; + + type OutV<'c> = BasicTypeEnum<'c>; + + type SumOutV<'c> = LLVMSumType<'c>; + + type FuncOutV<'c> = FunctionType<'c>; + + fn sum_into_out<'c>(&self, sum: Self::SumOutV<'c>) -> Self::OutV<'c> { + sum.as_basic_type_enum() + } + + fn func_into_out<'c>(&self, sum: Self::FuncOutV<'c>) -> Self::OutV<'c> { + sum.ptr_type(Default::default()).as_basic_type_enum() + } + + fn default_out<'c>(&self, hugr_type: &HugrType) -> Result> { + bail!("Unsupported type: {hugr_type}") + } + + fn map_sum_type<'c>( + &self, + sum_type: &HugrSumType, + context: TypingSession<'c>, + variants: impl IntoIterator>>, + ) -> Result> { + LLVMSumType::try_new2( + context.iw_context(), + variants.into_iter().collect(), + sum_type.clone(), + ) + } + + fn map_function_type<'c>( + &self, + _: &HugrFuncType, + context: TypingSession<'c>, + inputs: impl IntoIterator>, + outputs: impl IntoIterator>, + ) -> Result> { + let iw_context = context.iw_context(); + let inputs: Vec> = inputs.into_iter().map_into().collect_vec(); + let outputs = outputs.into_iter().collect_vec(); + Ok(match outputs.as_slice() { + &[] => iw_context.void_type().fn_type(&inputs, false), + [res] => res.fn_type(&inputs, false), + ress => iw_context.struct_type(ress, false).fn_type(&inputs, false), + }) + } +} diff --git a/src/emit.rs b/src/emit.rs index 6904da9..24ba824 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -17,11 +17,7 @@ use std::{collections::HashSet, rc::Rc}; use crate::types::{HugrFuncType, HugrSumType, HugrType, TypingSession}; -use crate::{ - custom::CodegenExtsMap, - fat::FatNode, - types::{LLVMSumType, TypeConverter}, -}; +use crate::{custom::CodegenExtsMap, fat::FatNode, types::LLVMSumType}; pub mod args; pub mod func; @@ -35,25 +31,21 @@ pub use namer::Namer; pub use ops::emit_value; pub struct EmitModuleContext<'c, H> { + iw_context: &'c Context, module: Module<'c>, - extensions: Rc>, - typer: Rc>, + extensions: Rc>, namer: Rc, } impl<'c, H> EmitModuleContext<'c, H> { delegate! { - to self.typer { - /// Returns a reference to the inner [Context]. - pub fn iw_context(&self) -> &'c Context; - } - to self.typer.clone() { + to self.typing_session() { /// Convert a [HugrType] into an LLVM [Type](BasicTypeEnum). - pub fn llvm_type(&self, [self.extensions()], hugr_type: &HugrType) -> Result>; + pub fn llvm_type(&self, hugr_type: &HugrType) -> Result>; /// Convert a [HugrFuncType] into an LLVM [FunctionType]. - pub fn llvm_func_type(&self, [self.extensions()], hugr_type: &HugrFuncType) -> Result>; + pub fn llvm_func_type(&self, hugr_type: &HugrFuncType) -> Result>; /// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType]. - pub fn llvm_sum_type(&self, [self.extensions()], sum_type: HugrSumType) -> Result>; + pub fn llvm_sum_type(&self, sum_type: HugrSumType) -> Result>; } to self.namer { @@ -62,19 +54,23 @@ impl<'c, H> EmitModuleContext<'c, H> { } } + pub fn iw_context(&self) -> &'c Context { + self.iw_context + } + /// Creates a new `EmitModuleContext`. We take ownership of the [Module], /// and return it in [EmitModuleContext::finish]. pub fn new( + iw_context: &'c Context, module: Module<'c>, namer: Rc, - extensions: Rc>, - typer: Rc>, + extensions: Rc>, ) -> Self { Self { + iw_context, module, namer, extensions, - typer, } } @@ -86,13 +82,16 @@ impl<'c, H> EmitModuleContext<'c, H> { } /// Returns a reference to the inner [CodegenExtsMap]. - pub fn extensions(&self) -> Rc> { + pub fn extensions(&self) -> Rc> { self.extensions.clone() } /// Returns a [TypingSession] constructed from it's members. - pub fn typing_session(&self) -> TypingSession<'c, H> { - self.typer.clone().session::(self.extensions()) + pub fn typing_session(&self) -> TypingSession<'c> { + self.extensions + .type_converter + .clone() + .session(self.iw_context) } fn get_func_impl( @@ -249,20 +248,15 @@ impl<'c, H: HugrView> EmitHugr<'c, H> { /// Creates a new `EmitHugr`. We take ownership of the [Module], and return it in [Self::finish]. pub fn new( - context: &'c Context, + iw_context: &'c Context, module: Module<'c>, namer: Rc, - extensions: Rc>, + extensions: Rc>, ) -> Self { - assert_eq!(context, &module.get_context()); + assert_eq!(iw_context, &module.get_context()); Self { emitted: Default::default(), - module_context: EmitModuleContext::new( - module, - namer, - extensions, - TypeConverter::new(context), - ), + module_context: EmitModuleContext::new(iw_context, module, namer, extensions), } } diff --git a/src/emit/func.rs b/src/emit/func.rs index 508bb8b..918f79f 100644 --- a/src/emit/func.rs +++ b/src/emit/func.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, rc::Rc}; use anyhow::{anyhow, Result}; use hugr::{ - ops::{FuncDecl, FuncDefn}, + ops::{constant::CustomConst, ExtensionOp, FuncDecl, FuncDefn}, types::Type, HugrView, NodeIndex, PortIndex, Wire, }; @@ -12,7 +12,7 @@ use inkwell::{ context::Context, module::Module, types::{BasicType, BasicTypeEnum, FunctionType}, - values::{FunctionValue, GlobalValue}, + values::{BasicValueEnum, FunctionValue, GlobalValue}, }; use itertools::zip_eq; @@ -22,7 +22,7 @@ use delegate::delegate; use self::mailbox::ValueMailBox; -use super::{EmissionSet, EmitModuleContext}; +use super::{EmissionSet, EmitModuleContext, EmitOpArgs}; mod mailbox; pub use mailbox::{RowMailBox, RowPromise}; @@ -59,9 +59,9 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> { /// Returns the inkwell [Context]. pub fn iw_context(&self) -> &'c Context; /// Returns the internal [CodegenExtsMap] . - pub fn extensions(&self) -> Rc>; + pub fn extensions(&self) -> Rc>; /// Returns a new [TypingSession]. - pub fn typing_session(&self) -> TypingSession<'c,H>; + pub fn typing_session(&self) -> TypingSession<'c>; /// Convert hugr [HugrType] into an LLVM [Type](BasicTypeEnum). pub fn llvm_type(&self, hugr_type: &HugrType) -> Result >; /// Convert a [HugrFuncType] into an LLVM [FunctionType]. @@ -291,6 +291,20 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> { self.emit_context.module() } + pub fn emit_custom_const(&mut self, v: &dyn CustomConst) -> Result> { + let exts = self.extensions(); + exts.as_ref() + .load_constant_handlers + .emit_load_constant(self, v) + } + + pub fn emit_extension_op(&mut self, args: EmitOpArgs<'c, '_, ExtensionOp, H>) -> Result<()> { + let exts = self.extensions(); + exts.as_ref() + .extension_op_handlers + .emit_extension_op(self, args) + } + /// Consumes the `EmitFuncContext` and returns both the inner /// [EmitModuleContext] and the scoped [FuncDefn]s that were encountered. pub fn finish(self) -> Result<(EmitModuleContext<'c, H>, EmissionSet)> { diff --git a/src/emit/ops.rs b/src/emit/ops.rs index 7fe2a82..a44d73d 100644 --- a/src/emit/ops.rs +++ b/src/emit/ops.rs @@ -116,10 +116,7 @@ pub fn emit_value<'c, H: HugrView>( v: &Value, ) -> Result> { match v { - Value::Extension { e } => { - let exts = context.extensions(); - exts.load_constant(context, e.value()) - } + Value::Extension { e } => context.emit_custom_const(e.value()), Value::Function { .. } => bail!( "Value::Function Const nodes are not supported. \ Ensure you eliminate these from the HUGR before lowering to LLVM. \ @@ -315,10 +312,7 @@ fn emit_optype<'c, H: HugrView>( OpType::Tag(ref tag) => emit_tag(context, args.into_ot(tag)), OpType::DFG(_) => emit_dataflow_parent(context, args), - OpType::ExtensionOp(ref co) => { - let extensions = context.extensions(); - extensions.emit(context, args.into_ot(co)) - } + OpType::ExtensionOp(ref co) => context.emit_extension_op(args.into_ot(co)), OpType::LoadConstant(ref lc) => emit_load_constant(context, args.into_ot(lc)), OpType::Call(ref cl) => emit_call(context, args.into_ot(cl)), OpType::CallIndirect(ref cl) => emit_call_indirect(context, args.into_ot(cl)), diff --git a/src/emit/ops/cfg.rs b/src/emit/ops/cfg.rs index 20171fd..483b65e 100644 --- a/src/emit/ops/cfg.rs +++ b/src/emit/ops/cfg.rs @@ -228,7 +228,7 @@ mod test { use rstest::rstest; use crate::custom::int::add_int_extensions; - use crate::custom::prelude::add_default_prelude_extensions; + use crate::custom::CodegenExtsBuilder; use crate::emit::test::SimpleHugrConfig; use crate::test::{llvm_ctx, TestContext}; @@ -287,7 +287,7 @@ mod test { let [cfg_out] = cfg.outputs_arr(); builder.finish_with_outputs([cfg_out]).unwrap() }); - llvm_ctx.add_extensions(add_default_prelude_extensions); + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); check_emission!(hugr, llvm_ctx); } diff --git a/src/emit/test.rs b/src/emit/test.rs index 66b1b82..ce0bf52 100644 --- a/src/emit/test.rs +++ b/src/emit/test.rs @@ -1,7 +1,7 @@ use std::iter; use crate::custom::int::add_int_extensions; -use crate::custom::prelude::add_default_prelude_extensions; +use crate::custom::CodegenExtsBuilder; use crate::fat::FatNode; use crate::types::HugrFuncType; use anyhow::{anyhow, Result}; @@ -516,6 +516,6 @@ fn test_exec(mut exec_ctx: TestContext) { let konst = builder.add_load_value(ConstUsize::new(42)); builder.finish_with_outputs([konst]).unwrap() }); - exec_ctx.add_extensions(add_default_prelude_extensions); + exec_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); assert_eq!(42, exec_ctx.exec_hugr_u64(hugr, "main")); } diff --git a/src/sum.rs b/src/sum.rs index 28ddaa3..1dad8fa 100644 --- a/src/sum.rs +++ b/src/sum.rs @@ -5,6 +5,7 @@ use delegate::delegate; use hugr::types::TypeRow; use inkwell::{ builder::Builder, + context::Context, types::{AnyType, AsTypeRef, BasicType, BasicTypeEnum, IntType, StructType}, values::{AnyValue, AsValueRef, BasicValue, BasicValueEnum, IntValue, StructValue}, }; @@ -31,8 +32,25 @@ fn sum_type_has_tag_field(st: &HugrSumType) -> bool { pub struct LLVMSumType<'c>(StructType<'c>, HugrSumType); impl<'c> LLVMSumType<'c> { + pub fn try_new2( + context: &'c Context, + variants: Vec>>, + sum_type: HugrSumType, + ) -> Result { + let has_tag_field = sum_type_has_tag_field(&sum_type); + let types = has_tag_field + .then_some(context.i32_type().as_basic_type_enum()) + .into_iter() + .chain( + variants + .iter() + .map(|lty_vec| context.struct_type(lty_vec, false).into()), + ) + .collect_vec(); + Ok(Self(context.struct_type(&types, false), sum_type.clone())) + } /// Attempt to create a new `LLVMSumType` from a [HugrSumType]. - pub fn try_new(session: &TypingSession<'c, H>, sum_type: HugrSumType) -> Result { + pub fn try_new(session: &TypingSession<'c>, sum_type: HugrSumType) -> Result { assert!(sum_type.num_variants() < u32::MAX as usize); let variants = (0..sum_type.num_variants()) .map(|i| { @@ -42,20 +60,7 @@ impl<'c> LLVMSumType<'c> { .collect::>>() }) .collect::>>()?; - let has_tag_field = sum_type_has_tag_field(&sum_type); - let types = has_tag_field - .then_some(session.iw_context().i32_type().as_basic_type_enum()) - .into_iter() - .chain( - variants - .iter() - .map(|lty_vec| session.iw_context().struct_type(lty_vec, false).into()), - ) - .collect_vec(); - Ok(Self( - session.iw_context().struct_type(&types, false), - sum_type.clone(), - )) + Self::try_new2(session.iw_context(), variants, sum_type) } /// Returns an LLVM constant value of `undef`. diff --git a/src/test.rs b/src/test.rs index 46cc625..3cfcc83 100644 --- a/src/test.rs +++ b/src/test.rs @@ -9,7 +9,7 @@ use itertools::Itertools as _; use rstest::fixture; use crate::{ - custom::CodegenExtsMap, + custom::{CodegenExtsBuilder, CodegenExtsMap}, emit::{test::Emission, EmitHugr, EmitModuleContext, Namer}, fat::FatExt, types::{TypeConverter, TypingSession}, @@ -60,20 +60,33 @@ pub fn no_extensions(id: CodegenExtsMap<'_, THugrView>) -> CodegenExtsMap<'_, TH id } +pub trait MakeCodegenExtsMapFn: + Fn(CodegenExtsBuilder<'static, THugrView>) -> CodegenExtsBuilder<'static, THugrView> + 'static +{ +} + +impl< + 'a, + F: Fn(CodegenExtsBuilder<'static, THugrView>) -> CodegenExtsBuilder<'static, THugrView> + + ?Sized + 'static, + > MakeCodegenExtsMapFn for F +{ +} + +type MakeCodegenExtsMapBox = Box; // We would like to just stor a CodegenExtsMap, but we can't because it's // lifetime parameter would need to be the lifetime of TestContext, which is // prohibitted. Instead, we store a factory function as below. -type MakeCodegenExtsMapFn = Box Fn(&'a Context) -> CodegenExtsMap<'a, THugrView>>; pub struct TestContext { context: Context, - mk_exts: MakeCodegenExtsMapFn, + mk_exts: MakeCodegenExtsMapBox, _insta: Option, namer: Namer, } impl TestContext { fn new( - ext_builder: impl for<'a> Fn(&'a Context) -> CodegenExtsMap<'a, THugrView> + 'static, + ext_builder: impl MakeCodegenExtsMapFn + 'static, insta_settings: Option, ) -> Self { let context = Context::create(); @@ -89,53 +102,36 @@ impl TestContext { self.context.i32_type().as_basic_type_enum() } - pub fn type_converter(&'_ self) -> Rc> { - TypeConverter::new(&self.context) + pub fn type_converter(&self) -> Rc> { + self.extensions().type_converter } - pub fn extensions(&'_ self) -> Rc> { - Rc::new((self.mk_exts)(&self.context)) + pub fn extensions(&self) -> CodegenExtsMap<'static, THugrView> { + (self.mk_exts)(Default::default()).finish() } - pub fn add_extensions< - F: for<'a> Fn(CodegenExtsMap<'a, THugrView>) -> CodegenExtsMap<'a, THugrView> + 'static, - >( - &'_ mut self, - f: F, - ) { - self.add_extensions_with_context(move |_, exts| f(exts)) - } - - pub fn add_extensions_with_context< - F: for<'a> Fn(&'a Context, CodegenExtsMap<'a, THugrView>) -> CodegenExtsMap<'a, THugrView> - + 'static, - >( - &'_ mut self, - f: F, - ) { - fn dummy(_: &'_ Context) -> CodegenExtsMap<'_, THugrView> { - unreachable!() - } - let mut old_mk_exts: MakeCodegenExtsMapFn = Box::new(dummy); - std::mem::swap(&mut self.mk_exts, &mut old_mk_exts); - let new_mk_exts: MakeCodegenExtsMapFn = Box::new(move |ctx| f(ctx, (old_mk_exts)(ctx))); - self.mk_exts = new_mk_exts; + pub fn add_extensions(&'_ mut self, f: impl MakeCodegenExtsMapFn) { + let old_mk_exts = { + let mut tmp: MakeCodegenExtsMapBox = Box::new(|x| x); + std::mem::swap(&mut self.mk_exts, &mut tmp); + tmp + }; + self.mk_exts = Box::new(move |cem| f(old_mk_exts(cem))) } pub fn iw_context(&self) -> &Context { &self.context } - pub fn get_typing_session(&'_ self) -> TypingSession<'_, THugrView> { - self.type_converter().session(self.extensions()) + pub fn get_typing_session(&self) -> TypingSession { + self.type_converter().session(&self.context) } pub fn get_emit_hugr(&'_ self) -> EmitHugr<'_, THugrView> { let ctx = self.iw_context(); let m = ctx.create_module("test_context"); - let namer = self.namer.clone().into(); let exts = self.extensions(); - EmitHugr::new(ctx, m, namer, exts) + EmitHugr::new(ctx, m, Rc::new(self.namer.clone()), Rc::new(exts)) } pub fn set_namer(&mut self, namer: Namer) { @@ -146,10 +142,10 @@ impl TestContext { let ctx = self.iw_context(); let m = ctx.create_module("test_context"); EmitModuleContext::new( + &self.context, m, self.namer.clone().into(), - self.extensions(), - self.type_converter(), + self.extensions().into(), ) } @@ -175,7 +171,7 @@ impl TestContext { pub fn test_ctx(#[default(-1)] id: i32) -> TestContext { let id = (id >= 0).then_some(id as usize); TestContext::new( - |_| CodegenExtsMap::default(), + |_| CodegenExtsBuilder::default(), Some(InstaSettingsBuilder::new(id)), ) } @@ -184,7 +180,7 @@ pub fn test_ctx(#[default(-1)] id: i32) -> TestContext { pub fn llvm_ctx(#[default(-1)] id: i32) -> TestContext { let id = (id >= 0).then_some(id as usize); TestContext::new( - |_| CodegenExtsMap::default(), + |_| CodegenExtsBuilder::default(), Some(InstaSettingsBuilder::new_llvm(id)), ) } @@ -193,7 +189,7 @@ pub fn llvm_ctx(#[default(-1)] id: i32) -> TestContext { pub fn exec_ctx(#[default(-1)] id: i32) -> TestContext { let id = (id >= 0).then_some(id as usize); let mut r = TestContext::new( - |_| CodegenExtsMap::default(), + |_| CodegenExtsBuilder::default(), Some(InstaSettingsBuilder::new_llvm(id)), ); // we need to refer to functions by name, so no mangling diff --git a/src/types.rs b/src/types.rs index 8eac331..348bc64 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,18 +1,15 @@ use std::rc::Rc; -use anyhow::{anyhow, Result}; +use anyhow::Result; use delegate::delegate; -use hugr::types::{Signature, SumType, Type}; +use hugr::extension::ExtensionId; +use hugr::types::{SumType, Type, TypeName}; use inkwell::types::FunctionType; -use inkwell::AddressSpace; -use inkwell::{ - context::Context, - types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum}, -}; +use inkwell::{context::Context, types::BasicTypeEnum}; +use crate::custom::types::{LLVMCustomTypeFn, LLVMTypeMapping}; pub use crate::sum::LLVMSumType; - -use super::custom::CodegenExtsMap; +use crate::utils::type_map::TypeMap; /// A type alias for a hugr function type. We use this to disambiguate from /// the LLVM [FunctionType]. @@ -24,125 +21,91 @@ pub type HugrType = Type; /// A type alias for a hugr sum type. pub type HugrSumType = SumType; -/// This type is mostly vestigal, it does very little but hold a &[Context]. -/// -/// I had thought it would grow some configuration that it would use while -/// constructing a [TypingSession]. -#[derive(Copy, Clone, Debug)] -pub struct TypeConverter<'c> { - context: &'c Context, -} - /// A type that holds [Rc] shared pointers to everything needed to convert from /// a hugr [HugrType] to an LLVM [Type](inkwell::types). -pub struct TypingSession<'c, H> { - tc: Rc>, - extensions: Rc>, +pub struct TypingSession<'c> { + iw_context: &'c Context, + type_converter: Rc>, } -impl<'c, H> TypingSession<'c, H> { - delegate! { - to self.tc { - /// Returns a reference to the inner [Context]. - pub fn iw_context(&self) -> &'c Context; +// TODO this con be derived once H is killed +impl<'c> Clone for TypingSession<'c> { + fn clone(&self) -> Self { + Self { + iw_context: self.iw_context, + type_converter: self.type_converter.clone(), } } +} - /// Creates a new `TypingSession`. - pub fn new(tc: Rc>, extensions: Rc>) -> Self { - TypingSession { tc, extensions } - } - - /// Convert a [HugrType] into an LLVM [Type](BasicTypeEnum). - pub fn llvm_type(&self, hugr_type: &HugrType) -> Result> { - use hugr::types::TypeEnum; - match hugr_type.as_type_enum() { - TypeEnum::Extension(ref custom_type) => self.extensions.llvm_type(self, custom_type), - TypeEnum::Sum(sum) => self.llvm_sum_type(sum.clone()).map(Into::into), - TypeEnum::Function(func_ty) => { - let func_ty: Signature = func_ty.as_ref().clone().try_into()?; - Ok(self - .llvm_func_type(&func_ty)? - .ptr_type(AddressSpace::default()) // Note: deprecated in LLVM >= 15 - .into()) - } - x => Err(anyhow!("Invalid type: {:?}", x)), +impl<'c> TypingSession<'c> { + delegate! { + to self.type_converter.clone() { + /// Convert a [HugrType] into an LLVM [Type](BasicTypeEnum). + pub fn llvm_type(&self, [self.clone()], hugr_type: &HugrType) -> Result>; + /// Convert a [HugrFuncType] into an LLVM [FunctionType]. + pub fn llvm_func_type(&self, [self.clone()], hugr_type: &HugrFuncType) -> Result>; + /// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType]. + pub fn llvm_sum_type(&self, [self.clone()], hugr_type: HugrSumType) -> Result>; } } - /// Convert a [HugrFuncType] into an LLVM [FunctionType]. - pub fn llvm_func_type( - &self, - hugr_type: &HugrFuncType, - ) -> Result> { - let args = hugr_type - .input() - .iter() - .map(|x| self.llvm_type(x).map(Into::::into)) - .collect::>>()?; - let res_unpacked = hugr_type - .output() - .iter() - .map(|x| self.llvm_type(x)) - .collect::>>()?; - - Ok(match res_unpacked.as_slice() { - &[] => self.iw_context().void_type().fn_type(&args, false), - [res] => res.fn_type(&args, false), - ress => self - .iw_context() - .struct_type(ress, false) - .fn_type(&args, false), - }) - } - - /// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType]. - pub fn llvm_sum_type(&self, sum_type: HugrSumType) -> Result> { - LLVMSumType::try_new(self, sum_type) - } -} - -impl<'c> TypeConverter<'c> { - /// Create a new `TypeConverter`. - pub fn new(context: &'c Context) -> Rc { - Self { context }.into() + /// Creates a new `TypingSession`. + pub fn new(iw_context: &'c Context, type_converter: Rc>) -> Self { + Self { + iw_context, + type_converter, + } } /// Returns a reference to the inner [Context]. pub fn iw_context(&self) -> &'c Context { - self.context + self.iw_context } +} + +#[derive(Default)] +pub struct TypeConverter<'a>(TypeMap<'a, LLVMTypeMapping>); - /// Creates a new [TypingSession]. - pub fn session(self: Rc, exts: Rc>) -> TypingSession<'c, H> { - TypingSession::new(self, exts) +impl<'a> TypeConverter<'a> { + pub(super) fn custom_type( + &mut self, + custom_type: (ExtensionId, TypeName), + handler: impl LLVMCustomTypeFn<'a>, + ) { + self.0.set_callback(custom_type, handler); } - /// Convert a [HugrType] into an LLVM [Type](BasicTypeEnum). - pub fn llvm_type( + pub fn llvm_type<'c>( self: Rc, - extensions: Rc>, + context: TypingSession<'c>, hugr_type: &HugrType, ) -> Result> { - self.session(extensions).llvm_type(hugr_type) + self.0.map_type(hugr_type, context) } - /// Convert a [HugrFuncType] into an LLVM [FunctionType]. - pub fn llvm_func_type( + pub fn llvm_func_type<'c>( self: Rc, - extensions: Rc>, + context: TypingSession<'c>, hugr_type: &HugrFuncType, ) -> Result> { - self.session(extensions).llvm_func_type(hugr_type) + self.0 + .map_function_type(hugr_type, context) } - /// Convert a hugr [HugrSumType] into an LLVM [LLVMSumType]. - pub fn llvm_sum_type( + pub fn llvm_sum_type<'c>( self: Rc, - extensions: Rc>, - sum_type: HugrSumType, + context: TypingSession<'c>, + hugr_type: HugrSumType, ) -> Result> { - self.session(extensions).llvm_sum_type(sum_type) + self.0 + .map_sum_type(&hugr_type, context) + } +} + +impl TypeConverter<'static> { + pub fn session(self: Rc, iw_context: &Context) -> TypingSession<'_> { + TypingSession::new(iw_context, self) } } diff --git a/src/utils.rs b/src/utils.rs index 45e8e57..c5301b0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,6 +4,7 @@ pub mod array_op_builder; pub mod inline_constant_functions; pub mod int_op_builder; pub mod logic_op_builder; +pub mod type_map; pub mod unwrap_builder; pub use array_op_builder::ArrayOpBuilder; diff --git a/src/utils/type_map.rs b/src/utils/type_map.rs new file mode 100644 index 0000000..19718bf --- /dev/null +++ b/src/utils/type_map.rs @@ -0,0 +1,124 @@ +//! Provides a generic mapping from [hugr::Type] to some domain. +use std::collections::HashMap; + +use hugr::{ + extension::ExtensionId, + types::{CustomType, TypeEnum, TypeName, TypeRow}, +}; + +use anyhow::{Result, anyhow}; + +use crate::types::{HugrFuncType, HugrSumType, HugrType}; + +pub trait TypeMapFnHelper<'c, TM: TypeMapping>: Fn(TM::InV<'c>, &CustomType) -> Result> {} +impl<'c, TM: TypeMapping, F> TypeMapFnHelper<'c, TM> for F where + F: Fn(TM::InV<'c>, &CustomType) -> Result> + ?Sized +{ +} + +pub trait TypeMappingFn<'a, TM: TypeMapping>: for<'c> TypeMapFnHelper<'c, TM> + 'a {} +impl<'a, TM: TypeMapping, F: for<'c> TypeMapFnHelper<'c, TM> + ?Sized + 'a> TypeMappingFn<'a, TM> for F {} + + +/// Desscribes a +pub trait TypeMapping { + type InV<'c>: Clone; + type OutV<'c>; + type SumOutV<'c>; + type FuncOutV<'c>; + + fn default_out<'c>(&self, hugr_type: &HugrType) -> Result>; + + fn sum_into_out<'c>(&self, sum: Self::SumOutV<'c>) -> Self::OutV<'c>; + + fn func_into_out<'c>(&self, sum: Self::FuncOutV<'c>) -> Self::OutV<'c>; + + fn map_sum_type<'c>( + &self, + sum_type: &HugrSumType, + inv: Self::InV<'c>, + variants: impl IntoIterator>>, + ) -> Result>; + + fn map_function_type<'c>( + &self, + function_type: &HugrFuncType, + inv: Self::InV<'c>, + inputs: impl IntoIterator>, + outputs: impl IntoIterator>, + ) -> Result>; // fn disaggregate_variants(sum_type: &HugrSumType, v: &Self::InV) -> impl Iterator>; +} + +pub type CustomTypeKey = (ExtensionId, TypeName); + +#[derive(Default)] +pub struct TypeMap<'a, TM: TypeMapping> { + type_map: TM, + custom_hooks: HashMap>>, +} + +impl<'a, TM: TypeMapping + 'a> TypeMap<'a, TM> { + pub fn set_callback(&mut self, hugr_type: CustomTypeKey, hook: impl TypeMappingFn<'a,TM> + 'a) -> bool{ + self.custom_hooks.insert(hugr_type, Box::new(hook)).is_none() + } + + pub fn map_type<'c>(&self, hugr_type: &HugrType, inv: TM::InV<'c>) -> Result> { + match hugr_type.as_type_enum() { + TypeEnum::Extension(custom_type) => self.custom_type(custom_type, inv), + TypeEnum::Sum(sum_type) => self + .map_sum_type(sum_type, inv) + .map(|x| self.type_map.sum_into_out(x)), + TypeEnum::Function(function_type) => self + .map_function_type(&function_type.as_ref().clone().try_into()?, inv) + .map(|x| self.type_map.func_into_out(x)), + _ => self.type_map.default_out(hugr_type) + } + } + + fn custom_type<'c>(&self, custom_type: &CustomType, inv: TM::InV<'c>) -> Result> { + let key = (custom_type.extension().clone(), custom_type.name().clone()); + let Some(handler) = self.custom_hooks.get(&key) else { + return self.type_map.default_out(&custom_type.clone().into()); + }; + handler(inv, custom_type) + } + + pub fn map_sum_type<'c>( + &self, + sum_type: &HugrSumType, + inv: TM::InV<'c>, + ) -> Result> { + let inv2 = inv.clone(); + self.type_map.map_sum_type( + sum_type, + inv, + (0..sum_type.num_variants()) + .map(move |i| { + let tr: TypeRow = sum_type.get_variant(i).unwrap().clone().try_into().unwrap(); + tr.iter() + .map(|t| self.map_type(t, inv2.clone())) + .collect::>>() + }) + .collect::>>()?, + ) + } + + pub fn map_function_type<'c>( + &self, + func_type: &HugrFuncType, + inv: TM::InV<'c>, + ) -> Result> { + let inputs = func_type + .input() + .iter() + .map(|t| self.map_type(t, inv.clone())) + .collect::>>()?; + let outputs = func_type + .output() + .iter() + .map(|t| self.map_type(t, inv.clone())) + .collect::>>()?; + self.type_map + .map_function_type(func_type, inv, inputs, outputs) + } +} diff --git a/tests/guppy.rs b/tests/guppy.rs deleted file mode 100644 index ae11794..0000000 --- a/tests/guppy.rs +++ /dev/null @@ -1,166 +0,0 @@ -use std::{ - env, - fmt::Display, - fs::File, - path::{Path, PathBuf}, -}; - -use anyhow::Result; -use hugr::{ - extension::{prelude, ExtensionId, ExtensionRegistry}, - ops::{DataflowOpTrait as _, ExtensionOp}, - std_extensions::arithmetic::{float_types, int_ops, int_types}, - types::CustomType, - Hugr, HugrView, -}; -use hugr_llvm::{ - custom::{CodegenExtension, CodegenExtsMap}, - emit::{deaggregate_call_result, EmitFuncContext, EmitHugr, EmitOpArgs, Namer}, - fat::FatExt as _, - types::TypingSession, -}; -use inkwell::{context::Context, module::Module, types::BasicTypeEnum}; -use itertools::Itertools as _; -use lazy_static::lazy_static; -use rstest::{fixture, rstest}; - -lazy_static! { - static ref EXTENSION_REGISTRY: ExtensionRegistry = ExtensionRegistry::try_new([ - int_ops::EXTENSION.to_owned(), - int_types::EXTENSION.to_owned(), - prelude::PRELUDE.to_owned(), - float_types::EXTENSION.to_owned(), - ]) - .unwrap(); -} - -// A toy codegen extension for "quantum.tket2" ops. -struct Tket2CodegenExtension; - -impl CodegenExtension for Tket2CodegenExtension { - fn extension(&self) -> ExtensionId { - ExtensionId::new("quantum.tket2").unwrap() - } - - fn llvm_type<'c>( - &self, - _context: &TypingSession<'c, H>, - _hugr_type: &CustomType, - ) -> anyhow::Result> { - unimplemented!() - } - - fn emit_extension_op<'c>( - &self, - context: &mut EmitFuncContext<'c, H>, - args: EmitOpArgs<'c, '_, ExtensionOp, H>, - ) -> Result<()> { - // we lower all ops by declaring an extern function of the same name - // and signature, and calling that function. - // let opaque = args.node().as_ref().clone().into_opaque(); - let node = args.node(); - let sig = node.signature(); - let func_type = context.llvm_func_type(&sig)?; - let func = context.get_extern_func(node.def().name(), func_type)?; - let call_args = args.inputs.into_iter().map_into().collect_vec(); - let builder = context.builder(); - let call_result = builder.build_call(func, &call_args, "")?; - let call_result = deaggregate_call_result(builder, call_result, args.outputs.len())?; - args.outputs.finish(builder, call_result) - } -} - -// drives `hugr-llvm` to produce an LLVM module from a Hugr. -fn hugr_to_module<'c>(context: &'c Context, hugr: &'c Hugr) -> Module<'c> { - let module = context.create_module("test_context"); - let namer = Namer::default().into(); - let exts = CodegenExtsMap::default() - .add_int_extensions() - .add_logic_extensions() - .add_default_prelude_extensions() - .add_float_extensions() - .add_cge(Tket2CodegenExtension); - let root = hugr.fat_root().unwrap(); - EmitHugr::new(context, module, namer, exts.into()) - .emit_module(root) - .unwrap() - .finish() -} - -struct TestConfig { - test_dir: PathBuf, -} - -impl TestConfig { - pub fn new() -> TestConfig { - let test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/guppy_test_cases"); - assert!(test_dir.is_dir()); - TestConfig { test_dir } - } -} - -impl TestConfig { - // invokes the path with python, expecting to recieve Hugr serialised as - // JSON on stdout. - fn get_guppy_output(&self, path: impl AsRef) -> Hugr { - let mut hugr: Hugr = - serde_json::from_reader(File::open(self.test_dir.join(path)).unwrap()).unwrap(); - hugr.update_validate(&EXTENSION_REGISTRY).unwrap(); - hugr - } - - fn run(&self, path: impl AsRef, opt: bool, go: impl FnOnce(String) -> T) -> T { - let hugr = self.get_guppy_output(path); - let context = Context::create(); - let module = hugr_to_module(&context, &hugr); - module - .verify() - .unwrap_or_else(|pp| panic!("Failed to verify module: {pp}")); - if opt { - let pb = inkwell::passes::PassManager::create(()); - pb.add_promote_memory_to_register_pass(); - pb.run_on(&module); - } - go(module.to_string()) - } -} - -#[fixture] -fn test_config() -> TestConfig { - TestConfig::new() -} - -fn with_suffix(s: impl Display, go: impl FnOnce() -> R) -> R { - let mut settings = insta::Settings::clone_current(); - let old_suffix = settings - .snapshot_suffix() - .map_or("".to_string(), |s| format!("{s}.")); - let llvm_str = hugr_llvm::llvm_version(); - settings.set_snapshot_suffix(format!("{old_suffix}{llvm_str}.{s}")); - settings.bind(go) -} - -macro_rules! guppy_test { - ($filename:expr, $testname:ident) => { - #[rstest] - #[ignore = "Guppy has not yet been upgraded to hugr-0.12.0"] - fn $testname(test_config: TestConfig) { - with_suffix("noopt", || { - test_config.run($filename, false, |module_string| { - insta::assert_snapshot!(module_string) - }); - }); - with_suffix("opt", || { - test_config.run($filename, true, |module_string| { - insta::assert_snapshot!(module_string) - }); - }); - } - }; -} - -guppy_test!("even_odd.py.json", even_odd); -guppy_test!("even_odd2.py.json", even_odd2); -guppy_test!("planqc-1.py.json", planqc1); -guppy_test!("planqc-2.py.json", planqc2); -guppy_test!("planqc-3.py.json", planqc3); From d333603f31870b40f1bc525418e7f426989d9ae6 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:07:17 +0100 Subject: [PATCH 2/9] wip --- src/custom.rs | 12 +++++--- src/custom/conversions.rs | 61 +++++++++++++++++++++++++++++++------ src/custom/extension_op.rs | 13 +++----- src/custom/int.rs | 5 +-- src/custom/load_constant.rs | 21 ++++++------- src/custom/prelude.rs | 56 +++++++++++++++++----------------- src/custom/prelude/array.rs | 8 +++-- src/custom/rotation.rs | 6 +--- src/test.rs | 3 +- src/types.rs | 6 ++-- src/utils/type_map.rs | 25 ++++++++++----- 11 files changed, 130 insertions(+), 86 deletions(-) diff --git a/src/custom.rs b/src/custom.rs index 57075b9..498012f 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -12,9 +12,9 @@ use hugr::{ use strum::IntoEnumIterator; -use anyhow::Result; use self::load_constant::{LoadConstantFn, LoadConstantsMap}; use self::types::LLVMCustomTypeFn; +use anyhow::Result; use crate::{ emit::{func::EmitFuncContext, EmitOpArgs}, @@ -33,7 +33,6 @@ pub mod logic; pub mod prelude; pub mod rotation; - /// A helper to register codegen extensions. /// /// Types that implement this trait can be registered with a [CodgenExtsBuilder] @@ -43,8 +42,12 @@ pub mod rotation; pub trait CodegenExtension { /// Implementers should add each of their handlers to `builder` and return the /// resulting [CodegenExtsBuilder]. - fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> - where Self: 'a; + fn add_extension<'a, H: HugrView + 'a>( + self, + builder: CodegenExtsBuilder<'a, H>, + ) -> CodegenExtsBuilder<'a, H> + where + Self: 'a; } /// A container for a collection of codegen callbacks as they are being @@ -148,4 +151,3 @@ pub struct CodegenExtsMap<'a, H> { pub extension_op_handlers: Rc>, pub type_converter: Rc>, // TODO remove this H } - diff --git a/src/custom/conversions.rs b/src/custom/conversions.rs index 5f00351..553a64f 100644 --- a/src/custom/conversions.rs +++ b/src/custom/conversions.rs @@ -216,12 +216,17 @@ fn emit_conversion_op<'c, H: HugrView>( } } -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct ConversionExtension; impl CodegenExtension for ConversionExtension { - fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> - where Self: 'a { + fn add_extension<'a, H: HugrView + 'a>( + self, + builder: CodegenExtsBuilder<'a, H>, + ) -> CodegenExtsBuilder<'a, H> + where + Self: 'a, + { builder.simple_extension_op(emit_conversion_op) } } @@ -286,7 +291,11 @@ mod test { #[case("convert_u", 4)] #[case("convert_s", 5)] fn test_convert(mut llvm_ctx: TestContext, #[case] op_name: &str, #[case] log_width: u8) -> () { - llvm_ctx.add_extensions(|ceb| ceb.add_int_extensions().add_float_extensions().add_conversion_extensions()); + llvm_ctx.add_extensions(|ceb| { + ceb.add_int_extensions() + .add_float_extensions() + .add_conversion_extensions() + }); let in_ty = INT_TYPES[log_width as usize].clone(); let out_ty = FLOAT64_TYPE; let hugr = test_conversion_op(op_name, in_ty, out_ty, log_width); @@ -301,7 +310,13 @@ mod test { #[case] op_name: &str, #[case] log_width: u8, ) -> () { - llvm_ctx.add_extensions(|builder| builder.add_int_extensions().add_float_extensions().add_conversion_extensions().add_default_prelude_extensions()); + llvm_ctx.add_extensions(|builder| { + builder + .add_int_extensions() + .add_float_extensions() + .add_conversion_extensions() + .add_default_prelude_extensions() + }); let in_ty = FLOAT64_TYPE; let out_ty = sum_with_error(INT_TYPES[log_width as usize].clone()); let hugr = test_conversion_op(op_name, in_ty, out_ty.into(), log_width); @@ -321,7 +336,12 @@ mod test { tys.reverse() }; let [in_t, out_t] = tys; - llvm_ctx.add_extensions(|builder| builder.add_int_extensions().add_float_extensions().add_conversion_extensions()); + llvm_ctx.add_extensions(|builder| { + builder + .add_int_extensions() + .add_float_extensions() + .add_conversion_extensions() + }); let hugr = SimpleHugrConfig::new() .with_ins(vec![in_t]) .with_outs(vec![out_t]) @@ -373,7 +393,12 @@ mod test { .outputs_arr(); builder.finish_with_outputs([usize_]).unwrap() }); - exec_ctx.add_extensions(|builder| builder.add_int_extensions().add_conversion_extensions().add_default_prelude_extensions()); + exec_ctx.add_extensions(|builder| { + builder + .add_int_extensions() + .add_conversion_extensions() + .add_default_prelude_extensions() + }); assert_eq!(val, exec_ctx.exec_hugr_u64(hugr, "main")); } @@ -426,7 +451,13 @@ mod test { } fn add_extensions(ctx: &mut TestContext) { - ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_float_extensions().add_int_extensions()); + ctx.add_extensions(|builder| { + builder + .add_conversion_extensions() + .add_default_prelude_extensions() + .add_float_extensions() + .add_int_extensions() + }); } #[rstest] @@ -483,7 +514,12 @@ mod test { let res = cond.finish_sub_container().unwrap(); builder.finish_with_outputs(res.outputs()).unwrap() }); - exec_ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_int_extensions()); + exec_ctx.add_extensions(|builder| { + builder + .add_conversion_extensions() + .add_default_prelude_extensions() + .add_int_extensions() + }); assert_eq!(i * 5 + 1, exec_ctx.exec_hugr_u64(hugr, "main")); } @@ -504,7 +540,12 @@ mod test { let [i] = builder.add_dataflow_op(b2i, [b]).unwrap().outputs_arr(); builder.finish_with_outputs([i]).unwrap() }); - exec_ctx.add_extensions(|builder| builder.add_conversion_extensions().add_default_prelude_extensions().add_int_extensions()); + exec_ctx.add_extensions(|builder| { + builder + .add_conversion_extensions() + .add_default_prelude_extensions() + .add_int_extensions() + }); assert_eq!(i, exec_ctx.exec_hugr_u64(hugr, "main")); } } diff --git a/src/custom/extension_op.rs b/src/custom/extension_op.rs index 95340fc..bfd9417 100644 --- a/src/custom/extension_op.rs +++ b/src/custom/extension_op.rs @@ -15,7 +15,6 @@ use strum::IntoEnumIterator; use crate::emit::{EmitFuncContext, EmitOpArgs}; - /// A helper trait for describing the callback used for emitting [ExtensionOp]s, /// and for hanging documentation. We have the appropriate `Fn` as a supertrait, /// and there is a blanket impl for that `Fn`. We do not intend users to impl @@ -85,14 +84,10 @@ impl<'a, H: HugrView> ExtensionOpMap<'a, H> { let handler = Rc::new(handler); for op in Op::iter() { let handler = handler.clone(); - self.extension_op( - op.extension(), - op.name().clone(), - move |context, args| { - let op = Op::from_extension_op(&args.node())?; - handler(context, args, op) - } - ); + self.extension_op(op.extension(), op.name().clone(), move |context, args| { + let op = Op::from_extension_op(&args.node())?; + handler(context, args, op) + }); } } diff --git a/src/custom/int.rs b/src/custom/int.rs index 98903f1..784d455 100644 --- a/src/custom/int.rs +++ b/src/custom/int.rs @@ -106,10 +106,7 @@ fn emit_int_op<'c, H: HugrView>( } } -fn llvm_type<'c>( - context: TypingSession<'c>, - hugr_type: &CustomType, -) -> Result> { +fn llvm_type<'c>(context: TypingSession<'c>, hugr_type: &CustomType) -> Result> { if let [TypeArg::BoundedNat { n }] = hugr_type.args() { let m = *n as usize; if m < int_types::INT_TYPES.len() && int_types::INT_TYPES[m] == hugr_type.clone().into() { diff --git a/src/custom/load_constant.rs b/src/custom/load_constant.rs index 2314c5c..1954550 100644 --- a/src/custom/load_constant.rs +++ b/src/custom/load_constant.rs @@ -43,17 +43,16 @@ impl<'a, H: HugrView> LoadConstantsMap<'a, H> { /// Register a callback to emit a `CC` value. /// /// If a callback is already registered for that type, we will replace it. - pub fn custom_const( - &mut self, - handler: impl LoadConstantFn<'a, H, CC>, - ) { - self.0 - .insert(TypeId::of::(), Box::new(move |context, konst: &dyn CustomConst| { - let cc = konst - .downcast_ref::() - .ok_or(anyhow!("impossible! Failed to downcast in LoadConstantsMap::custom_const"))?; - handler(context, cc)} - )); + pub fn custom_const(&mut self, handler: impl LoadConstantFn<'a, H, CC>) { + self.0.insert( + TypeId::of::(), + Box::new(move |context, konst: &dyn CustomConst| { + let cc = konst.downcast_ref::().ok_or(anyhow!( + "impossible! Failed to downcast in LoadConstantsMap::custom_const" + ))?; + handler(context, cc) + }), + ); } /// Emit instructions to materialise `konst` by delegating to the diff --git a/src/custom/prelude.rs b/src/custom/prelude.rs index 8d02552..a27facf 100644 --- a/src/custom/prelude.rs +++ b/src/custom/prelude.rs @@ -135,7 +135,13 @@ impl From for PreludeCodegenExtension { } impl CodegenExtension for PreludeCodegenExtension { - fn add_extension<'a, H: HugrView + 'a>(self, builder: CodegenExtsBuilder<'a, H>) -> CodegenExtsBuilder<'a, H> where Self: 'a { + fn add_extension<'a, H: HugrView + 'a>( + self, + builder: CodegenExtsBuilder<'a, H>, + ) -> CodegenExtsBuilder<'a, H> + where + Self: 'a, + { add_prelude_extensions(builder, self.0) } } @@ -292,12 +298,13 @@ fn add_prelude_extensions<'a, H: HugrView + 'a>( mod test { use hugr::builder::{Dataflow, DataflowSubContainer}; use hugr::extension::{PRELUDE, PRELUDE_REGISTRY}; - use hugr::type_row; use hugr::types::{Type, TypeArg}; + use hugr::{type_row, Hugr}; use prelude::{BOOL_T, PANIC_OP_ID, PRINT_OP_ID, QB_T, USIZE_T}; use rstest::rstest; use crate::check_emission; + use crate::custom::CodegenExtsBuilder; use crate::emit::test::SimpleHugrConfig; use crate::test::{llvm_ctx, TestContext}; use crate::types::HugrType; @@ -311,36 +318,29 @@ mod test { session.iw_context().i32_type() } - fn qubit_type<'c>( - &self, - session: &TypingSession<'c>, - ) -> impl BasicType<'c> { + fn qubit_type<'c>(&self, session: &TypingSession<'c>) -> impl BasicType<'c> { session.iw_context().f64_type() } } - // #[rstest] - // fn prelude_extension_types(llvm_ctx: TestContext) { - // let ctx = llvm_ctx.iw_context(); - // let ext: PreludeCodegenExtension = TestPreludeCodegen.into(); - // let tc = llvm_ctx.get_typing_session(); - - // let TypeEnum::Extension(qb_ct) = QB_T.as_type_enum().clone() else { - // unreachable!() - // }; - // let TypeEnum::Extension(usize_ct) = USIZE_T.as_type_enum().clone() else { - // unreachable!() - // }; - - // assert_eq!( - // ctx.i32_type().as_basic_type_enum(), - // ext.llvm_type(&tc, &usize_ct).unwrap() - // ); - // assert_eq!( - // ctx.f64_type().as_basic_type_enum(), - // ext.llvm_type(&tc, &qb_ct).unwrap() - // ); - // } + #[rstest] + fn prelude_extension_types(llvm_ctx: TestContext) { + let iw_context = llvm_ctx.iw_context(); + let type_converter = CodegenExtsBuilder::::default() + .add_prelude_extensions(TestPreludeCodegen) + .finish() + .type_converter; + let session = type_converter.session(iw_context); + + assert_eq!( + iw_context.i32_type().as_basic_type_enum(), + session.llvm_type(&USIZE_T).unwrap() + ); + assert_eq!( + iw_context.f64_type().as_basic_type_enum(), + session.llvm_type(&QB_T).unwrap() + ); + } #[rstest] fn prelude_extension_types_in_test_context(mut llvm_ctx: TestContext) { diff --git a/src/custom/prelude/array.rs b/src/custom/prelude/array.rs index 4551097..865609c 100644 --- a/src/custom/prelude/array.rs +++ b/src/custom/prelude/array.rs @@ -406,9 +406,13 @@ mod test { use rstest::rstest; use crate::{ - check_emission, custom::CodegenExtsBuilder, emit::test::SimpleHugrConfig, test::{exec_ctx, llvm_ctx, TestContext}, utils::{ + check_emission, + custom::CodegenExtsBuilder, + emit::test::SimpleHugrConfig, + test::{exec_ctx, llvm_ctx, TestContext}, + utils::{ array_op_builder, ArrayOpBuilder, IntOpBuilder, LogicOpBuilder, UnwrapBuilder as _, - } + }, }; #[rstest] diff --git a/src/custom/rotation.rs b/src/custom/rotation.rs index 1316bc0..a24a81f 100644 --- a/src/custom/rotation.rs +++ b/src/custom/rotation.rs @@ -1,10 +1,6 @@ use anyhow::{anyhow, bail, Result}; -use hugr::{ - extension::prelude::option_type, - ops::ExtensionOp, - HugrView, -}; +use hugr::{extension::prelude::option_type, ops::ExtensionOp, HugrView}; use inkwell::{types::FloatType, values::BasicValueEnum, FloatPredicate}; use crate::{ diff --git a/src/test.rs b/src/test.rs index 3cfcc83..7e5d38e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -68,7 +68,8 @@ pub trait MakeCodegenExtsMapFn: impl< 'a, F: Fn(CodegenExtsBuilder<'static, THugrView>) -> CodegenExtsBuilder<'static, THugrView> - + ?Sized + 'static, + + ?Sized + + 'static, > MakeCodegenExtsMapFn for F { } diff --git a/src/types.rs b/src/types.rs index 348bc64..bf5524e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -89,8 +89,7 @@ impl<'a> TypeConverter<'a> { context: TypingSession<'c>, hugr_type: &HugrFuncType, ) -> Result> { - self.0 - .map_function_type(hugr_type, context) + self.0.map_function_type(hugr_type, context) } pub fn llvm_sum_type<'c>( @@ -98,8 +97,7 @@ impl<'a> TypeConverter<'a> { context: TypingSession<'c>, hugr_type: HugrSumType, ) -> Result> { - self.0 - .map_sum_type(&hugr_type, context) + self.0.map_sum_type(&hugr_type, context) } } diff --git a/src/utils/type_map.rs b/src/utils/type_map.rs index 19718bf..7fe22e6 100644 --- a/src/utils/type_map.rs +++ b/src/utils/type_map.rs @@ -6,19 +6,24 @@ use hugr::{ types::{CustomType, TypeEnum, TypeName, TypeRow}, }; -use anyhow::{Result, anyhow}; +use anyhow::Result; use crate::types::{HugrFuncType, HugrSumType, HugrType}; -pub trait TypeMapFnHelper<'c, TM: TypeMapping>: Fn(TM::InV<'c>, &CustomType) -> Result> {} +pub trait TypeMapFnHelper<'c, TM: TypeMapping>: + Fn(TM::InV<'c>, &CustomType) -> Result> +{ +} impl<'c, TM: TypeMapping, F> TypeMapFnHelper<'c, TM> for F where F: Fn(TM::InV<'c>, &CustomType) -> Result> + ?Sized { } pub trait TypeMappingFn<'a, TM: TypeMapping>: for<'c> TypeMapFnHelper<'c, TM> + 'a {} -impl<'a, TM: TypeMapping, F: for<'c> TypeMapFnHelper<'c, TM> + ?Sized + 'a> TypeMappingFn<'a, TM> for F {} - +impl<'a, TM: TypeMapping, F: for<'c> TypeMapFnHelper<'c, TM> + ?Sized + 'a> TypeMappingFn<'a, TM> + for F +{ +} /// Desscribes a pub trait TypeMapping { @@ -58,8 +63,14 @@ pub struct TypeMap<'a, TM: TypeMapping> { } impl<'a, TM: TypeMapping + 'a> TypeMap<'a, TM> { - pub fn set_callback(&mut self, hugr_type: CustomTypeKey, hook: impl TypeMappingFn<'a,TM> + 'a) -> bool{ - self.custom_hooks.insert(hugr_type, Box::new(hook)).is_none() + pub fn set_callback( + &mut self, + hugr_type: CustomTypeKey, + hook: impl TypeMappingFn<'a, TM> + 'a, + ) -> bool { + self.custom_hooks + .insert(hugr_type, Box::new(hook)) + .is_none() } pub fn map_type<'c>(&self, hugr_type: &HugrType, inv: TM::InV<'c>) -> Result> { @@ -71,7 +82,7 @@ impl<'a, TM: TypeMapping + 'a> TypeMap<'a, TM> { TypeEnum::Function(function_type) => self .map_function_type(&function_type.as_ref().clone().try_into()?, inv) .map(|x| self.type_map.func_into_out(x)), - _ => self.type_map.default_out(hugr_type) + _ => self.type_map.default_out(hugr_type), } } From 55b5a13edcc80b5e57bfac73bc0281470353369b Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:22:39 +0100 Subject: [PATCH 3/9] fmt --- src/custom/extension_op.rs | 2 +- src/custom/types.rs | 8 +--- src/test.rs | 1 - src/types.rs | 6 +-- src/utils/type_map.rs | 79 ++++++++++++++++++++++++++++---------- 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/custom/extension_op.rs b/src/custom/extension_op.rs index bfd9417..a9b0e42 100644 --- a/src/custom/extension_op.rs +++ b/src/custom/extension_op.rs @@ -31,7 +31,7 @@ use crate::emit::{EmitFuncContext, EmitOpArgs}; /// the desired semantics of the op. If a callback returns success then the callback must: /// - ensure that [RowPromise::finish] has been called on the outputs. /// - ensure that the contexts [Builder] is positioned at the end of a basic -/// block, logically after the execution of the just-emitted op. +/// block, logically after the execution of the just-emitted op. /// /// Callbacks may hold references with lifetimes older than `'a`. pub trait ExtensionOpFn<'a, H>: diff --git a/src/custom/types.rs b/src/custom/types.rs index 5eba67b..706bf99 100644 --- a/src/custom/types.rs +++ b/src/custom/types.rs @@ -2,12 +2,12 @@ use itertools::Itertools as _; use hugr::types::CustomType; -use anyhow::{bail, Result}; +use anyhow::Result; use inkwell::types::{BasicMetadataTypeEnum, BasicType as _, BasicTypeEnum, FunctionType}; use crate::{ sum::LLVMSumType, - types::{HugrFuncType, HugrSumType, HugrType, TypingSession}, + types::{HugrFuncType, HugrSumType, TypingSession}, utils::type_map::TypeMapping, }; @@ -43,10 +43,6 @@ impl TypeMapping for LLVMTypeMapping { sum.ptr_type(Default::default()).as_basic_type_enum() } - fn default_out<'c>(&self, hugr_type: &HugrType) -> Result> { - bail!("Unsupported type: {hugr_type}") - } - fn map_sum_type<'c>( &self, sum_type: &HugrSumType, diff --git a/src/test.rs b/src/test.rs index 7e5d38e..802cac5 100644 --- a/src/test.rs +++ b/src/test.rs @@ -66,7 +66,6 @@ pub trait MakeCodegenExtsMapFn: } impl< - 'a, F: Fn(CodegenExtsBuilder<'static, THugrView>) -> CodegenExtsBuilder<'static, THugrView> + ?Sized + 'static, diff --git a/src/types.rs b/src/types.rs index bf5524e..25784d5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -92,11 +92,11 @@ impl<'a> TypeConverter<'a> { self.0.map_function_type(hugr_type, context) } - pub fn llvm_sum_type<'c>( + pub fn llvm_sum_type( self: Rc, - context: TypingSession<'c>, + context: TypingSession<'_>, hugr_type: HugrSumType, - ) -> Result> { + ) -> Result> { self.0.map_sum_type(&hugr_type, context) } } diff --git a/src/utils/type_map.rs b/src/utils/type_map.rs index 7fe22e6..0d5a88e 100644 --- a/src/utils/type_map.rs +++ b/src/utils/type_map.rs @@ -1,4 +1,4 @@ -//! Provides a generic mapping from [hugr::Type] to some domain. +//! Provides a generic mapping from [hugr::Type] into some domain. use std::collections::HashMap; use hugr::{ @@ -6,7 +6,7 @@ use hugr::{ types::{CustomType, TypeEnum, TypeName, TypeRow}, }; -use anyhow::Result; +use anyhow::{bail, Result}; use crate::types::{HugrFuncType, HugrSumType, HugrType}; @@ -14,30 +14,36 @@ pub trait TypeMapFnHelper<'c, TM: TypeMapping>: Fn(TM::InV<'c>, &CustomType) -> Result> { } + impl<'c, TM: TypeMapping, F> TypeMapFnHelper<'c, TM> for F where F: Fn(TM::InV<'c>, &CustomType) -> Result> + ?Sized { } +/// A helper trait to name the type of the Callback used by +/// [TypeMap](TypeMap). pub trait TypeMappingFn<'a, TM: TypeMapping>: for<'c> TypeMapFnHelper<'c, TM> + 'a {} impl<'a, TM: TypeMapping, F: for<'c> TypeMapFnHelper<'c, TM> + ?Sized + 'a> TypeMappingFn<'a, TM> for F { } -/// Desscribes a +/// Defines a mapping from [HugrType] to `OutV`; pub trait TypeMapping { + /// Auxilliary data provided when mapping from a [HugrType]. type InV<'c>: Clone; + /// The target type of the mapping. type OutV<'c>; + /// The target type when mapping from [HugrSumType]s. This type must be + /// convertible to `OutV` via `sum_into_out`. type SumOutV<'c>; + /// The target type when mapping from [HugrFuncType]s. This type must be + /// convertible to `OutV` via `func_into_out`. type FuncOutV<'c>; - fn default_out<'c>(&self, hugr_type: &HugrType) -> Result>; - - fn sum_into_out<'c>(&self, sum: Self::SumOutV<'c>) -> Self::OutV<'c>; - - fn func_into_out<'c>(&self, sum: Self::FuncOutV<'c>) -> Self::OutV<'c>; - + /// Returns the result of the mapping on `sum_type`, with auxilliary data + /// `inv`, and when the result of mapping all fields of all variants is + /// given by `variants`. fn map_sum_type<'c>( &self, sum_type: &HugrSumType, @@ -45,6 +51,9 @@ pub trait TypeMapping { variants: impl IntoIterator>>, ) -> Result>; + /// Returns the result of the mapping on `function_type`, with auxilliary data + /// `inv`, and when the result of mapping all inputs is given by `inputs` + /// and the result of mapping all outputs is given by `outputs`. fn map_function_type<'c>( &self, function_type: &HugrFuncType, @@ -52,10 +61,32 @@ pub trait TypeMapping { inputs: impl IntoIterator>, outputs: impl IntoIterator>, ) -> Result>; // fn disaggregate_variants(sum_type: &HugrSumType, v: &Self::InV) -> impl Iterator>; + + /// Infallibly convert from the result of `map_sum_type` to the result of + /// the mapping. + fn sum_into_out<'c>(&self, sum: Self::SumOutV<'c>) -> Self::OutV<'c>; + + /// Infallibly convert from the result of `map_functype` to the result of + /// the mapping. + fn func_into_out<'c>(&self, sum: Self::FuncOutV<'c>) -> Self::OutV<'c>; + + /// Construct an appropriate result of the mapping when `hugr_type` is not a + /// function, sum, registered custom type, or composition of same. + fn default_out<'c>( + &self, + #[allow(unused)] inv: Self::InV<'c>, + hugr_type: &HugrType, + ) -> Result> { + bail!("Unknown type: {hugr_type}") + } } pub type CustomTypeKey = (ExtensionId, TypeName); +/// An impl of `TypeMapping` together with a collection of callbacks +/// implementing the mapping. +/// +/// Callbacks may hold references with lifetimes longer than `'a` #[derive(Default)] pub struct TypeMap<'a, TM: TypeMapping> { type_map: TM, @@ -63,37 +94,42 @@ pub struct TypeMap<'a, TM: TypeMapping> { } impl<'a, TM: TypeMapping + 'a> TypeMap<'a, TM> { + /// Sets the callback for the given custom type. + /// + /// Returns false if this callback replaces another callback, which is + /// discarded, and true otherwise. pub fn set_callback( &mut self, - hugr_type: CustomTypeKey, + custom_type_key: CustomTypeKey, hook: impl TypeMappingFn<'a, TM> + 'a, ) -> bool { self.custom_hooks - .insert(hugr_type, Box::new(hook)) + .insert(custom_type_key, Box::new(hook)) .is_none() } + /// Map `hugr_type` using the [TypeMapping] `TM`, the registered callbacks, + /// and the auxilliary data `inv`. pub fn map_type<'c>(&self, hugr_type: &HugrType, inv: TM::InV<'c>) -> Result> { match hugr_type.as_type_enum() { - TypeEnum::Extension(custom_type) => self.custom_type(custom_type, inv), + TypeEnum::Extension(custom_type) => { + let key = (custom_type.extension().clone(), custom_type.name().clone()); + let Some(handler) = self.custom_hooks.get(&key) else { + return self.type_map.default_out(inv, &custom_type.clone().into()); + }; + handler(inv, custom_type) + } TypeEnum::Sum(sum_type) => self .map_sum_type(sum_type, inv) .map(|x| self.type_map.sum_into_out(x)), TypeEnum::Function(function_type) => self .map_function_type(&function_type.as_ref().clone().try_into()?, inv) .map(|x| self.type_map.func_into_out(x)), - _ => self.type_map.default_out(hugr_type), + _ => self.type_map.default_out(inv, hugr_type), } } - fn custom_type<'c>(&self, custom_type: &CustomType, inv: TM::InV<'c>) -> Result> { - let key = (custom_type.extension().clone(), custom_type.name().clone()); - let Some(handler) = self.custom_hooks.get(&key) else { - return self.type_map.default_out(&custom_type.clone().into()); - }; - handler(inv, custom_type) - } - + /// As `map_type`, but maps a [HugrSumType] to an [TypeMapping::SumOutV]. pub fn map_sum_type<'c>( &self, sum_type: &HugrSumType, @@ -114,6 +150,7 @@ impl<'a, TM: TypeMapping + 'a> TypeMap<'a, TM> { ) } + /// As `map_type`, but maps a [HugrSumType] to an [TypeMapping::FuncOutV]. pub fn map_function_type<'c>( &self, func_type: &HugrFuncType, From 967dbe67b5174371c384f239ab92642e95dae03f Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:34:06 +0100 Subject: [PATCH 4/9] docs --- src/custom.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/custom.rs b/src/custom.rs index 498012f..e396764 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -1,5 +1,9 @@ //! Provides an interface for extending `hugr-llvm` to emit [CustomType]s, //! [CustomConst]s, and [ExtensionOp]s. +//! +//! [CustomType]: hugr::types::CustomType +//! [CustomConst]: hugr::ops::constant::CustomConst +//! [ExtensionOp]: hugr::ops::ExtensionOp use std::rc::Rc; use self::extension_op::{ExtensionOpFn, ExtensionOpMap}; @@ -11,6 +15,7 @@ use hugr::{ }; use strum::IntoEnumIterator; +use types::CustomTypeKey; use self::load_constant::{LoadConstantFn, LoadConstantsMap}; use self::types::LLVMCustomTypeFn; @@ -35,7 +40,7 @@ pub mod rotation; /// A helper to register codegen extensions. /// -/// Types that implement this trait can be registered with a [CodgenExtsBuilder] +/// Types that implement this trait can be registered with a [CodegenExtsBuilder] /// via [CodegenExtsBuilder::add_extension]. /// /// See [prelude::PreludeCodegenExtension] for an example. @@ -62,6 +67,8 @@ pub trait CodegenExtension { /// /// Registering any callback silently replaces any other callback registered for /// that same key. +/// +/// [CustomType]: hugr::types::CustomType #[derive(Default)] pub struct CodegenExtsBuilder<'a, H> { load_constant_handlers: LoadConstantsMap<'a, H>, @@ -81,17 +88,20 @@ impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { ext.add_extension(self) } - /// Register a callback to map a [hugr::CustomType] to a [BasicTypeEnum]. + /// Register a callback to map a [CustomType] to a [BasicTypeEnum]. + /// + /// [CustomType]: hugr::types::CustomType + /// [BasicTypeEnum]: inkwell::types::BasicTypeEnum pub fn custom_type( mut self, - custom_type: (ExtensionId, TypeName), + custom_type: CustomTypeKey, handler: impl LLVMCustomTypeFn<'a>, ) -> Self { self.type_converter.custom_type(custom_type, handler); self } - /// Register a callback to emit a [hugr::ExtensionOp], keyed by fully + /// Register a callback to emit a [ExtensionOp], keyed by fully /// qualified [OpName]. pub fn extension_op( mut self, @@ -104,7 +114,7 @@ impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { self } - /// Register callbacks to emit [hugr::ExtensionOp]s that match the + /// Register callbacks to emit [ExtensionOp]s that match the /// definitions generated by `Op`s impl of [strum::IntoEnumIterator]> pub fn simple_extension_op( mut self, From f7355eaeff65c9b200a56a0842258bb3ee9dc7d2 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:34:26 +0100 Subject: [PATCH 5/9] fmt --- src/custom.rs | 1 - src/custom/extension_op.rs | 8 ++++---- src/custom/int.rs | 8 ++++---- src/custom/logic.rs | 8 ++++---- src/custom/prelude.rs | 8 ++------ src/custom/types.rs | 2 ++ src/emit/args.rs | 2 +- src/utils/type_map.rs | 4 ++-- 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/custom.rs b/src/custom.rs index e396764..014d4ac 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -10,7 +10,6 @@ use self::extension_op::{ExtensionOpFn, ExtensionOpMap}; use hugr::{ extension::{simple_op::MakeOpDef, ExtensionId}, ops::{constant::CustomConst, ExtensionOp, OpName}, - types::TypeName, HugrView, }; diff --git a/src/custom/extension_op.rs b/src/custom/extension_op.rs index a9b0e42..b6afc97 100644 --- a/src/custom/extension_op.rs +++ b/src/custom/extension_op.rs @@ -29,8 +29,8 @@ use crate::emit::{EmitFuncContext, EmitOpArgs}; /// /// Callbacks should use the supplied [EmitFuncContext] to emit LLVM to match /// the desired semantics of the op. If a callback returns success then the callback must: -/// - ensure that [RowPromise::finish] has been called on the outputs. -/// - ensure that the contexts [Builder] is positioned at the end of a basic +/// - ensure that [crate::emit::func::RowPromise::finish] has been called on the outputs. +/// - ensure that the contexts [inkwell::builder::Builder] is positioned at the end of a basic /// block, logically after the execution of the just-emitted op. /// /// Callbacks may hold references with lifetimes older than `'a`. @@ -59,7 +59,7 @@ impl< pub struct ExtensionOpMap<'a, H>(HashMap<(ExtensionId, OpName), Box>>); impl<'a, H: HugrView> ExtensionOpMap<'a, H> { - /// Register a callback to emit a [hugr::ExtensionOp], keyed by fully + /// Register a callback to emit a [ExtensionOp], keyed by fully /// qualified [OpName]. pub fn extension_op( &mut self, @@ -70,7 +70,7 @@ impl<'a, H: HugrView> ExtensionOpMap<'a, H> { self.0.insert((extension, op), Box::new(handler)); } - /// Register callbacks to emit [hugr::ExtensionOp]s that match the + /// Register callbacks to emit [ExtensionOp]s that match the /// definitions generated by `Op`s impl of [strum::IntoEnumIterator]> pub fn simple_extension_op( &mut self, diff --git a/src/custom/int.rs b/src/custom/int.rs index 784d455..29ef697 100644 --- a/src/custom/int.rs +++ b/src/custom/int.rs @@ -140,8 +140,8 @@ fn emit_const_int<'c, H: HugrView>( Ok(ty.const_int(k.value_u(), false).as_basic_value_enum()) } -/// Populates a [CodegenExtsMap] with all extensions needed to lower int ops, -/// types, and constants. +/// Populates a [CodegenExtsBuilder] with all extensions needed to lower int +/// ops, types, and constants. pub fn add_int_extensions<'a, H: HugrView + 'a>( cem: CodegenExtsBuilder<'a, H>, ) -> CodegenExtsBuilder<'a, H> { @@ -151,8 +151,8 @@ pub fn add_int_extensions<'a, H: HugrView + 'a>( } impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { - /// Populates a [CodegenExtsMap] with all extensions needed to lower int ops, - /// types, and constants. + /// Populates a [CodegenExtsBuilder] with all extensions needed to lower int + /// ops, types, and constants. pub fn add_int_extensions(self) -> Self { add_int_extensions(self) } diff --git a/src/custom/logic.rs b/src/custom/logic.rs index 47116f7..09bafd2 100644 --- a/src/custom/logic.rs +++ b/src/custom/logic.rs @@ -70,8 +70,8 @@ fn emit_logic_op<'c, H: HugrView>( args.outputs.finish(context.builder(), vec![res]) } -/// Populates a [CodegenExtsMap] with all extensions needed to lower logic ops, -/// types, and constants. +/// Populates a [CodegenExtsBuilder] with all extensions needed to lower logic +/// ops. pub fn add_logic_extensions<'a, H: HugrView + 'a>( cem: CodegenExtsBuilder<'a, H>, ) -> CodegenExtsBuilder<'a, H> { @@ -82,8 +82,8 @@ pub fn add_logic_extensions<'a, H: HugrView + 'a>( } impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { - /// Populates a [CodegenExtsMap] with all extensions needed to lower logic ops, - /// types, and constants. + /// Populates a [CodegenExtsBuilder] with all extensions needed to lower + /// logic ops. pub fn add_logic_extensions(self) -> Self { add_logic_extensions(self) } diff --git a/src/custom/prelude.rs b/src/custom/prelude.rs index a27facf..6badfe7 100644 --- a/src/custom/prelude.rs +++ b/src/custom/prelude.rs @@ -40,10 +40,6 @@ pub mod array; /// trivial implementation of this trait, which delegates everything to those /// default implementations. /// -/// One should use either [PreludeCodegenExtension::new], or -/// [CodegenExtsMap::add_prelude_extensions] to work with the -/// [CodegenExtension]. -/// /// TODO several types and ops are unimplemented. We expect to add methods to /// this trait as necessary, allowing downstream users to customise the lowering /// of `prelude`. @@ -147,13 +143,13 @@ impl CodegenExtension for PreludeCodegenExtension { } impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { - /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using `pcg` + /// Add a [PreludeCodegenExtension] to the given [CodegenExtsBuilder] using `pcg` /// as the implementation. pub fn add_default_prelude_extensions(self) -> Self { self.add_prelude_extensions(DefaultPreludeCodegen) } - /// Add a [PreludeCodegenExtension] to the given [CodegenExtsMap] using + /// Add a [PreludeCodegenExtension] to the given [CodegenExtsBuilder] using /// [DefaultPreludeCodegen] as the implementation. pub fn add_prelude_extensions(self, pcg: impl PreludeCodegen + 'a) -> Self { self.add_extension(PreludeCodegenExtension::from(pcg)) diff --git a/src/custom/types.rs b/src/custom/types.rs index 706bf99..2284686 100644 --- a/src/custom/types.rs +++ b/src/custom/types.rs @@ -5,6 +5,8 @@ use hugr::types::CustomType; use anyhow::Result; use inkwell::types::{BasicMetadataTypeEnum, BasicType as _, BasicTypeEnum, FunctionType}; +pub use crate::utils::type_map::CustomTypeKey; + use crate::{ sum::LLVMSumType, types::{HugrFuncType, HugrSumType, TypingSession}, diff --git a/src/emit/args.rs b/src/emit/args.rs index 4f8a1b1..4dc64ef 100644 --- a/src/emit/args.rs +++ b/src/emit/args.rs @@ -6,7 +6,7 @@ use crate::fat::FatNode; use super::func::RowPromise; /// A type used whenever emission is delegated to a function, for example in -/// [crate::custom::CodegenExtension::emit_extension_op]. +/// [crate::custom::extension_op::ExtensionOpMap::emit_extension_op]. pub struct EmitOpArgs<'c, 'hugr, OT, H> { /// The [HugrView] and [hugr::Node] we are emitting pub node: FatNode<'hugr, OT, H>, diff --git a/src/utils/type_map.rs b/src/utils/type_map.rs index 0d5a88e..ba79f6d 100644 --- a/src/utils/type_map.rs +++ b/src/utils/type_map.rs @@ -1,4 +1,4 @@ -//! Provides a generic mapping from [hugr::Type] into some domain. +//! Provides a generic mapping from [HugrType] into some domain. use std::collections::HashMap; use hugr::{ @@ -21,7 +21,7 @@ impl<'c, TM: TypeMapping, F> TypeMapFnHelper<'c, TM> for F where } /// A helper trait to name the type of the Callback used by -/// [TypeMap](TypeMap). +/// [`TypeMap`](TypeMap). pub trait TypeMappingFn<'a, TM: TypeMapping>: for<'c> TypeMapFnHelper<'c, TM> + 'a {} impl<'a, TM: TypeMapping, F: for<'c> TypeMapFnHelper<'c, TM> + ?Sized + 'a> TypeMappingFn<'a, TM> for F From 8d15bea91dfad247ef4dc76e302a61170553084c Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:55:55 +0100 Subject: [PATCH 6/9] tweaks --- src/emit.rs | 6 ++++++ src/emit/func.rs | 14 +++++++------- src/types.rs | 13 +++---------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/emit.rs b/src/emit.rs index 24ba824..2b9f65b 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -30,6 +30,12 @@ pub use func::{EmitFuncContext, RowPromise}; pub use namer::Namer; pub use ops::emit_value; +/// A context holding data required for emitting HUGRs into an LLVM module. +/// This includes the module itself, a set of extensions for lowering custom +/// elements, and policy for naming various HUGR elements. +/// +/// `'c` names the lifetime of the LLVM context. +// TODO add another lifetime parameter for `extensions` below. pub struct EmitModuleContext<'c, H> { iw_context: &'c Context, module: Module<'c>, diff --git a/src/emit/func.rs b/src/emit/func.rs index 918f79f..e87c841 100644 --- a/src/emit/func.rs +++ b/src/emit/func.rs @@ -43,6 +43,8 @@ pub use mailbox::{RowMailBox, RowPromise}; /// [MailBox](RowMailBox)es are stack allocations that are `alloca`ed in the /// first basic block of the function, read from to get the input values of each /// node, and written to with the output values of each node. +/// +// TODO add another lifetime parameter which `emit_context` will need. pub struct EmitFuncContext<'c, H> { emit_context: EmitModuleContext<'c, H>, todo: EmissionSet, @@ -105,11 +107,6 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> { self.todo.insert(node.node()); } - // TODO likely we don't need this - // pub fn func(&self) -> &FunctionValue<'c> { - // &self.func - // } - /// Returns the internal [Builder]. Callers must ensure that it is /// positioned at the end of a basic block. This invariant is not checked(it /// doesn't seem possible to check it). @@ -291,14 +288,17 @@ impl<'c, H: HugrView> EmitFuncContext<'c, H> { self.emit_context.module() } - pub fn emit_custom_const(&mut self, v: &dyn CustomConst) -> Result> { + pub(crate) fn emit_custom_const(&mut self, v: &dyn CustomConst) -> Result> { let exts = self.extensions(); exts.as_ref() .load_constant_handlers .emit_load_constant(self, v) } - pub fn emit_extension_op(&mut self, args: EmitOpArgs<'c, '_, ExtensionOp, H>) -> Result<()> { + pub(crate) fn emit_extension_op( + &mut self, + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + ) -> Result<()> { let exts = self.extensions(); exts.as_ref() .extension_op_handlers diff --git a/src/types.rs b/src/types.rs index 25784d5..87353b0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -23,21 +23,14 @@ pub type HugrSumType = SumType; /// A type that holds [Rc] shared pointers to everything needed to convert from /// a hugr [HugrType] to an LLVM [Type](inkwell::types). +/// +// TODO add another lifetime parameter and substitute it for 'static in `type_converter` +#[derive(Clone)] pub struct TypingSession<'c> { iw_context: &'c Context, type_converter: Rc>, } -// TODO this con be derived once H is killed -impl<'c> Clone for TypingSession<'c> { - fn clone(&self) -> Self { - Self { - iw_context: self.iw_context, - type_converter: self.type_converter.clone(), - } - } -} - impl<'c> TypingSession<'c> { delegate! { to self.type_converter.clone() { From 04487d1ee840e23eebe37488ad7c6bdfb5ca1fa9 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 9 Oct 2024 14:58:38 +0100 Subject: [PATCH 7/9] fix --- src/utils/type_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/type_map.rs b/src/utils/type_map.rs index ba79f6d..b86a9c4 100644 --- a/src/utils/type_map.rs +++ b/src/utils/type_map.rs @@ -60,7 +60,7 @@ pub trait TypeMapping { inv: Self::InV<'c>, inputs: impl IntoIterator>, outputs: impl IntoIterator>, - ) -> Result>; // fn disaggregate_variants(sum_type: &HugrSumType, v: &Self::InV) -> impl Iterator>; + ) -> Result>; /// Infallibly convert from the result of `map_sum_type` to the result of /// the mapping. From 92285fd0d5e57e129afb8b1316f7ee8018a0bad9 Mon Sep 17 00:00:00 2001 From: Douglas Wilson <141026920+doug-q@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:04:44 +0100 Subject: [PATCH 8/9] Update src/custom.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Agustín Borgna <121866228+aborgna-q@users.noreply.github.com> --- src/custom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/custom.rs b/src/custom.rs index 014d4ac..5938cfd 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -57,7 +57,7 @@ pub trait CodegenExtension { /// A container for a collection of codegen callbacks as they are being /// assembled. /// -/// We callbacks are registered against several keys: +/// The callbacks are registered against several keys: /// - [CustomType]s, with [CodegenExtsBuilder::custom_type] /// - [CustomConst]s, with [CodegenExtsBuilder::custom_const] /// - [ExtensionOp]s, with [CodegenExtsBuilder::extension_op] From 69f3a12eff268f3f14db8a7c4597e0073dd59f2f Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Thu, 10 Oct 2024 09:05:59 +0100 Subject: [PATCH 9/9] address review --- src/custom.rs | 3 +- src/custom/prelude.rs | 1 + tests/guppy_test_cases/.gitattributes | 1 - tests/guppy_test_cases/even_odd.py | 21 ------------- tests/guppy_test_cases/even_odd.py.json | 1 - tests/guppy_test_cases/even_odd2.py | 22 ------------- tests/guppy_test_cases/even_odd2.py.json | 1 - tests/guppy_test_cases/planqc-1.py | 23 -------------- tests/guppy_test_cases/planqc-1.py.json | 1 - tests/guppy_test_cases/planqc-2.py | 29 ------------------ tests/guppy_test_cases/planqc-2.py.json | 1 - tests/guppy_test_cases/planqc-3.py | 39 ------------------------ tests/guppy_test_cases/planqc-3.py.json | 1 - 13 files changed, 3 insertions(+), 141 deletions(-) delete mode 100644 tests/guppy_test_cases/.gitattributes delete mode 100644 tests/guppy_test_cases/even_odd.py delete mode 100644 tests/guppy_test_cases/even_odd.py.json delete mode 100644 tests/guppy_test_cases/even_odd2.py delete mode 100644 tests/guppy_test_cases/even_odd2.py.json delete mode 100644 tests/guppy_test_cases/planqc-1.py delete mode 100644 tests/guppy_test_cases/planqc-1.py.json delete mode 100644 tests/guppy_test_cases/planqc-2.py delete mode 100644 tests/guppy_test_cases/planqc-2.py.json delete mode 100644 tests/guppy_test_cases/planqc-3.py delete mode 100644 tests/guppy_test_cases/planqc-3.py.json diff --git a/src/custom.rs b/src/custom.rs index 5938cfd..4c1ca1d 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -30,6 +30,7 @@ pub mod load_constant; pub mod types; // TODO move these extension implementations to crate::extension +// https://github.com/CQCL/hugr-llvm/issues/121 pub mod conversions; pub mod float; pub mod int; @@ -158,5 +159,5 @@ impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { pub struct CodegenExtsMap<'a, H> { pub load_constant_handlers: Rc>, pub extension_op_handlers: Rc>, - pub type_converter: Rc>, // TODO remove this H + pub type_converter: Rc>, } diff --git a/src/custom/prelude.rs b/src/custom/prelude.rs index 6badfe7..91bf1ce 100644 --- a/src/custom/prelude.rs +++ b/src/custom/prelude.rs @@ -207,6 +207,7 @@ fn add_prelude_extensions<'a, H: HugrView + 'a>( }) .custom_const::(|context, k| { // TODO we should namespace these symbols + // https://github.com/CQCL/hugr-llvm/issues/120 let llvm_type = context.llvm_type(&k.get_type())?; let global = context.get_global(&k.symbol, llvm_type, k.constant)?; Ok(context diff --git a/tests/guppy_test_cases/.gitattributes b/tests/guppy_test_cases/.gitattributes deleted file mode 100644 index 587b786..0000000 --- a/tests/guppy_test_cases/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.json -diff diff --git a/tests/guppy_test_cases/even_odd.py b/tests/guppy_test_cases/even_odd.py deleted file mode 100644 index 7f3469e..0000000 --- a/tests/guppy_test_cases/even_odd.py +++ /dev/null @@ -1,21 +0,0 @@ -from guppylang.decorator import guppy -from guppylang.module import GuppyModule - -main = GuppyModule("main") - - -@guppy(main) -def is_even(x: int) -> bool: - if x == 0: - return True - return is_odd(x - 1) - - -@guppy(main) -def is_odd(x: int) -> bool: - if x == 0: - return False - return is_even(x - 1) - -if __name__ == "__main__": - print(main.compile().serialize()) diff --git a/tests/guppy_test_cases/even_odd.py.json b/tests/guppy_test_cases/even_odd.py.json deleted file mode 100644 index 7a8aee5..0000000 --- a/tests/guppy_test_cases/even_odd.py.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"live","nodes":[{"parent":0,"op":"Module"},{"parent":31,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[],"sum_rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]],"extension_delta":[]},{"parent":50,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[],"sum_rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]],"extension_delta":[]},{"parent":31,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":50,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":29,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":1,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":36,"op":"Input","types":[]},{"parent":38,"op":"Input","types":[]},{"parent":40,"op":"Input","types":[]},{"parent":44,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":30,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":2,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":55,"op":"Input","types":[]},{"parent":57,"op":"Input","types":[]},{"parent":59,"op":"Input","types":[]},{"parent":63,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":36,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":38,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":1,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":40,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":44,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":29,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":55,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":57,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":2,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":59,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":63,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":30,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":0,"op":"FuncDefn","name":"is_even","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":0,"op":"FuncDefn","name":"is_odd","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":29,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":1,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":0}}}},{"parent":1,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":1,"op":"CustomOp","extension":"arithmetic.int","name":"ieq","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":1,"op":"Conditional","other_inputs":[],"outputs":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":35,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":36,"op":"Tag","tag":0,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":35,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":38,"op":"Tag","tag":1,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":31,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":40,"op":"Const","v":{"v":"Sum","tag":1,"typ":{"t":"Sum","s":"Unit","size":2},"vs":[]}},{"parent":40,"op":"LoadConstant","datatype":{"t":"Sum","s":"Unit","size":2}},{"parent":40,"op":"Tag","tag":0,"variants":[[]]},{"parent":31,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":44,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":1}}}},{"parent":44,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":44,"op":"CustomOp","extension":"arithmetic.int","name":"isub","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":44,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":44,"op":"Tag","tag":0,"variants":[[]]},{"parent":30,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":2,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":0}}}},{"parent":2,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":2,"op":"CustomOp","extension":"arithmetic.int","name":"ieq","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":2,"op":"Conditional","other_inputs":[],"outputs":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":54,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":55,"op":"Tag","tag":0,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":54,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":57,"op":"Tag","tag":1,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":50,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":59,"op":"Const","v":{"v":"Sum","tag":0,"typ":{"t":"Sum","s":"Unit","size":2},"vs":[]}},{"parent":59,"op":"LoadConstant","datatype":{"t":"Sum","s":"Unit","size":2}},{"parent":59,"op":"Tag","tag":0,"variants":[[]]},{"parent":50,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":63,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":1}}}},{"parent":63,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":63,"op":"CustomOp","extension":"arithmetic.int","name":"isub","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":63,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":63,"op":"Tag","tag":0,"variants":[[]]}],"edges":[[[29,0],[67,1]],[[30,0],[48,1]],[[5,0],[31,0]],[[31,0],[22,0]],[[1,0],[44,null]],[[1,1],[40,null]],[[6,0],[34,0]],[[6,0],[37,0]],[[32,0],[33,0]],[[33,0],[34,1]],[[34,0],[35,0]],[[35,0],[19,0]],[[37,0],[17,0]],[[39,0],[18,0]],[[40,0],[3,null]],[[41,0],[42,0]],[[42,0],[20,1]],[[43,0],[20,0]],[[44,0],[3,null]],[[10,0],[47,0]],[[45,0],[46,0]],[[46,0],[47,1]],[[47,0],[48,0]],[[48,0],[21,1]],[[49,0],[21,0]],[[11,0],[50,0]],[[50,0],[28,0]],[[2,0],[63,null]],[[2,1],[59,null]],[[12,0],[53,0]],[[12,0],[56,0]],[[51,0],[52,0]],[[52,0],[53,1]],[[53,0],[54,0]],[[54,0],[25,0]],[[56,0],[23,0]],[[58,0],[24,0]],[[59,0],[4,null]],[[60,0],[61,0]],[[61,0],[26,1]],[[62,0],[26,0]],[[63,0],[4,null]],[[16,0],[66,0]],[[64,0],[65,0]],[[65,0],[66,1]],[[66,0],[67,0]],[[67,0],[27,1]],[[68,0],[27,0]],[[6,null],[35,null]],[[12,null],[54,null]]],"metadata":null,"encoder":"hugr-py v0.5.0"} diff --git a/tests/guppy_test_cases/even_odd2.py b/tests/guppy_test_cases/even_odd2.py deleted file mode 100644 index 3dfd5a5..0000000 --- a/tests/guppy_test_cases/even_odd2.py +++ /dev/null @@ -1,22 +0,0 @@ -from guppylang.decorator import guppy -from guppylang.module import GuppyModule -from guppylang.prelude import quantum -from guppylang.prelude.quantum import measure, phased_x, qubit - -mod = GuppyModule("main") -mod.load(quantum) - -@guppy(mod) -def is_even(x: int) -> bool: - q = qubit() - return measure(h(q)) - - -@guppy(mod) -def is_odd(x: int) -> bool: - if x == 0: - return False - return is_even(x - 1) - -if __name__ == "__main__": - print(mod.compile().serialize()) diff --git a/tests/guppy_test_cases/even_odd2.py.json b/tests/guppy_test_cases/even_odd2.py.json deleted file mode 100644 index dea94bc..0000000 --- a/tests/guppy_test_cases/even_odd2.py.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"live","nodes":[{"parent":0,"op":"Module"},{"parent":23,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":30,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[],"sum_rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]],"extension_delta":[]},{"parent":23,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":30,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":21,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":1,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":22,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":2,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":35,"op":"Input","types":[]},{"parent":37,"op":"Input","types":[]},{"parent":39,"op":"Input","types":[]},{"parent":43,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":1,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":21,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":35,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":37,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":2,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":39,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":43,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":22,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":0,"op":"FuncDefn","name":"is_even","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":0,"op":"FuncDefn","name":"is_odd","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":21,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"Tag","tag":0,"variants":[[]]},{"parent":22,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":2,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":0}}}},{"parent":2,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":2,"op":"CustomOp","extension":"arithmetic.int","name":"ieq","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":2,"op":"Conditional","other_inputs":[],"outputs":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":34,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":35,"op":"Tag","tag":0,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":34,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":37,"op":"Tag","tag":1,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":30,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":39,"op":"Const","v":{"v":"Sum","tag":0,"typ":{"t":"Sum","s":"Unit","size":2},"vs":[]}},{"parent":39,"op":"LoadConstant","datatype":{"t":"Sum","s":"Unit","size":2}},{"parent":39,"op":"Tag","tag":0,"variants":[[]]},{"parent":30,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":43,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":1}}}},{"parent":43,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":43,"op":"CustomOp","extension":"arithmetic.int","name":"isub","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":43,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":43,"op":"Tag","tag":0,"variants":[[]]}],"edges":[[[21,0],[47,1]],[[5,0],[23,0]],[[23,0],[14,0]],[[1,0],[3,null]],[[24,0],[25,0]],[[25,0],[26,0]],[[26,0],[27,0]],[[27,0],[28,0]],[[27,1],[13,1]],[[29,0],[13,0]],[[7,0],[30,0]],[[30,0],[20,0]],[[2,0],[43,null]],[[2,1],[39,null]],[[8,0],[33,0]],[[8,0],[36,0]],[[31,0],[32,0]],[[32,0],[33,1]],[[33,0],[34,0]],[[34,0],[17,0]],[[36,0],[15,0]],[[38,0],[16,0]],[[39,0],[4,null]],[[40,0],[41,0]],[[41,0],[18,1]],[[42,0],[18,0]],[[43,0],[4,null]],[[12,0],[46,0]],[[44,0],[45,0]],[[45,0],[46,1]],[[46,0],[47,0]],[[47,0],[19,1]],[[48,0],[19,0]],[[8,null],[34,null]]],"metadata":null,"encoder":"hugr-py v0.5.0"} diff --git a/tests/guppy_test_cases/planqc-1.py b/tests/guppy_test_cases/planqc-1.py deleted file mode 100644 index 1023a3f..0000000 --- a/tests/guppy_test_cases/planqc-1.py +++ /dev/null @@ -1,23 +0,0 @@ -from guppylang.decorator import guppy -from guppylang.module import GuppyModule -from guppylang.prelude import quantum -from guppylang.prelude.quantum import measure, qubit, h, rz - -mod = GuppyModule("main") -mod.load(quantum) - -@guppy(mod) -def rx(q: qubit, x: float) -> qubit: - # Implement Rx via Rz rotation - return h(rz(h(q), x)) - - -@guppy(mod) -def main() -> bool: - q = qubit() - z = rx(q,1.5) - return measure(z) - -if __name__ == "__main__": - print(mod.compile().serialize()) - diff --git a/tests/guppy_test_cases/planqc-1.py.json b/tests/guppy_test_cases/planqc-1.py.json deleted file mode 100644 index 322ea89..0000000 --- a/tests/guppy_test_cases/planqc-1.py.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"live","nodes":[{"parent":0,"op":"Module"},{"parent":15,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":20,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":15,"op":"ExitBlock","cfg_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":20,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":13,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}]},{"parent":1,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}]},{"parent":14,"op":"Input","types":[]},{"parent":2,"op":"Input","types":[]},{"parent":1,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":13,"op":"Output","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":2,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":14,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":0,"op":"FuncDefn","name":"rx","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}}},{"parent":0,"op":"FuncDefn","name":"main","signature":{"params":[],"body":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":13,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"RzF64","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"Tag","tag":0,"variants":[[]]},{"parent":14,"op":"CFG","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.float.types"],"typ":{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"},"value":{"c":"ConstF64","v":{"value":1.5}}}},{"parent":2,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}},{"parent":2,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.float.types","id":"float64","args":[],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"Tag","tag":0,"variants":[[]]}],"edges":[[[13,0],[25,2]],[[5,0],[15,0]],[[5,1],[15,1]],[[15,0],[10,0]],[[1,0],[3,null]],[[6,0],[16,0]],[[6,1],[17,1]],[[16,0],[17,0]],[[17,0],[18,0]],[[18,0],[9,1]],[[19,0],[9,0]],[[20,0],[12,0]],[[2,0],[4,null]],[[21,0],[22,0]],[[22,0],[25,0]],[[23,0],[24,0]],[[24,0],[25,1]],[[25,0],[26,0]],[[26,0],[27,0]],[[26,1],[11,1]],[[28,0],[11,0]]],"metadata":null,"encoder":"hugr-py v0.5.0"} diff --git a/tests/guppy_test_cases/planqc-2.py b/tests/guppy_test_cases/planqc-2.py deleted file mode 100644 index f02f371..0000000 --- a/tests/guppy_test_cases/planqc-2.py +++ /dev/null @@ -1,29 +0,0 @@ -from guppylang.decorator import guppy -from guppylang.module import GuppyModule -from guppylang.prelude import quantum -from guppylang.prelude.quantum import measure, qubit, cx, h, z, x - -mod = GuppyModule("main") -mod.load(quantum) - -@guppy(mod) -def teleport( - src: qubit, tgt: qubit -) -> qubit: - # Entangle qubits with ancilla - tmp, tgt = cx(h(qubit()), tgt) - src, tmp = cx(src, tmp) - # Apply classical corrections - if measure(h(src)): - tgt = z(tgt) - if measure(tmp): - tgt = x(tgt) - return tgt - -@guppy(mod) -def main() -> bool: - q1,q2 = qubit(), qubit() # TODO initialise into some interesting state - return measure(teleport(q1,q2)) - -if __name__ == "__main__": - print(mod.compile().serialize()) diff --git a/tests/guppy_test_cases/planqc-2.py.json b/tests/guppy_test_cases/planqc-2.py.json deleted file mode 100644 index 3eddff9..0000000 --- a/tests/guppy_test_cases/planqc-2.py.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"live","nodes":[{"parent":0,"op":"Module"},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":55,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":27,"op":"ExitBlock","cfg_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":55,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":25,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":1,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":40,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":43,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":45,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":51,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":53,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":26,"op":"Input","types":[]},{"parent":2,"op":"Input","types":[]},{"parent":1,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":40,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":43,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":45,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":51,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":53,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":25,"op":"Output","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":2,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":26,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":0,"op":"FuncDefn","name":"teleport","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}}},{"parent":0,"op":"FuncDefn","name":"main","signature":{"params":[],"body":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":25,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"CX","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":1,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"CX","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":1,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":1,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":40,"op":"CustomOp","extension":"quantum.tket2","name":"Z","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":40,"op":"Tag","tag":0,"variants":[[]]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":43,"op":"Tag","tag":0,"variants":[[]]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":45,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":45,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"X","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"Tag","tag":0,"variants":[[]]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":51,"op":"Tag","tag":0,"variants":[[]]},{"parent":27,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":53,"op":"Tag","tag":0,"variants":[[]]},{"parent":26,"op":"CFG","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":2,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":2,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"Tag","tag":0,"variants":[[]]}],"edges":[[[25,0],[62,2]],[[5,0],[27,0]],[[5,1],[27,1]],[[27,0],[22,0]],[[1,0],[43,null]],[[1,1],[40,null]],[[6,1],[31,1]],[[6,0],[34,0]],[[28,0],[29,0]],[[29,0],[30,0]],[[30,0],[31,0]],[[31,0],[32,0]],[[31,1],[32,1]],[[32,0],[33,0]],[[33,0],[34,1]],[[33,1],[15,1]],[[34,0],[35,0]],[[34,1],[35,1]],[[35,0],[36,0]],[[36,0],[37,0]],[[36,1],[15,2]],[[37,0],[38,0]],[[38,0],[39,0]],[[38,1],[15,0]],[[40,0],[45,null]],[[7,0],[41,0]],[[7,1],[16,2]],[[41,0],[16,1]],[[42,0],[16,0]],[[43,0],[45,null]],[[8,0],[17,1]],[[8,1],[17,2]],[[44,0],[17,0]],[[45,0],[51,null]],[[45,1],[48,null]],[[9,1],[46,0]],[[9,0],[18,1]],[[46,0],[47,0]],[[46,1],[18,0]],[[48,0],[53,null]],[[10,0],[49,0]],[[49,0],[19,1]],[[50,0],[19,0]],[[51,0],[53,null]],[[11,0],[20,1]],[[52,0],[20,0]],[[53,0],[3,null]],[[12,0],[21,1]],[[54,0],[21,0]],[[55,0],[24,0]],[[2,0],[4,null]],[[56,0],[57,0]],[[57,0],[60,0]],[[58,0],[59,0]],[[59,0],[60,1]],[[60,0],[61,0]],[[61,0],[62,0]],[[61,1],[62,1]],[[62,0],[63,0]],[[63,0],[64,0]],[[63,1],[23,1]],[[65,0],[23,0]]],"metadata":null,"encoder":"hugr-py v0.5.0"} diff --git a/tests/guppy_test_cases/planqc-3.py b/tests/guppy_test_cases/planqc-3.py deleted file mode 100644 index d0ef399..0000000 --- a/tests/guppy_test_cases/planqc-3.py +++ /dev/null @@ -1,39 +0,0 @@ -from guppylang.decorator import guppy -from guppylang.module import GuppyModule -from guppylang.prelude import quantum -from guppylang.prelude.quantum import measure, qubit, cx, h, z, x, t, tdg, discard - -mod = GuppyModule("main") -mod.load(quantum) - -@guppy(mod) -def rus(q: qubit, tries: int) -> qubit: - i = 0; - while i < tries: - # Prepare ancillary qubits - a, b = h(qubit()), h(qubit()) - - b, a = cx(b, tdg(a)) - if not measure(t(a)): - # First part failed; try again - discard(b) - continue - - q, b = cx(z(t(q)), b) - if measure(t(b)): - # Success, we are done - break - - # Otherwise, apply correction - q = x(q) - i = i + 1 - - return q - -@guppy(mod) -def main() -> bool: - q = qubit() # todo initialise into an interesting state - return measure(rus(q,100)) - -if __name__ == "__main__": - print(mod.compile().serialize()) diff --git a/tests/guppy_test_cases/planqc-3.py.json b/tests/guppy_test_cases/planqc-3.py.json deleted file mode 100644 index 27f075a..0000000 --- a/tests/guppy_test_cases/planqc-3.py.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"live","nodes":[{"parent":0,"op":"Module"},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"other_outputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":92,"op":"DataflowBlock","inputs":[],"other_outputs":[{"t":"Sum","s":"Unit","size":2}],"sum_rows":[[]],"extension_delta":[]},{"parent":37,"op":"ExitBlock","cfg_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":92,"op":"ExitBlock","cfg_outputs":[{"t":"Sum","s":"Unit","size":2}]},{"parent":35,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":1,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]},{"parent":41,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":44,"op":"Input","types":[]},{"parent":46,"op":"Input","types":[]},{"parent":48,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":64,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":66,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":76,"op":"Input","types":[]},{"parent":78,"op":"Input","types":[]},{"parent":80,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":84,"op":"Input","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":86,"op":"Input","types":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":36,"op":"Input","types":[]},{"parent":2,"op":"Input","types":[]},{"parent":1,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":44,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]}]},{"parent":46,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]}]},{"parent":41,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":64,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":76,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":78,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}]},{"parent":66,"op":"Output","types":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":80,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":84,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":86,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":35,"op":"Output","types":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":2,"op":"Output","types":[{"t":"Sum","s":"Unit","size":1},{"t":"Sum","s":"Unit","size":2}]},{"parent":36,"op":"Output","types":[{"t":"Sum","s":"Unit","size":2}]},{"parent":0,"op":"FuncDefn","name":"rus","signature":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}}},{"parent":0,"op":"FuncDefn","name":"main","signature":{"params":[],"body":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}}},{"parent":35,"op":"CFG","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":1,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":0}}}},{"parent":1,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":1,"op":"Tag","tag":0,"variants":[[]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]],"extension_delta":[]},{"parent":41,"op":"CustomOp","extension":"arithmetic.int","name":"ilt_s","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":41,"op":"Conditional","other_inputs":[],"outputs":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":43,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]}],"extension_reqs":[]}},{"parent":44,"op":"Tag","tag":0,"variants":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]},{"parent":43,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]}],"extension_reqs":[]}},{"parent":46,"op":"Tag","tag":1,"variants":[[],[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"H","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"Tdg","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"CX","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"T","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":48,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":64,"op":"Tag","tag":0,"variants":[[]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]],"extension_delta":[]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"T","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"Z","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"CX","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"MakeTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":66,"op":"UnpackTuple","tys":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"T","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":66,"op":"Conditional","other_inputs":[],"outputs":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"sum_rows":[[],[]],"extension_delta":[]},{"parent":75,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":76,"op":"Tag","tag":0,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":75,"op":"Case","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"General","rows":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]}],"extension_reqs":[]}},{"parent":78,"op":"Tag","tag":1,"variants":[[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],[]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":80,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":80,"op":"MakeTuple","tys":[]},{"parent":80,"op":"Tag","tag":0,"variants":[[]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":84,"op":"Tag","tag":0,"variants":[[]]},{"parent":37,"op":"DataflowBlock","inputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"other_outputs":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"sum_rows":[[]],"extension_delta":[]},{"parent":86,"op":"CustomOp","extension":"quantum.tket2","name":"X","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":86,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":1}}}},{"parent":86,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":86,"op":"CustomOp","extension":"arithmetic.int","name":"iadd","signature":{"t":"G","input":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"extension_reqs":[]},"description":"","args":[{"tya":"BoundedNat","n":6}]},{"parent":86,"op":"Tag","tag":0,"variants":[[]]},{"parent":36,"op":"CFG","signature":{"t":"G","input":[],"output":[{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QAlloc","signature":{"t":"G","input":[],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Reset","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"Const","v":{"v":"Extension","extensions":["arithmetic.int.types"],"typ":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"},"value":{"c":"ConstInt","v":{"log_width":6,"value":100}}}},{"parent":2,"op":"LoadConstant","datatype":{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}},{"parent":2,"op":"Call","func_sig":{"params":[],"body":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},"type_args":[],"instantiation":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Opaque","extension":"arithmetic.int.types","id":"int","args":[{"tya":"BoundedNat","n":6}],"bound":"C"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"extension_reqs":[]}},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"Measure","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"},{"t":"Sum","s":"Unit","size":2}],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"CustomOp","extension":"quantum.tket2","name":"QFree","signature":{"t":"G","input":[{"t":"Opaque","extension":"prelude","id":"qubit","args":[],"bound":"A"}],"output":[],"extension_reqs":[]},"description":"","args":[]},{"parent":2,"op":"Tag","tag":0,"variants":[[]]}],"edges":[[[35,0],[97,2]],[[5,0],[37,0]],[[5,1],[37,1]],[[37,0],[32,0]],[[1,0],[41,null]],[[6,1],[20,2]],[[6,0],[20,3]],[[38,0],[39,0]],[[39,0],[20,1]],[[40,0],[20,0]],[[41,0],[64,null]],[[41,1],[48,null]],[[7,0],[42,0]],[[7,1],[42,1]],[[7,0],[47,0]],[[7,1],[47,1]],[[7,2],[23,1]],[[42,0],[43,0]],[[43,0],[23,0]],[[45,0],[21,0]],[[47,0],[22,0]],[[48,0],[80,null]],[[48,1],[66,null]],[[10,0],[24,1]],[[10,1],[24,2]],[[10,2],[24,4]],[[49,0],[50,0]],[[50,0],[51,0]],[[51,0],[55,0]],[[52,0],[53,0]],[[53,0],[54,0]],[[54,0],[55,1]],[[55,0],[56,0]],[[56,0],[57,0]],[[56,1],[58,0]],[[57,0],[58,1]],[[58,0],[59,0]],[[58,1],[59,1]],[[59,0],[60,0]],[[60,1],[61,0]],[[60,0],[24,3]],[[61,0],[62,0]],[[62,0],[63,0]],[[62,1],[24,0]],[[64,0],[3,null]],[[11,0],[25,1]],[[65,0],[25,0]],[[66,0],[86,null]],[[66,1],[84,null]],[[12,3],[67,0]],[[12,2],[69,1]],[[12,0],[77,0]],[[12,1],[77,1]],[[67,0],[68,0]],[[68,0],[69,0]],[[69,0],[70,0]],[[69,1],[70,1]],[[70,0],[71,0]],[[71,1],[72,0]],[[71,0],[28,1]],[[72,0],[73,0]],[[73,0],[74,0]],[[73,1],[75,0]],[[75,0],[28,0]],[[77,0],[26,0]],[[79,0],[27,0]],[[80,0],[41,null]],[[15,2],[81,0]],[[15,0],[29,1]],[[15,1],[29,2]],[[15,3],[29,3]],[[83,0],[29,0]],[[84,0],[64,null]],[[16,0],[30,1]],[[85,0],[30,0]],[[86,0],[41,null]],[[17,2],[87,0]],[[17,0],[90,0]],[[17,1],[31,2]],[[87,0],[31,3]],[[88,0],[89,0]],[[89,0],[90,1]],[[90,0],[31,1]],[[91,0],[31,0]],[[92,0],[34,0]],[[2,0],[4,null]],[[93,0],[94,0]],[[94,0],[97,0]],[[95,0],[96,0]],[[96,0],[97,1]],[[97,0],[98,0]],[[98,0],[99,0]],[[98,1],[33,1]],[[100,0],[33,0]],[[7,null],[43,null]],[[12,null],[75,null]]],"metadata":null,"encoder":"hugr-py v0.5.0"}