diff --git a/hugr-core/src/std_extensions/collections.rs b/hugr-core/src/std_extensions/collections.rs index 17a1b0d035..43ae97f681 100644 --- a/hugr-core/src/std_extensions/collections.rs +++ b/hugr-core/src/std_extensions/collections.rs @@ -59,6 +59,11 @@ impl ListValue { pub fn custom_type(&self) -> CustomType { list_custom_type(self.1.clone()) } + + /// Returns the values contained inside the `[ListValue]`. + pub fn get_contents(&self) -> &Vec { + &self.0 + } } impl TryHash for ListValue { diff --git a/hugr-llvm/src/emit/test.rs b/hugr-llvm/src/emit/test.rs index 647636c959..632224946e 100644 --- a/hugr-llvm/src/emit/test.rs +++ b/hugr-llvm/src/emit/test.rs @@ -10,7 +10,7 @@ use hugr_core::ops::handle::FuncID; use hugr_core::std_extensions::arithmetic::{ conversions, float_ops, float_types, int_ops, int_types, }; -use hugr_core::std_extensions::logic; +use hugr_core::std_extensions::{collections, logic}; use hugr_core::types::TypeRow; use hugr_core::{Hugr, HugrView}; use inkwell::module::Module; @@ -153,6 +153,7 @@ impl SimpleHugrConfig { float_ops::EXTENSION_ID, conversions::EXTENSION_ID, logic::EXTENSION_ID, + collections::EXTENSION_ID, ]), ), ) diff --git a/hugr-llvm/src/extension.rs b/hugr-llvm/src/extension.rs index fe6db7ed5f..4757926b33 100644 --- a/hugr-llvm/src/extension.rs +++ b/hugr-llvm/src/extension.rs @@ -1,3 +1,4 @@ +pub mod collections; pub mod conversions; pub mod float; pub mod int; diff --git a/hugr-llvm/src/extension/collections.rs b/hugr-llvm/src/extension/collections.rs new file mode 100644 index 0000000000..ca453585c0 --- /dev/null +++ b/hugr-llvm/src/extension/collections.rs @@ -0,0 +1,596 @@ +use anyhow::{anyhow, Ok, Result}; +use hugr_core::core::Either; +use hugr_core::core::Either::{Left, Right}; +use hugr_core::{ + extension::prelude::{either_type, option_type}, + ops::{constant::CustomConst, ExtensionOp, NamedOp}, + std_extensions::collections::{self, ListOp, ListValue}, + types::{SumType, Type, TypeArg}, + HugrView, +}; +use inkwell::{ + types::{BasicType, BasicTypeEnum, FunctionType}, + values::{BasicValueEnum, IntValue, PointerValue}, + AddressSpace, +}; +use itertools::Itertools; + +use crate::{ + custom::{CodegenExtension, CodegenExtsBuilder}, + emit::{emit_value, func::EmitFuncContext, EmitOpArgs}, + types::{HugrType, TypingSession}, +}; + +/// A helper trait for customising the lowering [hugr_core::std_extensions::collections] +/// types, [CustomConst]s, and ops. +/// +/// All methods have defaults provided that call out to runtime functions, and +/// [DefaultCollectionsCodegen] is a trivial implementation of this trait which +/// delegates everything to those default implementations. +pub trait CollectionsCodegen: Clone { + /// Return the llvm type of [hugr_core::std_extensions::collections::LIST_TYPENAME]. + fn list_type<'c>(&self, session: &TypingSession<'c, '_>) -> BasicTypeEnum<'c> { + session + .iw_context() + .i8_type() + .ptr_type(AddressSpace::default()) + .into() + } + + /// Helper function to compute the signature of runtime functions. + fn rt_func_sig<'c>( + &self, + ts: TypingSession<'c, '_>, + fallible: bool, + indexed: bool, + inout: bool, + ) -> FunctionType<'c> { + let iwc = ts.iw_context(); + let mut args = vec![self.list_type(&ts).into()]; + if indexed { + args.push(iwc.i64_type().into()); + } + if inout { + args.push(iwc.i8_type().ptr_type(AddressSpace::default()).into()); + } + if fallible { + iwc.bool_type().fn_type(&args, false) + } else { + iwc.void_type().fn_type(&args, false) + } + } + + /// Emits a call to the runtime function that allocates a new list. + fn rt_list_new<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + capacity: IntValue<'c>, + elem_size: IntValue<'c>, + alignment: IntValue<'c>, + destructor: PointerValue<'c>, + ) -> Result> { + let session = ctx.typing_session(); + let iwc = session.iw_context(); + let func_ty = self.list_type(&session).fn_type( + &[ + iwc.i64_type().into(), // Capacity + iwc.i64_type().into(), // Single element size in bytes + iwc.i64_type().into(), // Element alignment + // Pointer to element destructor + iwc.i8_type().ptr_type(AddressSpace::default()).into(), + ], + false, + ); + let func = ctx.get_extern_func("__rt__list__new", func_ty)?; + let list = ctx + .builder() + .build_call( + func, + &[ + capacity.into(), + elem_size.into(), + alignment.into(), + destructor.into(), + ], + "", + )? + .try_as_basic_value() + .unwrap_left(); + Ok(list) + } + + /// Emits a call to the runtime function that pushes to a list. + fn rt_list_push<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + elem_ptr: PointerValue<'c>, + ) -> Result<()> { + let sig = self.rt_func_sig(ctx.typing_session(), false, false, true); + let func = ctx.get_extern_func("__rt__list__push", sig)?; + ctx.builder() + .build_call(func, &[list.into(), elem_ptr.into()], "")?; + Ok(()) + } + + /// Emits a call to the runtime function that pops from a list. + fn rt_list_pop<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + out_ptr: PointerValue<'c>, + ) -> Result> { + let sig = self.rt_func_sig(ctx.typing_session(), true, false, true); + let func = ctx.get_extern_func("__rt__list__pop", sig)?; + let res = ctx + .builder() + .build_call(func, &[list.into(), out_ptr.into()], "")? + .try_as_basic_value() + .unwrap_left() + .into_int_value(); + Ok(res) + } + + /// Emits a call to the runtime function that retrives an element from a list. + fn rt_list_get<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + idx: IntValue<'c>, + out_ptr: PointerValue<'c>, + ) -> Result> { + let sig = self.rt_func_sig(ctx.typing_session(), true, true, true); + let func = ctx.get_extern_func("__rt__list__get", sig)?; + let res = ctx + .builder() + .build_call(func, &[list.into(), idx.into(), out_ptr.into()], "")? + .try_as_basic_value() + .unwrap_left() + .into_int_value(); + Ok(res) + } + + /// Emits a call to the runtime function that updates an element in a list. + fn rt_list_set<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + idx: IntValue<'c>, + elem_ptr: PointerValue<'c>, + ) -> Result> { + let sig = self.rt_func_sig(ctx.typing_session(), true, true, true); + let func = ctx.get_extern_func("__rt__list__set", sig)?; + let res = ctx + .builder() + .build_call(func, &[list.into(), idx.into(), elem_ptr.into()], "")? + .try_as_basic_value() + .unwrap_left() + .into_int_value(); + Ok(res) + } + + /// Emits a call to the runtime function that inserts an element into a list. + fn rt_list_insert<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + idx: IntValue<'c>, + elem_ptr: PointerValue<'c>, + ) -> Result> { + let sig = self.rt_func_sig(ctx.typing_session(), true, true, true); + let func = ctx.get_extern_func("__rt__list__insert", sig)?; + let res = ctx + .builder() + .build_call(func, &[list.into(), idx.into(), elem_ptr.into()], "")? + .try_as_basic_value() + .unwrap_left() + .into_int_value(); + Ok(res) + } + + /// Emits a call to the runtime function that computes the length of a list. + fn rt_list_length<'c, H: HugrView>( + &self, + ctx: &EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + ) -> Result> { + let session = ctx.typing_session(); + let func_ty = session + .iw_context() + .i64_type() + .fn_type(&[self.list_type(&session).into()], false); + let func = ctx.get_extern_func("__rt__list__length", func_ty)?; + let res = ctx + .builder() + .build_call(func, &[list.into()], "")? + .try_as_basic_value() + .unwrap_left() + .into_int_value(); + Ok(res) + } + + /// Emit instructions to materialise an LLVM value representing + /// a [ListValue]. + fn emit_const_list<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + elems: Vec>, + elem_ty: BasicTypeEnum<'c>, + ) -> Result> { + let iwc = ctx.typing_session().iw_context(); + let capacity = iwc.i64_type().const_int(elems.len() as u64, false); + let elem_size = elem_ty.size_of().unwrap(); + let alignment = iwc.i64_type().const_int(8, false); + // TODO: Lookup destructor for elem_ty + let destructor = iwc.i8_type().ptr_type(AddressSpace::default()).const_null(); + let list = self.rt_list_new(ctx, capacity, elem_size, alignment, destructor)?; + for elem in elems { + self.emit_push(ctx, list, elem)?; + } + Ok(list) + } + + /// Emit a [ListOp::push] node. + fn emit_push<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + elem: BasicValueEnum<'c>, + ) -> Result<()> { + let elem_ptr = build_alloca_i8_ptr(ctx, Right(elem))?; + self.rt_list_push(ctx, list, elem_ptr) + } + + /// Emit a [ListOp::pop] node. + fn emit_pop<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + hugr_elem_ty: HugrType, + ) -> Result> { + let elem_ty = ctx.llvm_type(&hugr_elem_ty)?; + let out_ptr = build_alloca_i8_ptr(ctx, Left(elem_ty))?; + let pop_ok = self.rt_list_pop(ctx, list, out_ptr)?; + let elem = build_load_i8_ptr(ctx, out_ptr, elem_ty)?; + build_option(ctx, pop_ok, elem, hugr_elem_ty) + } + + /// Emit a [ListOp::get] node. + fn emit_get<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + index: IntValue<'c>, + hugr_elem_ty: HugrType, + ) -> Result> { + let elem_ty = ctx.llvm_type(&hugr_elem_ty)?; + let out_ptr = build_alloca_i8_ptr(ctx, Left(elem_ty))?; + let get_ok = self.rt_list_get(ctx, list, index, out_ptr)?; + let elem = build_load_i8_ptr(ctx, out_ptr, elem_ty)?; + build_option(ctx, get_ok, elem, hugr_elem_ty) + } + + /// Emit a [ListOp::set] node. + fn emit_set<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + index: IntValue<'c>, + elem: BasicValueEnum<'c>, + hugr_elem_ty: HugrType, + ) -> Result> { + let elem_ptr = build_alloca_i8_ptr(ctx, Right(elem))?; + let set_ok = self.rt_list_set(ctx, list, index, elem_ptr)?; + let old_elem = build_load_i8_ptr(ctx, elem_ptr, elem.get_type())?; + build_ok_or_else( + ctx, + set_ok, + elem, + hugr_elem_ty.clone(), + old_elem, + hugr_elem_ty, + ) + } + + /// Emit a [ListOp::insert] node. + fn emit_insert<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + index: IntValue<'c>, + elem: BasicValueEnum<'c>, + hugr_elem_ty: HugrType, + ) -> Result> { + let elem_ptr = build_alloca_i8_ptr(ctx, Right(elem))?; + let insert_ok = self.rt_list_insert(ctx, list, index, elem_ptr)?; + let unit = ctx + .llvm_sum_type(SumType::new_unary(1))? + .build_tag(ctx.builder(), 0, vec![])?; + build_ok_or_else(ctx, insert_ok, unit, Type::UNIT, elem, hugr_elem_ty) + } + + /// Emit a [ListOp::length] node. + fn emit_length<'c, H: HugrView>( + &self, + ctx: &mut EmitFuncContext<'c, '_, H>, + list: BasicValueEnum<'c>, + ) -> Result> { + Ok(self.rt_list_length(ctx, list)?) + } +} + +fn build_option<'c, H: HugrView>( + ctx: &mut EmitFuncContext<'c, '_, H>, + is_some: IntValue<'c>, + some_value: BasicValueEnum<'c>, + hugr_ty: HugrType, +) -> Result> { + let option_ty = ctx.llvm_sum_type(option_type(hugr_ty))?; + let builder = ctx.builder(); + let some = option_ty.build_tag(builder, 1, vec![some_value])?; + let none = option_ty.build_tag(builder, 0, vec![])?; + let option = builder.build_select(is_some, some, none, "")?; + Ok(option) +} + +fn build_ok_or_else<'c, H: HugrView>( + ctx: &mut EmitFuncContext<'c, '_, H>, + is_ok: IntValue<'c>, + ok_value: BasicValueEnum<'c>, + ok_hugr_ty: HugrType, + else_value: BasicValueEnum<'c>, + else_hugr_ty: HugrType, +) -> Result> { + let either_ty = ctx.llvm_sum_type(either_type(else_hugr_ty, ok_hugr_ty))?; + let builder = ctx.builder(); + let left = either_ty.build_tag(builder, 0, vec![else_value])?; + let right = either_ty.build_tag(builder, 1, vec![ok_value])?; + let either = builder.build_select(is_ok, right, left, "")?; + Ok(either) +} + +/// Helper function to allocate space on the stack for a given type. +/// +/// Returns an i8 pointer to the allocated memory. +fn build_alloca_i8_ptr<'c, H: HugrView>( + ctx: &mut EmitFuncContext<'c, '_, H>, + ty_or_val: Either, BasicValueEnum<'c>>, +) -> Result> { + let builder = ctx.builder(); + let ty = match ty_or_val { + Left(ty) => ty, + Right(val) => val.get_type(), + }; + let ptr = builder.build_alloca(ty, "")?; + + if let Right(val) = ty_or_val { + builder.build_store(ptr, val)?; + } + let i8_ptr = builder.build_pointer_cast( + ptr, + ctx.iw_context().i8_type().ptr_type(AddressSpace::default()), + "", + )?; + Ok(i8_ptr) +} + +/// Helper function to load a value from an i8 pointer. +fn build_load_i8_ptr<'c, H: HugrView>( + ctx: &mut EmitFuncContext<'c, '_, H>, + i8_ptr: PointerValue<'c>, + ty: BasicTypeEnum<'c>, +) -> Result> { + let builder = ctx.builder(); + let ptr = builder.build_pointer_cast(i8_ptr, ty.ptr_type(AddressSpace::default()), "")?; + let val = builder.build_load(ptr, "")?; + Ok(val) +} + +/// A trivial implementation of [CollectionsCodegen] which passes all methods +/// through to their default implementations. +#[derive(Default, Clone)] +pub struct DefaultCollectionsCodegen; + +impl CollectionsCodegen for DefaultCollectionsCodegen {} + +#[derive(Clone, Debug, Default)] +pub struct CollectionsCodegenExtension(CCG); + +impl CollectionsCodegenExtension { + pub fn new(ccg: CCG) -> Self { + Self(ccg) + } +} + +impl From for CollectionsCodegenExtension { + fn from(ccg: CCG) -> Self { + Self::new(ccg) + } +} + +impl CodegenExtension for CollectionsCodegenExtension { + fn add_extension<'a, H: HugrView + 'a>( + self, + builder: CodegenExtsBuilder<'a, H>, + ) -> CodegenExtsBuilder<'a, H> + where + Self: 'a, + { + add_collections_extensions(builder, self.0) + } +} + +impl<'a, H: HugrView + 'a> CodegenExtsBuilder<'a, H> { + /// Add a [CollectionsCodegenExtension] to the given [CodegenExtsBuilder] using `ccg` + /// as the implementation. + pub fn add_default_collections_extensions(self) -> Self { + self.add_collections_extensions(DefaultCollectionsCodegen) + } + + /// Add a [CollectionsCodegenExtension] to the given [CodegenExtsBuilder] using + /// [DefaultCollectionsCodegen] as the implementation. + pub fn add_collections_extensions(self, ccg: impl CollectionsCodegen + 'a) -> Self { + self.add_extension(CollectionsCodegenExtension::from(ccg)) + } +} + +fn emit_list_op<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, '_, H>, + ccg: &(impl CollectionsCodegen + 'c), + args: EmitOpArgs<'c, '_, ExtensionOp, H>, + op: ListOp, +) -> Result<()> { + let hugr_elem_ty = match args.node().args() { + [TypeArg::Type { ty }] => ty.clone(), + _ => { + return Err(anyhow!("Collections: invalid type args for list op")); + } + }; + match op { + ListOp::push => { + let [list, elem] = args.inputs.try_into().unwrap(); + ccg.emit_push(context, list, elem)?; + args.outputs.finish(context.builder(), vec![list])?; + } + ListOp::pop => { + let [list] = args.inputs.try_into().unwrap(); + let elem_opt = ccg.emit_pop(context, list, hugr_elem_ty)?; + args.outputs + .finish(context.builder(), vec![list, elem_opt])?; + } + ListOp::get => { + let [list, idx] = args.inputs.try_into().unwrap(); + let elem_opt = ccg.emit_get(context, list, idx.into_int_value(), hugr_elem_ty)?; + args.outputs.finish(context.builder(), vec![elem_opt])?; + } + ListOp::set => { + let [list, idx, elem] = args.inputs.try_into().unwrap(); + let ok = ccg.emit_set(context, list, idx.into_int_value(), elem, hugr_elem_ty)?; + args.outputs.finish(context.builder(), vec![list, ok])?; + } + ListOp::insert => { + let [list, idx, elem] = args.inputs.try_into().unwrap(); + let ok = ccg.emit_insert(context, list, idx.into_int_value(), elem, hugr_elem_ty)?; + args.outputs.finish(context.builder(), vec![list, ok])?; + } + ListOp::length => { + let [list] = args.inputs.try_into().unwrap(); + let length = ccg.emit_length(context, list)?; + args.outputs + .finish(context.builder(), vec![list, length.into()])?; + } + _ => return Err(anyhow!("Collections: unimplemented op: {}", op.name())), + } + Ok(()) +} + +/// Add a [CollectionsCodegenExtension] to the given [CodegenExtsBuilder] using `ccg` +/// as the implementation. +pub fn add_collections_extensions<'a, H: HugrView + 'a>( + cem: CodegenExtsBuilder<'a, H>, + ccg: impl CollectionsCodegen + 'a, +) -> CodegenExtsBuilder<'a, H> { + cem.custom_type((collections::EXTENSION_ID, collections::LIST_TYPENAME), { + let ccg = ccg.clone(); + move |ts, _hugr_type| Ok(ccg.list_type(&ts).as_basic_type_enum()) + }) + .custom_const::({ + let ccg = ccg.clone(); + move |ctx, k| { + let ty = ctx.llvm_type(&k.get_type())?; + let elems = k + .get_contents() + .iter() + .map(|v| emit_value(ctx, v)) + .try_collect()?; + ccg.emit_const_list(ctx, elems, ty) + } + }) + .simple_extension_op::(move |ctx, args, op| emit_list_op(ctx, &ccg, args, op)) +} + +#[cfg(test)] +mod test { + use hugr_core::{ + builder::{Dataflow, DataflowSubContainer}, + extension::{ + prelude::{self, ConstUsize, QB_T, USIZE_T}, + ExtensionRegistry, + }, + ops::{DataflowOpTrait, NamedOp, Value}, + std_extensions::collections::{self, list_type, ListOp, ListValue}, + Hugr, + }; + use rstest::rstest; + + use crate::{ + check_emission, + custom::CodegenExtsBuilder, + emit::test::SimpleHugrConfig, + test::{llvm_ctx, TestContext}, + }; + + fn test_collections_op(op: ListOp) -> Hugr { + let ext_op = collections::EXTENSION + .instantiate_extension_op( + op.name().as_ref(), + [QB_T.into()], + &collections::COLLECTIONS_REGISTRY, + ) + .unwrap(); + let es = ExtensionRegistry::try_new([ + collections::EXTENSION.to_owned(), + prelude::PRELUDE.to_owned(), + ]) + .unwrap(); + SimpleHugrConfig::new() + .with_ins(ext_op.signature().input().clone()) + .with_outs(ext_op.signature().output().clone()) + .with_extensions(es) + .finish(|mut hugr_builder| { + let outputs = hugr_builder + .add_dataflow_op(ext_op, hugr_builder.input_wires()) + .unwrap() + .outputs(); + hugr_builder.finish_with_outputs(outputs).unwrap() + }) + } + + #[rstest] + #[case::push(ListOp::push)] + #[case::pop(ListOp::pop)] + #[case::get(ListOp::get)] + #[case::set(ListOp::set)] + #[case::insert(ListOp::insert)] + #[case::length(ListOp::length)] + fn test_collections_emission(mut llvm_ctx: TestContext, #[case] op: ListOp) { + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_collections_extensions); + let hugr = test_collections_op(op); + check_emission!(op.name().as_str(), hugr, llvm_ctx); + } + + #[rstest] + fn test_const_list_emmission(mut llvm_ctx: TestContext) { + let elem_ty = USIZE_T; + let contents = (1..4).map(|i| Value::extension(ConstUsize::new(i))); + let es = ExtensionRegistry::try_new([ + collections::EXTENSION.to_owned(), + prelude::PRELUDE.to_owned(), + ]) + .unwrap(); + + let hugr = SimpleHugrConfig::new() + .with_ins(vec![]) + .with_outs(vec![list_type(elem_ty.clone())]) + .with_extensions(es) + .finish(|mut hugr_builder| { + let list = hugr_builder.add_load_value(ListValue::new(elem_ty, contents)); + hugr_builder.finish_with_outputs(vec![list]).unwrap() + }); + + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_collections_extensions); + check_emission!("const", hugr, llvm_ctx); + } +} diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@llvm14.snap new file mode 100644 index 0000000000..8102b8690f --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@llvm14.snap @@ -0,0 +1,32 @@ +--- +source: hugr-llvm/src/extension/collections.rs +assertion_line: 592 +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define i8* @_hl.main.1() { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %0 = call i8* @__rt__list__new(i64 3, i64 ptrtoint (i8** getelementptr (i8*, i8** null, i32 1) to i64), i64 8, i8* null) + %1 = alloca i64, align 8 + store i64 1, i64* %1, align 4 + %2 = bitcast i64* %1 to i8* + call void @__rt__list__push(i8* %0, i8* %2) + %3 = alloca i64, align 8 + store i64 2, i64* %3, align 4 + %4 = bitcast i64* %3 to i8* + call void @__rt__list__push(i8* %0, i8* %4) + %5 = alloca i64, align 8 + store i64 3, i64* %5, align 4 + %6 = bitcast i64* %5 to i8* + call void @__rt__list__push(i8* %0, i8* %6) + ret i8* %0 +} + +declare i8* @__rt__list__new(i64, i64, i64, i8*) + +declare void @__rt__list__push(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..d3a6c8b10e --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__const@pre-mem2reg@llvm14.snap @@ -0,0 +1,37 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define i8* @_hl.main.1() { +alloca_block: + %"0" = alloca i8*, align 8 + %"5_0" = alloca i8*, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + %0 = call i8* @__rt__list__new(i64 3, i64 ptrtoint (i8** getelementptr (i8*, i8** null, i32 1) to i64), i64 8, i8* null) + %1 = alloca i64, align 8 + store i64 1, i64* %1, align 4 + %2 = bitcast i64* %1 to i8* + call void @__rt__list__push(i8* %0, i8* %2) + %3 = alloca i64, align 8 + store i64 2, i64* %3, align 4 + %4 = bitcast i64* %3 to i8* + call void @__rt__list__push(i8* %0, i8* %4) + %5 = alloca i64, align 8 + store i64 3, i64* %5, align 4 + %6 = bitcast i64* %5 to i8* + call void @__rt__list__push(i8* %0, i8* %6) + store i8* %0, i8** %"5_0", align 8 + %"5_01" = load i8*, i8** %"5_0", align 8 + store i8* %"5_01", i8** %"0", align 8 + %"02" = load i8*, i8** %"0", align 8 + ret i8* %"02" +} + +declare i8* @__rt__list__new(i64, i64, i64, i8*) + +declare void @__rt__list__push(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@llvm14.snap new file mode 100644 index 0000000000..5d7d0d3815 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@llvm14.snap @@ -0,0 +1,24 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i32, {}, { i16 } } @_hl.main.1(i8* %0, i64 %1) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %2 = alloca i16, align 2 + %3 = bitcast i16* %2 to i8* + %4 = call i1 @__rt__list__get(i8* %0, i64 %1, i8* %3) + %5 = bitcast i8* %3 to i16* + %6 = load i16, i16* %5, align 2 + %7 = insertvalue { i16 } undef, i16 %6, 0 + %8 = insertvalue { i32, {}, { i16 } } { i32 1, {} poison, { i16 } poison }, { i16 } %7, 2 + %9 = select i1 %4, { i32, {}, { i16 } } %8, { i32, {}, { i16 } } { i32 0, {} undef, { i16 } poison } + ret { i32, {}, { i16 } } %9 +} + +declare i1 @__rt__list__get(i8*, i64, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..a7eee4d033 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__get@pre-mem2reg@llvm14.snap @@ -0,0 +1,36 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i32, {}, { i16 } } @_hl.main.1(i8* %0, i64 %1) { +alloca_block: + %"0" = alloca { i32, {}, { i16 } }, align 8 + %"2_0" = alloca i8*, align 8 + %"2_1" = alloca i64, align 8 + %"4_0" = alloca { i32, {}, { i16 } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + store i64 %1, i64* %"2_1", align 4 + %"2_01" = load i8*, i8** %"2_0", align 8 + %"2_12" = load i64, i64* %"2_1", align 4 + %2 = alloca i16, align 2 + %3 = bitcast i16* %2 to i8* + %4 = call i1 @__rt__list__get(i8* %"2_01", i64 %"2_12", i8* %3) + %5 = bitcast i8* %3 to i16* + %6 = load i16, i16* %5, align 2 + %7 = insertvalue { i16 } undef, i16 %6, 0 + %8 = insertvalue { i32, {}, { i16 } } { i32 1, {} poison, { i16 } poison }, { i16 } %7, 2 + %9 = select i1 %4, { i32, {}, { i16 } } %8, { i32, {}, { i16 } } { i32 0, {} undef, { i16 } poison } + store { i32, {}, { i16 } } %9, { i32, {}, { i16 } }* %"4_0", align 4 + %"4_03" = load { i32, {}, { i16 } }, { i32, {}, { i16 } }* %"4_0", align 4 + store { i32, {}, { i16 } } %"4_03", { i32, {}, { i16 } }* %"0", align 4 + %"04" = load { i32, {}, { i16 } }, { i32, {}, { i16 } }* %"0", align 4 + ret { i32, {}, { i16 } } %"04" +} + +declare i1 @__rt__list__get(i8*, i64, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@llvm14.snap new file mode 100644 index 0000000000..deb84f1b54 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@llvm14.snap @@ -0,0 +1,25 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, { i16 }, { { {} } } } } @_hl.main.1(i8* %0, i64 %1, i16 %2) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %3 = alloca i16, align 2 + store i16 %2, i16* %3, align 2 + %4 = bitcast i16* %3 to i8* + %5 = call i1 @__rt__list__insert(i8* %0, i64 %1, i8* %4) + %6 = insertvalue { i16 } undef, i16 %2, 0 + %7 = insertvalue { i32, { i16 }, { { {} } } } { i32 0, { i16 } poison, { { {} } } poison }, { i16 } %6, 1 + %8 = select i1 %5, { i32, { i16 }, { { {} } } } { i32 1, { i16 } poison, { { {} } } undef }, { i32, { i16 }, { { {} } } } %7 + %mrv = insertvalue { i8*, { i32, { i16 }, { { {} } } } } undef, i8* %0, 0 + %mrv8 = insertvalue { i8*, { i32, { i16 }, { { {} } } } } %mrv, { i32, { i16 }, { { {} } } } %8, 1 + ret { i8*, { i32, { i16 }, { { {} } } } } %mrv8 +} + +declare i1 @__rt__list__insert(i8*, i64, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..9f92cf9a6e --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__insert@pre-mem2reg@llvm14.snap @@ -0,0 +1,46 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, { i16 }, { { {} } } } } @_hl.main.1(i8* %0, i64 %1, i16 %2) { +alloca_block: + %"0" = alloca i8*, align 8 + %"1" = alloca { i32, { i16 }, { { {} } } }, align 8 + %"2_0" = alloca i8*, align 8 + %"2_1" = alloca i64, align 8 + %"2_2" = alloca i16, align 2 + %"4_0" = alloca i8*, align 8 + %"4_1" = alloca { i32, { i16 }, { { {} } } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + store i64 %1, i64* %"2_1", align 4 + store i16 %2, i16* %"2_2", align 2 + %"2_01" = load i8*, i8** %"2_0", align 8 + %"2_12" = load i64, i64* %"2_1", align 4 + %"2_23" = load i16, i16* %"2_2", align 2 + %3 = alloca i16, align 2 + store i16 %"2_23", i16* %3, align 2 + %4 = bitcast i16* %3 to i8* + %5 = call i1 @__rt__list__insert(i8* %"2_01", i64 %"2_12", i8* %4) + %6 = insertvalue { i16 } undef, i16 %"2_23", 0 + %7 = insertvalue { i32, { i16 }, { { {} } } } { i32 0, { i16 } poison, { { {} } } poison }, { i16 } %6, 1 + %8 = select i1 %5, { i32, { i16 }, { { {} } } } { i32 1, { i16 } poison, { { {} } } undef }, { i32, { i16 }, { { {} } } } %7 + store i8* %"2_01", i8** %"4_0", align 8 + store { i32, { i16 }, { { {} } } } %8, { i32, { i16 }, { { {} } } }* %"4_1", align 4 + %"4_04" = load i8*, i8** %"4_0", align 8 + %"4_15" = load { i32, { i16 }, { { {} } } }, { i32, { i16 }, { { {} } } }* %"4_1", align 4 + store i8* %"4_04", i8** %"0", align 8 + store { i32, { i16 }, { { {} } } } %"4_15", { i32, { i16 }, { { {} } } }* %"1", align 4 + %"06" = load i8*, i8** %"0", align 8 + %"17" = load { i32, { i16 }, { { {} } } }, { i32, { i16 }, { { {} } } }* %"1", align 4 + %mrv = insertvalue { i8*, { i32, { i16 }, { { {} } } } } undef, i8* %"06", 0 + %mrv8 = insertvalue { i8*, { i32, { i16 }, { { {} } } } } %mrv, { i32, { i16 }, { { {} } } } %"17", 1 + ret { i8*, { i32, { i16 }, { { {} } } } } %mrv8 +} + +declare i1 @__rt__list__insert(i8*, i64, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@llvm14.snap new file mode 100644 index 0000000000..61ddae3a37 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@llvm14.snap @@ -0,0 +1,19 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, i64 } @_hl.main.1(i8* %0) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %1 = call i64 @__rt__list__length(i8* %0) + %mrv = insertvalue { i8*, i64 } undef, i8* %0, 0 + %mrv6 = insertvalue { i8*, i64 } %mrv, i64 %1, 1 + ret { i8*, i64 } %mrv6 +} + +declare i64 @__rt__list__length(i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..e993956bbf --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__length@pre-mem2reg@llvm14.snap @@ -0,0 +1,34 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, i64 } @_hl.main.1(i8* %0) { +alloca_block: + %"0" = alloca i8*, align 8 + %"1" = alloca i64, align 8 + %"2_0" = alloca i8*, align 8 + %"4_0" = alloca i8*, align 8 + %"4_1" = alloca i64, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + %"2_01" = load i8*, i8** %"2_0", align 8 + %1 = call i64 @__rt__list__length(i8* %"2_01") + store i8* %"2_01", i8** %"4_0", align 8 + store i64 %1, i64* %"4_1", align 4 + %"4_02" = load i8*, i8** %"4_0", align 8 + %"4_13" = load i64, i64* %"4_1", align 4 + store i8* %"4_02", i8** %"0", align 8 + store i64 %"4_13", i64* %"1", align 4 + %"04" = load i8*, i8** %"0", align 8 + %"15" = load i64, i64* %"1", align 4 + %mrv = insertvalue { i8*, i64 } undef, i8* %"04", 0 + %mrv6 = insertvalue { i8*, i64 } %mrv, i64 %"15", 1 + ret { i8*, i64 } %mrv6 +} + +declare i64 @__rt__list__length(i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@llvm14.snap new file mode 100644 index 0000000000..e011b3dfee --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@llvm14.snap @@ -0,0 +1,26 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, {}, { i16 } } } @_hl.main.1(i8* %0) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %1 = alloca i16, align 2 + %2 = bitcast i16* %1 to i8* + %3 = call i1 @__rt__list__pop(i8* %0, i8* %2) + %4 = bitcast i8* %2 to i16* + %5 = load i16, i16* %4, align 2 + %6 = insertvalue { i16 } undef, i16 %5, 0 + %7 = insertvalue { i32, {}, { i16 } } { i32 1, {} poison, { i16 } poison }, { i16 } %6, 2 + %8 = select i1 %3, { i32, {}, { i16 } } %7, { i32, {}, { i16 } } { i32 0, {} undef, { i16 } poison } + %mrv = insertvalue { i8*, { i32, {}, { i16 } } } undef, i8* %0, 0 + %mrv6 = insertvalue { i8*, { i32, {}, { i16 } } } %mrv, { i32, {}, { i16 } } %8, 1 + ret { i8*, { i32, {}, { i16 } } } %mrv6 +} + +declare i1 @__rt__list__pop(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..4b677b1a85 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__pop@pre-mem2reg@llvm14.snap @@ -0,0 +1,41 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, {}, { i16 } } } @_hl.main.1(i8* %0) { +alloca_block: + %"0" = alloca i8*, align 8 + %"1" = alloca { i32, {}, { i16 } }, align 8 + %"2_0" = alloca i8*, align 8 + %"4_0" = alloca i8*, align 8 + %"4_1" = alloca { i32, {}, { i16 } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + %"2_01" = load i8*, i8** %"2_0", align 8 + %1 = alloca i16, align 2 + %2 = bitcast i16* %1 to i8* + %3 = call i1 @__rt__list__pop(i8* %"2_01", i8* %2) + %4 = bitcast i8* %2 to i16* + %5 = load i16, i16* %4, align 2 + %6 = insertvalue { i16 } undef, i16 %5, 0 + %7 = insertvalue { i32, {}, { i16 } } { i32 1, {} poison, { i16 } poison }, { i16 } %6, 2 + %8 = select i1 %3, { i32, {}, { i16 } } %7, { i32, {}, { i16 } } { i32 0, {} undef, { i16 } poison } + store i8* %"2_01", i8** %"4_0", align 8 + store { i32, {}, { i16 } } %8, { i32, {}, { i16 } }* %"4_1", align 4 + %"4_02" = load i8*, i8** %"4_0", align 8 + %"4_13" = load { i32, {}, { i16 } }, { i32, {}, { i16 } }* %"4_1", align 4 + store i8* %"4_02", i8** %"0", align 8 + store { i32, {}, { i16 } } %"4_13", { i32, {}, { i16 } }* %"1", align 4 + %"04" = load i8*, i8** %"0", align 8 + %"15" = load { i32, {}, { i16 } }, { i32, {}, { i16 } }* %"1", align 4 + %mrv = insertvalue { i8*, { i32, {}, { i16 } } } undef, i8* %"04", 0 + %mrv6 = insertvalue { i8*, { i32, {}, { i16 } } } %mrv, { i32, {}, { i16 } } %"15", 1 + ret { i8*, { i32, {}, { i16 } } } %mrv6 +} + +declare i1 @__rt__list__pop(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@llvm14.snap new file mode 100644 index 0000000000..6e9be48bc6 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@llvm14.snap @@ -0,0 +1,20 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define i8* @_hl.main.1(i8* %0, i16 %1) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %2 = alloca i16, align 2 + store i16 %1, i16* %2, align 2 + %3 = bitcast i16* %2 to i8* + call void @__rt__list__push(i8* %0, i8* %3) + ret i8* %0 +} + +declare void @__rt__list__push(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..5e88ddf5a4 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__push@pre-mem2reg@llvm14.snap @@ -0,0 +1,32 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define i8* @_hl.main.1(i8* %0, i16 %1) { +alloca_block: + %"0" = alloca i8*, align 8 + %"2_0" = alloca i8*, align 8 + %"2_1" = alloca i16, align 2 + %"4_0" = alloca i8*, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + store i16 %1, i16* %"2_1", align 2 + %"2_01" = load i8*, i8** %"2_0", align 8 + %"2_12" = load i16, i16* %"2_1", align 2 + %2 = alloca i16, align 2 + store i16 %"2_12", i16* %2, align 2 + %3 = bitcast i16* %2 to i8* + call void @__rt__list__push(i8* %"2_01", i8* %3) + store i8* %"2_01", i8** %"4_0", align 8 + %"4_03" = load i8*, i8** %"4_0", align 8 + store i8* %"4_03", i8** %"0", align 8 + %"04" = load i8*, i8** %"0", align 8 + ret i8* %"04" +} + +declare void @__rt__list__push(i8*, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@llvm14.snap new file mode 100644 index 0000000000..f2b0ac21a3 --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@llvm14.snap @@ -0,0 +1,29 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, { i16 }, { i16 } } } @_hl.main.1(i8* %0, i64 %1, i16 %2) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + %3 = alloca i16, align 2 + store i16 %2, i16* %3, align 2 + %4 = bitcast i16* %3 to i8* + %5 = call i1 @__rt__list__set(i8* %0, i64 %1, i8* %4) + %6 = bitcast i8* %4 to i16* + %7 = load i16, i16* %6, align 2 + %8 = insertvalue { i16 } undef, i16 %7, 0 + %9 = insertvalue { i32, { i16 }, { i16 } } { i32 0, { i16 } poison, { i16 } poison }, { i16 } %8, 1 + %10 = insertvalue { i16 } undef, i16 %2, 0 + %11 = insertvalue { i32, { i16 }, { i16 } } { i32 1, { i16 } poison, { i16 } poison }, { i16 } %10, 2 + %12 = select i1 %5, { i32, { i16 }, { i16 } } %11, { i32, { i16 }, { i16 } } %9 + %mrv = insertvalue { i8*, { i32, { i16 }, { i16 } } } undef, i8* %0, 0 + %mrv8 = insertvalue { i8*, { i32, { i16 }, { i16 } } } %mrv, { i32, { i16 }, { i16 } } %12, 1 + ret { i8*, { i32, { i16 }, { i16 } } } %mrv8 +} + +declare i1 @__rt__list__set(i8*, i64, i8*) diff --git a/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@pre-mem2reg@llvm14.snap b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@pre-mem2reg@llvm14.snap new file mode 100644 index 0000000000..ba89dc6ccb --- /dev/null +++ b/hugr-llvm/src/extension/snapshots/hugr_llvm__extension__collections__test__set@pre-mem2reg@llvm14.snap @@ -0,0 +1,50 @@ +--- +source: hugr-llvm/src/extension/collections.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { i8*, { i32, { i16 }, { i16 } } } @_hl.main.1(i8* %0, i64 %1, i16 %2) { +alloca_block: + %"0" = alloca i8*, align 8 + %"1" = alloca { i32, { i16 }, { i16 } }, align 8 + %"2_0" = alloca i8*, align 8 + %"2_1" = alloca i64, align 8 + %"2_2" = alloca i16, align 2 + %"4_0" = alloca i8*, align 8 + %"4_1" = alloca { i32, { i16 }, { i16 } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i8* %0, i8** %"2_0", align 8 + store i64 %1, i64* %"2_1", align 4 + store i16 %2, i16* %"2_2", align 2 + %"2_01" = load i8*, i8** %"2_0", align 8 + %"2_12" = load i64, i64* %"2_1", align 4 + %"2_23" = load i16, i16* %"2_2", align 2 + %3 = alloca i16, align 2 + store i16 %"2_23", i16* %3, align 2 + %4 = bitcast i16* %3 to i8* + %5 = call i1 @__rt__list__set(i8* %"2_01", i64 %"2_12", i8* %4) + %6 = bitcast i8* %4 to i16* + %7 = load i16, i16* %6, align 2 + %8 = insertvalue { i16 } undef, i16 %7, 0 + %9 = insertvalue { i32, { i16 }, { i16 } } { i32 0, { i16 } poison, { i16 } poison }, { i16 } %8, 1 + %10 = insertvalue { i16 } undef, i16 %"2_23", 0 + %11 = insertvalue { i32, { i16 }, { i16 } } { i32 1, { i16 } poison, { i16 } poison }, { i16 } %10, 2 + %12 = select i1 %5, { i32, { i16 }, { i16 } } %11, { i32, { i16 }, { i16 } } %9 + store i8* %"2_01", i8** %"4_0", align 8 + store { i32, { i16 }, { i16 } } %12, { i32, { i16 }, { i16 } }* %"4_1", align 4 + %"4_04" = load i8*, i8** %"4_0", align 8 + %"4_15" = load { i32, { i16 }, { i16 } }, { i32, { i16 }, { i16 } }* %"4_1", align 4 + store i8* %"4_04", i8** %"0", align 8 + store { i32, { i16 }, { i16 } } %"4_15", { i32, { i16 }, { i16 } }* %"1", align 4 + %"06" = load i8*, i8** %"0", align 8 + %"17" = load { i32, { i16 }, { i16 } }, { i32, { i16 }, { i16 } }* %"1", align 4 + %mrv = insertvalue { i8*, { i32, { i16 }, { i16 } } } undef, i8* %"06", 0 + %mrv8 = insertvalue { i8*, { i32, { i16 }, { i16 } } } %mrv, { i32, { i16 }, { i16 } } %"17", 1 + ret { i8*, { i32, { i16 }, { i16 } } } %mrv8 +} + +declare i1 @__rt__list__set(i8*, i64, i8*)