From 595e63f79c1f61edb841f52bfb63eb023e0f0f32 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 10 Dec 2024 09:19:44 +0000 Subject: [PATCH 1/7] tests: Add tail loop emission insta tests --- hugr-llvm/src/emit/test.rs | 163 ++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) diff --git a/hugr-llvm/src/emit/test.rs b/hugr-llvm/src/emit/test.rs index 8bf8856c1..263799ef6 100644 --- a/hugr-llvm/src/emit/test.rs +++ b/hugr-llvm/src/emit/test.rs @@ -4,14 +4,14 @@ use anyhow::{anyhow, Result}; use hugr_core::builder::{ BuildHandle, Container, DFGWrapper, HugrBuilder, ModuleBuilder, SubContainer, }; -use hugr_core::extension::prelude::PRELUDE_ID; +use hugr_core::extension::prelude::{bool_t, usize_t, PRELUDE, PRELUDE_ID}; use hugr_core::extension::{ExtensionRegistry, ExtensionSet}; 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::{collections, logic}; -use hugr_core::types::TypeRow; +use hugr_core::types::{SumType, TypeRow}; use hugr_core::{Hugr, HugrView}; use inkwell::module::Module; use inkwell::passes::PassManager; @@ -549,6 +549,165 @@ mod test_fns { check_emission!(hugr, llvm_ctx); } + #[rstest] + fn tail_loop_simple(mut llvm_ctx: TestContext) { + // Infinite loop + let hugr = { + let just_input = usize_t(); + let just_output = Type::UNIT; + let sum_ty = SumType::new(vec![just_input.clone(), just_output.clone()]); + let input_v = TypeRow::from(vec![just_input.clone()]); + let output_v = TypeRow::from(vec![just_output.clone()]); + + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); + + SimpleHugrConfig::new() + .with_extensions(PRELUDE_REGISTRY.clone()) + .with_ins(input_v) + .with_outs(output_v) + .finish(|mut builder: DFGW| { + let [just_in_w] = builder.input_wires_arr(); + let mut tail_b = builder + .tail_loop_builder( + [(just_input.clone(), just_in_w)], + [], + vec![just_output.clone()].into(), + ) + .unwrap(); + + let input = tail_b.input(); + let [inp_w] = input.outputs_arr(); + + let loop_sig = tail_b.loop_signature().unwrap().clone(); + + // builder.add_dataflow_op(ops::Noop, input_wires) + + let sum_inp_w = tail_b.make_continue(loop_sig.clone(), [inp_w]).unwrap(); + + let outs @ [_] = tail_b + .finish_with_outputs(sum_inp_w, []) + .unwrap() + .outputs_arr(); + builder.finish_with_outputs(outs).unwrap() + }) + }; + check_emission!(hugr, llvm_ctx); + } + + #[rstest] + fn tail_loop(mut llvm_ctx: TestContext) { + // Implement the hugr equivalent of the program: + let hugr = { + let int_ty = int_types::int_type(6); + let just_input = int_ty.clone(); + let just_output = Type::UNIT; + let other_ty = int_ty.clone(); + let sum_ty = SumType::new(vec![just_input.clone(), just_output.clone()]); + let input_v = TypeRow::from(vec![just_input.clone(), other_ty.clone()]); + let output_v = TypeRow::from(vec![just_output.clone(), other_ty.clone()]); + + llvm_ctx.add_extensions(add_int_extensions); + + let mut registry = PRELUDE_REGISTRY.clone(); + registry.register(int_ops::EXTENSION.clone()).unwrap(); + registry.register(int_types::EXTENSION.clone()).unwrap(); + + SimpleHugrConfig::new() + .with_extensions(registry) + .with_ins(input_v) + .with_outs(output_v) + .finish(|mut builder: DFGW| { + let [just_in_w, other_w] = builder.input_wires_arr(); + let mut tail_b = builder + .tail_loop_builder( + [(just_input.clone(), just_in_w)], + [(other_ty.clone(), other_w)], + vec![just_output.clone()].into(), + ) + .unwrap(); + let [sum_inp_w, other_w] = tail_b.input_wires_arr(); + + let zero = ConstInt::new_u(6, 0).unwrap(); + let zero_w = tail_b.add_load_value(zero); + let [result] = tail_b + .add_dataflow_op( + int_ops::IntOpDef::ile_u.with_log_width(6), + [sum_inp_w, zero_w], + ) + .unwrap() + .outputs_arr(); + let input = tail_b.input(); + let [inp_w, other_w] = input.outputs_arr(); + + let loop_sig = tail_b.loop_signature().unwrap().clone(); + + let sum_inp_w = tail_b.make_continue(loop_sig.clone(), [inp_w]).unwrap(); + + let cond = { + let mut cond_b = tail_b + .conditional_builder( + ([just_input.into(), just_output.into()], sum_inp_w), + vec![(other_ty.clone(), other_w)], + vec![sum_ty.into(), other_ty.clone()].into(), + ) + .unwrap(); + + // If the check is false, we add 1 and continue + let mut false_case_b = cond_b.case_builder(0).unwrap(); + let [counter, val] = false_case_b.input_wires_arr(); + let one = ConstInt::new_u(6, 1).unwrap(); + let one_w = false_case_b.add_load_value(one); + + let two = ConstInt::new_u(6, 2).unwrap(); + let two_w = false_case_b.add_load_value(two); + let [val] = false_case_b + .add_dataflow_op( + int_ops::IntOpDef::imul.with_log_width(6), + [val, two_w], + ) + .unwrap() + .outputs_arr(); + + let [counter] = false_case_b + .add_dataflow_op( + int_ops::IntOpDef::isub.with_log_width(6), + [counter, one_w], + ) + .unwrap() + .outputs_arr(); + let tagged_counter = false_case_b + .make_continue(loop_sig.clone(), [counter]) + .unwrap(); + + false_case_b + .finish_with_outputs([tagged_counter, val]) + .unwrap(); + + // In the true case, we break and output true along with the "other" input wire + let mut true_case_b = cond_b.case_builder(1).unwrap(); + + let [_, val_w] = true_case_b.input_wires_arr(); + let unit_v = Value::unit_sum(0, 1).unwrap(); + let unit_w = true_case_b.add_load_value(unit_v); + let tagged_output = + true_case_b.make_break(loop_sig.clone(), [unit_w]).unwrap(); + true_case_b + .finish_with_outputs([tagged_output, val_w]) + .unwrap(); + + cond_b.finish_sub_container().unwrap() + }; + let [sum, rest] = cond.outputs_arr(); + let outs @ [_, _] = tail_b + .finish_with_outputs(sum, [rest]) + .unwrap() + .outputs_arr(); + builder.finish_with_outputs(outs).unwrap() + }) + }; + check_emission!(hugr, llvm_ctx); + } + #[rstest] fn test_exec(mut exec_ctx: TestContext) { let hugr = SimpleHugrConfig::new() From 86190eece392c6b1857b20b00f57dafb2a0cb278 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 10 Dec 2024 09:20:40 +0000 Subject: [PATCH 2/7] typos --- hugr-llvm/src/emit/func.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugr-llvm/src/emit/func.rs b/hugr-llvm/src/emit/func.rs index 0a09dc9b3..0d954d55f 100644 --- a/hugr-llvm/src/emit/func.rs +++ b/hugr-llvm/src/emit/func.rs @@ -252,7 +252,7 @@ impl<'c, 'a, H: HugrView> EmitFuncContext<'c, 'a, H> { Ok(r) } - /// Returns a [RowMailBox] mapped to thie ouput wires of `node`. When emitting a node + /// Returns a [RowMailBox] mapped to the output wires of `node`. When emitting a node /// output values are written to this mailbox. pub fn node_outs_rmb<'hugr, OT: 'hugr>( &mut self, From c3ddd38d27af3308eb44ccc0f8849a5e6fdb8220 Mon Sep 17 00:00:00 2001 From: Craig Roy Date: Tue, 10 Dec 2024 09:30:37 +0000 Subject: [PATCH 3/7] WIP: Tail loop emission --- hugr-llvm/src/emit/ops.rs | 78 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/hugr-llvm/src/emit/ops.rs b/hugr-llvm/src/emit/ops.rs index 5fdbd5a76..c8991e514 100644 --- a/hugr-llvm/src/emit/ops.rs +++ b/hugr-llvm/src/emit/ops.rs @@ -1,15 +1,15 @@ use anyhow::{anyhow, bail, Result}; use hugr_core::ops::{ constant::Sum, Call, CallIndirect, Case, Conditional, Const, ExtensionOp, Input, LoadConstant, - LoadFunction, OpTag, OpTrait, OpType, Output, Tag, Value, CFG, + LoadFunction, OpTag, OpTrait, OpType, Output, Tag, TailLoop, Value, CFG, }; use hugr_core::{ hugr::views::SiblingGraph, types::{SumType, Type, TypeEnum}, HugrView, NodeIndex, }; -use inkwell::types::BasicTypeEnum; -use inkwell::values::{BasicValueEnum, CallableValue}; +use inkwell::types::{BasicTypeEnum, IntType}; +use inkwell::values::{BasicValueEnum, CallableValue, IntValue}; use itertools::{zip_eq, Itertools}; use petgraph::visit::Walker; @@ -21,7 +21,7 @@ use crate::{ use super::{ deaggregate_call_result, - func::{EmitFuncContext, RowPromise}, + func::{EmitFuncContext, RowMailBox, RowPromise}, EmitOpArgs, }; @@ -31,6 +31,7 @@ struct DataflowParentEmitter<'c, 'hugr, OT, H> { node: FatNode<'hugr, OT, H>, inputs: Option>>, outputs: Option>, + output_vals: Option>>, } impl<'c, 'hugr, OT: OpTrait, H: HugrView> DataflowParentEmitter<'c, 'hugr, OT, H> @@ -42,6 +43,7 @@ where node: args.node, inputs: Some(args.inputs), outputs: Some(args.outputs), + output_vals: None, } } @@ -58,7 +60,7 @@ where .ok_or(anyhow!("DataflowParentEmitter: Output taken twice")) } - pub fn emit_children(mut self, context: &mut EmitFuncContext<'c, '_, H>) -> Result<()> { + pub fn emit_children(&mut self, context: &mut EmitFuncContext<'c, '_, H>) -> Result<()> { use petgraph::visit::Topo; let node = self.node; if !OpTag::DataflowParent.is_superset(node.tag()) { @@ -306,6 +308,70 @@ fn emit_cfg<'c, H: HugrView>( cfg::CfgEmitter::new(context, args)?.emit_children(context) } +fn emit_tail_loop<'c, H: HugrView>( + context: &mut EmitFuncContext<'c, '_, H>, + args: EmitOpArgs<'c, '_, TailLoop, H> +) -> Result<()> { + // TODO: Switch on the tag in loop_body to see where to go next + // TODO: Handle "other" args + + + // Make a block to jump to when we `Break` + let out_bb = context.new_basic_block("loop_out", None); + // A block for the body of the loop + let body_bb = context.new_basic_block("loop_body", Some(out_bb)); + // Pack input data into a sum type - do we need this? + let prep_bb = context.new_basic_block("loop_prep", Some(body_bb)); + + context.builder().build_unconditional_branch(prep_bb); + + let sum_ty = SumType::new([args.node().just_inputs.clone(), args.node().just_outputs.clone()]); + let outs_rmb = context.node_outs_rmb(args.node)?; + + { + let builder = context.builder(); + builder.position_at_end(prep_bb); + let body_in_row = args.node.just_inputs.clone(); + let body_in_len = body_in_row.len(); + let body_in_tuple = context.llvm_sum_type(SumType::new_tuple(body_in_row))?; + + let mut loop_inputs = args.inputs.clone(); + let other_inputs = loop_inputs.split_off(body_in_len); + let loop_input_ptr = builder.build_alloca(body_in_tuple.clone(), "loop_input")?; + + let body_in_tup = body_in_tuple.build_tag(builder, 0, loop_inputs)?; + builder.build_store(loop_input_ptr, body_in_tup); + builder.build_unconditional_branch(body_bb); + + builder.position_at_end(body_bb); + }; + + + // Emit the body of the loop into the right block + let mut dfpe = DataflowParentEmitter::new(args); + dfpe.emit_children(context)?; + + // After the body we need to unpack the row type, then jump to the right block + let builder = context.builder(); + let output_vals: Vec = outs_rmb.read(builder, []).unwrap(); + let output_types: Vec<_> = outs_rmb.get_types().collect(); + let llvm_sum_ty = LLVMSumType::try_new(&context.typing_session(), sum_ty)?; + + println!("{:?}", output_vals); + let sum_output = LLVMSumValue::try_new(output_vals[0], llvm_sum_ty)?; + let tag = sum_output.build_get_tag(builder)?; + + let tag = IntValue::try_from(output_vals[0]).unwrap(); + let continue_tag = context.iw_context().i64_type().const_int(0, false); + let break_tag = context.iw_context().i64_type().const_int(1, false); + // TODO: Make this a conditional branch instead of switch + builder.build_switch(tag, out_bb, &[(break_tag, out_bb), (continue_tag, prep_bb)]); +du + // Return Ok so we can see the insta emission with + // `cargo insta test` for debugging + Ok(()) +} + fn emit_optype<'c, H: HugrView>( context: &mut EmitFuncContext<'c, '_, H>, args: EmitOpArgs<'c, '_, OpType, H>, @@ -330,7 +396,7 @@ fn emit_optype<'c, H: HugrView>( context.push_todo_func(node.into_ot(fd)); Ok(()) } - + OpType::TailLoop(x) => emit_tail_loop(context, args.into_ot(x)), _ => Err(anyhow!("Invalid child for Dataflow Parent: {node}")), } } From 56942ce4961bc182930e5fd9a9e72e08a528a2c7 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 11 Dec 2024 06:28:07 +0000 Subject: [PATCH 4/7] tests pass --- hugr-llvm/src/emit/func/mailbox.rs | 15 +- hugr-llvm/src/emit/ops.rs | 80 ++++----- ...mit__test__test_fns__tail_loop@llvm14.snap | 71 ++++++++ ...est_fns__tail_loop@pre-mem2reg@llvm14.snap | 168 ++++++++++++++++++ ...st__test_fns__tail_loop_simple@llvm14.snap | 36 ++++ ...__tail_loop_simple@pre-mem2reg@llvm14.snap | 55 ++++++ hugr-llvm/src/sum.rs | 2 +- 7 files changed, 381 insertions(+), 46 deletions(-) create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@llvm14.snap create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14.snap diff --git a/hugr-llvm/src/emit/func/mailbox.rs b/hugr-llvm/src/emit/func/mailbox.rs index a5c8b2e7b..5dc25fb29 100644 --- a/hugr-llvm/src/emit/func/mailbox.rs +++ b/hugr-llvm/src/emit/func/mailbox.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, rc::Rc}; -use anyhow::Result; +use anyhow::{bail, Result}; use delegate::delegate; use inkwell::{ builder::Builder, @@ -148,6 +148,19 @@ impl<'c> RowMailBox<'c> { builder: &Builder<'c>, vs: impl IntoIterator>, ) -> Result<()> { + let vs = vs.into_iter().collect_vec(); + #[cfg(debug_assertions)] + { + let actual_types = vs.clone().into_iter().map(|x| x.get_type()).collect_vec(); + let expected_types = self.get_types().collect_vec(); + if actual_types != expected_types { + bail!( + "RowMailbox::write: Expected types {:?}, got {:?}", + expected_types, + actual_types + ); + } + } zip_eq(self.0.iter(), vs).try_for_each(|(mb, v)| mb.write(builder, v)) } diff --git a/hugr-llvm/src/emit/ops.rs b/hugr-llvm/src/emit/ops.rs index c8991e514..063099911 100644 --- a/hugr-llvm/src/emit/ops.rs +++ b/hugr-llvm/src/emit/ops.rs @@ -314,61 +314,53 @@ fn emit_tail_loop<'c, H: HugrView>( ) -> Result<()> { // TODO: Switch on the tag in loop_body to see where to go next // TODO: Handle "other" args + let node = args.node(); // Make a block to jump to when we `Break` let out_bb = context.new_basic_block("loop_out", None); // A block for the body of the loop let body_bb = context.new_basic_block("loop_body", Some(out_bb)); - // Pack input data into a sum type - do we need this? - let prep_bb = context.new_basic_block("loop_prep", Some(body_bb)); - - context.builder().build_unconditional_branch(prep_bb); - - let sum_ty = SumType::new([args.node().just_inputs.clone(), args.node().just_outputs.clone()]); - let outs_rmb = context.node_outs_rmb(args.node)?; - { - let builder = context.builder(); - builder.position_at_end(prep_bb); - let body_in_row = args.node.just_inputs.clone(); - let body_in_len = body_in_row.len(); - let body_in_tuple = context.llvm_sum_type(SumType::new_tuple(body_in_row))?; - - let mut loop_inputs = args.inputs.clone(); - let other_inputs = loop_inputs.split_off(body_in_len); - let loop_input_ptr = builder.build_alloca(body_in_tuple.clone(), "loop_input")?; + let (body_i_node, body_o_node) = node.get_io().unwrap(); + let body_i_rmb = context.node_outs_rmb(body_i_node)?; + let body_o_rmb = context.node_ins_rmb(body_o_node)?; - let body_in_tup = body_in_tuple.build_tag(builder, 0, loop_inputs)?; - builder.build_store(loop_input_ptr, body_in_tup); - builder.build_unconditional_branch(body_bb); + body_i_rmb.write(context.builder(), args.inputs)?; + context.builder().build_unconditional_branch(body_bb)?; - builder.position_at_end(body_bb); + let control_llvm_sum_type = { + let sum_ty = SumType::new([node.just_inputs.clone(), node.just_outputs.clone()]); + context.llvm_sum_type(sum_ty)? }; - - // Emit the body of the loop into the right block - let mut dfpe = DataflowParentEmitter::new(args); - dfpe.emit_children(context)?; - - // After the body we need to unpack the row type, then jump to the right block - let builder = context.builder(); - let output_vals: Vec = outs_rmb.read(builder, []).unwrap(); - let output_types: Vec<_> = outs_rmb.get_types().collect(); - let llvm_sum_ty = LLVMSumType::try_new(&context.typing_session(), sum_ty)?; - - println!("{:?}", output_vals); - let sum_output = LLVMSumValue::try_new(output_vals[0], llvm_sum_ty)?; - let tag = sum_output.build_get_tag(builder)?; - - let tag = IntValue::try_from(output_vals[0]).unwrap(); - let continue_tag = context.iw_context().i64_type().const_int(0, false); - let break_tag = context.iw_context().i64_type().const_int(1, false); - // TODO: Make this a conditional branch instead of switch - builder.build_switch(tag, out_bb, &[(break_tag, out_bb), (continue_tag, prep_bb)]); -du - // Return Ok so we can see the insta emission with - // `cargo insta test` for debugging + context.build_positioned(body_bb, move |context| { + let inputs = body_i_rmb.read_vec(context.builder(), [])?; + emit_dataflow_parent( + context, + EmitOpArgs { + node, + inputs, + outputs: body_o_rmb.promise(), + }, + )?; + let dataflow_outputs = body_o_rmb.read_vec(context.builder(), [])?; + let control_val = LLVMSumValue::try_new(dataflow_outputs[0], control_llvm_sum_type)?; + let mut outputs = Some(args.outputs); + + control_val.build_destructure(context.builder(), |builder, tag, mut values| { + values.extend(dataflow_outputs[1..].iter().copied()); + if tag == 0 { + body_i_rmb.write(builder, values)?; + builder.build_unconditional_branch(body_bb)?; + } else { + outputs.take().unwrap().finish(builder, values)?; + builder.build_unconditional_branch(out_bb)?; + } + Ok(()) + }) + })?; + context.builder().position_at_end(out_bb); Ok(()) } diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap new file mode 100644 index 000000000..33109ab27 --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap @@ -0,0 +1,71 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { { {} }, i64 } @_hl.main.1(i64 %0, i64 %1) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + br label %loop_body + +loop_body: ; preds = %20, %entry_block + %"5_0.0" = phi i64 [ %0, %entry_block ], [ %22, %20 ] + %"5_1.0" = phi i64 [ %1, %entry_block ], [ %"19.0", %20 ] + %2 = insertvalue { i64 } undef, i64 %"5_0.0", 0 + %3 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %2, 1 + %4 = extractvalue { i32, { i64 }, { { {} } } } %3, 0 + switch i32 %4, label %5 [ + i32 1, label %8 + ] + +5: ; preds = %loop_body + %6 = extractvalue { i32, { i64 }, { { {} } } } %3, 1 + %7 = extractvalue { i64 } %6, 0 + br label %cond_12_case_0 + +8: ; preds = %loop_body + %9 = extractvalue { i32, { i64 }, { { {} } } } %3, 2 + %10 = extractvalue { { {} } } %9, 0 + br label %cond_12_case_1 + +loop_out: ; preds = %23 + %mrv = insertvalue { { {} }, i64 } undef, { {} } %25, 0 + %mrv40 = insertvalue { { {} }, i64 } %mrv, i64 %"19.0", 1 + ret { { {} }, i64 } %mrv40 + +cond_12_case_0: ; preds = %5 + %11 = mul i64 %"5_1.0", 2 + %12 = sub i64 %7, 1 + %13 = insertvalue { i64 } undef, i64 %12, 0 + %14 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %13, 1 + br label %cond_exit_12 + +cond_12_case_1: ; preds = %8 + %15 = insertvalue { { {} } } undef, { {} } undef, 0 + %16 = insertvalue { i32, { i64 }, { { {} } } } { i32 1, { i64 } poison, { { {} } } poison }, { { {} } } %15, 2 + br label %cond_exit_12 + +cond_exit_12: ; preds = %cond_12_case_1, %cond_12_case_0 + %"08.0" = phi { i32, { i64 }, { { {} } } } [ %14, %cond_12_case_0 ], [ %16, %cond_12_case_1 ] + %"19.0" = phi i64 [ %11, %cond_12_case_0 ], [ %"5_1.0", %cond_12_case_1 ] + %17 = icmp ule i64 %"5_0.0", 0 + %18 = select i1 %17, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } + %19 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 0 + switch i32 %19, label %20 [ + i32 1, label %23 + ] + +20: ; preds = %cond_exit_12 + %21 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 1 + %22 = extractvalue { i64 } %21, 0 + br label %loop_body + +23: ; preds = %cond_exit_12 + %24 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 2 + %25 = extractvalue { { {} } } %24, 0 + br label %loop_out +} diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap new file mode 100644 index 000000000..4b5b4ccf4 --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap @@ -0,0 +1,168 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { { {} }, i64 } @_hl.main.1(i64 %0, i64 %1) { +alloca_block: + %"0" = alloca { {} }, align 8 + %"1" = alloca i64, align 8 + %"2_0" = alloca i64, align 8 + %"2_1" = alloca i64, align 8 + %"4_0" = alloca { {} }, align 8 + %"4_1" = alloca i64, align 8 + %"5_0" = alloca i64, align 8 + %"5_1" = alloca i64, align 8 + %"12_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"12_1" = alloca i64, align 8 + %"8_0" = alloca i64, align 8 + %"10_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"08" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"19" = alloca i64, align 8 + %"012" = alloca i64, align 8 + %"113" = alloca i64, align 8 + %"19_0" = alloca i64, align 8 + %"17_0" = alloca i64, align 8 + %"14_0" = alloca i64, align 8 + %"14_1" = alloca i64, align 8 + %"20_0" = alloca i64, align 8 + %"21_0" = alloca i64, align 8 + %"22_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"023" = alloca { {} }, align 8 + %"124" = alloca i64, align 8 + %"27_0" = alloca { {} }, align 8 + %"28_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"24_0" = alloca { {} }, align 8 + %"24_1" = alloca i64, align 8 + %"9_0" = alloca { i32, {}, {} }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i64 %0, i64* %"2_0", align 4 + store i64 %1, i64* %"2_1", align 4 + %"2_01" = load i64, i64* %"2_0", align 4 + %"2_12" = load i64, i64* %"2_1", align 4 + store i64 %"2_01", i64* %"5_0", align 4 + store i64 %"2_12", i64* %"5_1", align 4 + br label %loop_body + +loop_body: ; preds = %20, %entry_block + %"5_03" = load i64, i64* %"5_0", align 4 + %"5_14" = load i64, i64* %"5_1", align 4 + store i64 0, i64* %"8_0", align 4 + store i64 %"5_03", i64* %"5_0", align 4 + store i64 %"5_14", i64* %"5_1", align 4 + %"5_05" = load i64, i64* %"5_0", align 4 + %2 = insertvalue { i64 } undef, i64 %"5_05", 0 + %3 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %2, 1 + store { i32, { i64 }, { { {} } } } %3, { i32, { i64 }, { { {} } } }* %"10_0", align 4 + %"10_06" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"10_0", align 4 + %"5_17" = load i64, i64* %"5_1", align 4 + %4 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 0 + switch i32 %4, label %5 [ + i32 1, label %8 + ] + +5: ; preds = %loop_body + %6 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 1 + %7 = extractvalue { i64 } %6, 0 + store i64 %7, i64* %"012", align 4 + store i64 %"5_17", i64* %"113", align 4 + br label %cond_12_case_0 + +8: ; preds = %loop_body + %9 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 2 + %10 = extractvalue { { {} } } %9, 0 + store { {} } %10, { {} }* %"023", align 1 + store i64 %"5_17", i64* %"124", align 4 + br label %cond_12_case_1 + +loop_out: ; preds = %23 + %"4_036" = load { {} }, { {} }* %"4_0", align 1 + %"4_137" = load i64, i64* %"4_1", align 4 + store { {} } %"4_036", { {} }* %"0", align 1 + store i64 %"4_137", i64* %"1", align 4 + %"038" = load { {} }, { {} }* %"0", align 1 + %"139" = load i64, i64* %"1", align 4 + %mrv = insertvalue { { {} }, i64 } undef, { {} } %"038", 0 + %mrv40 = insertvalue { { {} }, i64 } %mrv, i64 %"139", 1 + ret { { {} }, i64 } %mrv40 + +cond_12_case_0: ; preds = %5 + %"014" = load i64, i64* %"012", align 4 + %"115" = load i64, i64* %"113", align 4 + store i64 2, i64* %"19_0", align 4 + store i64 1, i64* %"17_0", align 4 + store i64 %"014", i64* %"14_0", align 4 + store i64 %"115", i64* %"14_1", align 4 + %"14_116" = load i64, i64* %"14_1", align 4 + %"19_017" = load i64, i64* %"19_0", align 4 + %11 = mul i64 %"14_116", %"19_017" + store i64 %11, i64* %"20_0", align 4 + %"14_018" = load i64, i64* %"14_0", align 4 + %"17_019" = load i64, i64* %"17_0", align 4 + %12 = sub i64 %"14_018", %"17_019" + store i64 %12, i64* %"21_0", align 4 + %"21_020" = load i64, i64* %"21_0", align 4 + %13 = insertvalue { i64 } undef, i64 %"21_020", 0 + %14 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %13, 1 + store { i32, { i64 }, { { {} } } } %14, { i32, { i64 }, { { {} } } }* %"22_0", align 4 + %"22_021" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"22_0", align 4 + %"20_022" = load i64, i64* %"20_0", align 4 + store { i32, { i64 }, { { {} } } } %"22_021", { i32, { i64 }, { { {} } } }* %"08", align 4 + store i64 %"20_022", i64* %"19", align 4 + br label %cond_exit_12 + +cond_12_case_1: ; preds = %8 + %"025" = load { {} }, { {} }* %"023", align 1 + %"126" = load i64, i64* %"124", align 4 + store { {} } undef, { {} }* %"27_0", align 1 + %"27_027" = load { {} }, { {} }* %"27_0", align 1 + %15 = insertvalue { { {} } } undef, { {} } %"27_027", 0 + %16 = insertvalue { i32, { i64 }, { { {} } } } { i32 1, { i64 } poison, { { {} } } poison }, { { {} } } %15, 2 + store { i32, { i64 }, { { {} } } } %16, { i32, { i64 }, { { {} } } }* %"28_0", align 4 + store { {} } %"025", { {} }* %"24_0", align 1 + store i64 %"126", i64* %"24_1", align 4 + %"28_028" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"28_0", align 4 + %"24_129" = load i64, i64* %"24_1", align 4 + store { i32, { i64 }, { { {} } } } %"28_028", { i32, { i64 }, { { {} } } }* %"08", align 4 + store i64 %"24_129", i64* %"19", align 4 + br label %cond_exit_12 + +cond_exit_12: ; preds = %cond_12_case_1, %cond_12_case_0 + %"010" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"08", align 4 + %"111" = load i64, i64* %"19", align 4 + store { i32, { i64 }, { { {} } } } %"010", { i32, { i64 }, { { {} } } }* %"12_0", align 4 + store i64 %"111", i64* %"12_1", align 4 + %"12_030" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 + %"12_131" = load i64, i64* %"12_1", align 4 + store { i32, { i64 }, { { {} } } } %"12_030", { i32, { i64 }, { { {} } } }* %"12_0", align 4 + store i64 %"12_131", i64* %"12_1", align 4 + %"5_032" = load i64, i64* %"5_0", align 4 + %"8_033" = load i64, i64* %"8_0", align 4 + %17 = icmp ule i64 %"5_032", %"8_033" + %18 = select i1 %17, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } + store { i32, {}, {} } %18, { i32, {}, {} }* %"9_0", align 4 + %"12_034" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 + %"12_135" = load i64, i64* %"12_1", align 4 + %19 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 0 + switch i32 %19, label %20 [ + i32 1, label %23 + ] + +20: ; preds = %cond_exit_12 + %21 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 1 + %22 = extractvalue { i64 } %21, 0 + store i64 %22, i64* %"5_0", align 4 + store i64 %"12_135", i64* %"5_1", align 4 + br label %loop_body + +23: ; preds = %cond_exit_12 + %24 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 2 + %25 = extractvalue { { {} } } %24, 0 + store { {} } %25, { {} }* %"4_0", align 1 + store i64 %"12_135", i64* %"4_1", align 4 + br label %loop_out +} diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@llvm14.snap new file mode 100644 index 000000000..408f61aeb --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@llvm14.snap @@ -0,0 +1,36 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { {} } @_hl.main.1(i64 %0) { +alloca_block: + br label %entry_block + +entry_block: ; preds = %alloca_block + br label %loop_body + +loop_body: ; preds = %4, %entry_block + %"5_0.0" = phi i64 [ %0, %entry_block ], [ %6, %4 ] + %1 = insertvalue { i64 } undef, i64 %"5_0.0", 0 + %2 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %1, 1 + %3 = extractvalue { i32, { i64 }, { { {} } } } %2, 0 + switch i32 %3, label %4 [ + i32 1, label %7 + ] + +4: ; preds = %loop_body + %5 = extractvalue { i32, { i64 }, { { {} } } } %2, 1 + %6 = extractvalue { i64 } %5, 0 + br label %loop_body + +7: ; preds = %loop_body + %8 = extractvalue { i32, { i64 }, { { {} } } } %2, 2 + %9 = extractvalue { { {} } } %8, 0 + br label %loop_out + +loop_out: ; preds = %7 + ret { {} } %9 +} diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14.snap new file mode 100644 index 000000000..7c1a36ea0 --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14.snap @@ -0,0 +1,55 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { {} } @_hl.main.1(i64 %0) { +alloca_block: + %"0" = alloca { {} }, align 8 + %"2_0" = alloca i64, align 8 + %"4_0" = alloca { {} }, align 8 + %"5_0" = alloca i64, align 8 + %"7_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i64 %0, i64* %"2_0", align 4 + %"2_01" = load i64, i64* %"2_0", align 4 + store i64 %"2_01", i64* %"5_0", align 4 + br label %loop_body + +loop_body: ; preds = %4, %entry_block + %"5_02" = load i64, i64* %"5_0", align 4 + store i64 %"5_02", i64* %"5_0", align 4 + %"5_03" = load i64, i64* %"5_0", align 4 + %1 = insertvalue { i64 } undef, i64 %"5_03", 0 + %2 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %1, 1 + store { i32, { i64 }, { { {} } } } %2, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %"7_04" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + store { i32, { i64 }, { { {} } } } %"7_04", { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %"7_05" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %3 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 0 + switch i32 %3, label %4 [ + i32 1, label %7 + ] + +4: ; preds = %loop_body + %5 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 1 + %6 = extractvalue { i64 } %5, 0 + store i64 %6, i64* %"5_0", align 4 + br label %loop_body + +7: ; preds = %loop_body + %8 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 2 + %9 = extractvalue { { {} } } %8, 0 + store { {} } %9, { {} }* %"4_0", align 1 + br label %loop_out + +loop_out: ; preds = %7 + %"4_06" = load { {} }, { {} }* %"4_0", align 1 + store { {} } %"4_06", { {} }* %"0", align 1 + %"07" = load { {} }, { {} }* %"0", align 1 + ret { {} } %"07" +} diff --git a/hugr-llvm/src/sum.rs b/hugr-llvm/src/sum.rs index 31c6b5357..059b37873 100644 --- a/hugr-llvm/src/sum.rs +++ b/hugr-llvm/src/sum.rs @@ -249,7 +249,7 @@ impl<'c> LLVMSumValue<'c> { pub fn build_destructure( &self, builder: &Builder<'c>, - handler: impl Fn(&Builder<'c>, usize, Vec>) -> Result<()>, + mut handler: impl FnMut(&Builder<'c>, usize, Vec>) -> Result<()>, ) -> Result<()> { let orig_bb = builder .get_insert_block() From 87c48ed225210f343e9bb50e7812f6ed71bfaf32 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Wed, 11 Dec 2024 06:41:13 +0000 Subject: [PATCH 5/7] fmt --- hugr-llvm/src/emit/ops.rs | 11 ++++------- hugr-llvm/src/emit/test.rs | 13 ++++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/hugr-llvm/src/emit/ops.rs b/hugr-llvm/src/emit/ops.rs index 063099911..d84b62ba6 100644 --- a/hugr-llvm/src/emit/ops.rs +++ b/hugr-llvm/src/emit/ops.rs @@ -8,8 +8,8 @@ use hugr_core::{ types::{SumType, Type, TypeEnum}, HugrView, NodeIndex, }; -use inkwell::types::{BasicTypeEnum, IntType}; -use inkwell::values::{BasicValueEnum, CallableValue, IntValue}; +use inkwell::types::BasicTypeEnum; +use inkwell::values::{BasicValueEnum, CallableValue}; use itertools::{zip_eq, Itertools}; use petgraph::visit::Walker; @@ -21,7 +21,7 @@ use crate::{ use super::{ deaggregate_call_result, - func::{EmitFuncContext, RowMailBox, RowPromise}, + func::{EmitFuncContext, RowPromise}, EmitOpArgs, }; @@ -31,7 +31,6 @@ struct DataflowParentEmitter<'c, 'hugr, OT, H> { node: FatNode<'hugr, OT, H>, inputs: Option>>, outputs: Option>, - output_vals: Option>>, } impl<'c, 'hugr, OT: OpTrait, H: HugrView> DataflowParentEmitter<'c, 'hugr, OT, H> @@ -43,7 +42,6 @@ where node: args.node, inputs: Some(args.inputs), outputs: Some(args.outputs), - output_vals: None, } } @@ -310,13 +308,12 @@ fn emit_cfg<'c, H: HugrView>( fn emit_tail_loop<'c, H: HugrView>( context: &mut EmitFuncContext<'c, '_, H>, - args: EmitOpArgs<'c, '_, TailLoop, H> + args: EmitOpArgs<'c, '_, TailLoop, H>, ) -> Result<()> { // TODO: Switch on the tag in loop_body to see where to go next // TODO: Handle "other" args let node = args.node(); - // Make a block to jump to when we `Break` let out_bb = context.new_basic_block("loop_out", None); // A block for the body of the loop diff --git a/hugr-llvm/src/emit/test.rs b/hugr-llvm/src/emit/test.rs index 263799ef6..ad418bb84 100644 --- a/hugr-llvm/src/emit/test.rs +++ b/hugr-llvm/src/emit/test.rs @@ -4,14 +4,14 @@ use anyhow::{anyhow, Result}; use hugr_core::builder::{ BuildHandle, Container, DFGWrapper, HugrBuilder, ModuleBuilder, SubContainer, }; -use hugr_core::extension::prelude::{bool_t, usize_t, PRELUDE, PRELUDE_ID}; +use hugr_core::extension::prelude::PRELUDE_ID; use hugr_core::extension::{ExtensionRegistry, ExtensionSet}; 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::{collections, logic}; -use hugr_core::types::{SumType, TypeRow}; +use hugr_core::types::TypeRow; use hugr_core::{Hugr, HugrView}; use inkwell::module::Module; use inkwell::passes::PassManager; @@ -246,7 +246,7 @@ mod test_fns { use super::*; use crate::custom::CodegenExtsBuilder; use crate::extension::int::add_int_extensions; - use crate::types::HugrFuncType; + use crate::types::{HugrFuncType, HugrSumType}; use hugr_core::builder::DataflowSubContainer; use hugr_core::builder::{Container, Dataflow, HugrBuilder, ModuleBuilder, SubContainer}; @@ -555,7 +555,6 @@ mod test_fns { let hugr = { let just_input = usize_t(); let just_output = Type::UNIT; - let sum_ty = SumType::new(vec![just_input.clone(), just_output.clone()]); let input_v = TypeRow::from(vec![just_input.clone()]); let output_v = TypeRow::from(vec![just_output.clone()]); @@ -602,7 +601,7 @@ mod test_fns { let just_input = int_ty.clone(); let just_output = Type::UNIT; let other_ty = int_ty.clone(); - let sum_ty = SumType::new(vec![just_input.clone(), just_output.clone()]); + let sum_ty = HugrSumType::new(vec![just_input.clone(), just_output.clone()]); let input_v = TypeRow::from(vec![just_input.clone(), other_ty.clone()]); let output_v = TypeRow::from(vec![just_output.clone(), other_ty.clone()]); @@ -625,11 +624,11 @@ mod test_fns { vec![just_output.clone()].into(), ) .unwrap(); - let [sum_inp_w, other_w] = tail_b.input_wires_arr(); + let [sum_inp_w, _other_w] = tail_b.input_wires_arr(); let zero = ConstInt::new_u(6, 0).unwrap(); let zero_w = tail_b.add_load_value(zero); - let [result] = tail_b + let [_result] = tail_b .add_dataflow_op( int_ops::IntOpDef::ile_u.with_log_width(6), [sum_inp_w, zero_w], From 7bcb9eb338e104c6c3e9d96e77ba1e6780801060 Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Wed, 11 Dec 2024 14:24:06 +0000 Subject: [PATCH 6/7] add tail loop execution test --- ...mit__test__test_fns__tail_loop@llvm14.snap | 80 +++--- ...est_fns__tail_loop@pre-mem2reg@llvm14.snap | 239 ++++++++---------- ...t_fns__tail_loop@pre-mem2reg@llvm14_2.snap | 168 ++++++++++++ ...tail_loop_simple@pre-mem2reg@llvm14_3.snap | 55 ++++ hugr-llvm/src/emit/test.rs | 201 ++++++++------- 5 files changed, 474 insertions(+), 269 deletions(-) create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14_2.snap create mode 100644 hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14_3.snap diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap index 33109ab27..7765ae0a2 100644 --- a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@llvm14.snap @@ -5,67 +5,57 @@ expression: mod_str ; ModuleID = 'test_context' source_filename = "test_context" -define { { {} }, i64 } @_hl.main.1(i64 %0, i64 %1) { +define i64 @_hl.main.1() { alloca_block: br label %entry_block entry_block: ; preds = %alloca_block br label %loop_body -loop_body: ; preds = %20, %entry_block - %"5_0.0" = phi i64 [ %0, %entry_block ], [ %22, %20 ] - %"5_1.0" = phi i64 [ %1, %entry_block ], [ %"19.0", %20 ] - %2 = insertvalue { i64 } undef, i64 %"5_0.0", 0 - %3 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %2, 1 - %4 = extractvalue { i32, { i64 }, { { {} } } } %3, 0 - switch i32 %4, label %5 [ - i32 1, label %8 +loop_body: ; preds = %12, %entry_block + %"9_0.0" = phi i64 [ 3, %entry_block ], [ %14, %12 ] + %"9_1.0" = phi i64 [ 7, %entry_block ], [ %0, %12 ] + %0 = mul i64 %"9_1.0", 2 + %1 = icmp eq i64 %"9_0.0", 0 + %2 = select i1 %1, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } + %3 = extractvalue { i32, {}, {} } %2, 0 + switch i32 %3, label %4 [ + i32 1, label %6 ] -5: ; preds = %loop_body - %6 = extractvalue { i32, { i64 }, { { {} } } } %3, 1 - %7 = extractvalue { i64 } %6, 0 - br label %cond_12_case_0 +4: ; preds = %loop_body + %5 = extractvalue { i32, {}, {} } %2, 1 + br label %cond_17_case_0 -8: ; preds = %loop_body - %9 = extractvalue { i32, { i64 }, { { {} } } } %3, 2 - %10 = extractvalue { { {} } } %9, 0 - br label %cond_12_case_1 +6: ; preds = %loop_body + %7 = extractvalue { i32, {}, {} } %2, 2 + br label %cond_17_case_1 -loop_out: ; preds = %23 - %mrv = insertvalue { { {} }, i64 } undef, { {} } %25, 0 - %mrv40 = insertvalue { { {} }, i64 } %mrv, i64 %"19.0", 1 - ret { { {} }, i64 } %mrv40 +loop_out: ; preds = %15 + ret i64 %0 -cond_12_case_0: ; preds = %5 - %11 = mul i64 %"5_1.0", 2 - %12 = sub i64 %7, 1 - %13 = insertvalue { i64 } undef, i64 %12, 0 - %14 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %13, 1 - br label %cond_exit_12 +cond_17_case_0: ; preds = %4 + %8 = sub i64 %"9_0.0", 1 + %9 = insertvalue { i64 } undef, i64 %8, 0 + %10 = insertvalue { i32, { i64 }, {} } { i32 0, { i64 } poison, {} poison }, { i64 } %9, 1 + br label %cond_exit_17 -cond_12_case_1: ; preds = %8 - %15 = insertvalue { { {} } } undef, { {} } undef, 0 - %16 = insertvalue { i32, { i64 }, { { {} } } } { i32 1, { i64 } poison, { { {} } } poison }, { { {} } } %15, 2 - br label %cond_exit_12 +cond_17_case_1: ; preds = %6 + br label %cond_exit_17 -cond_exit_12: ; preds = %cond_12_case_1, %cond_12_case_0 - %"08.0" = phi { i32, { i64 }, { { {} } } } [ %14, %cond_12_case_0 ], [ %16, %cond_12_case_1 ] - %"19.0" = phi i64 [ %11, %cond_12_case_0 ], [ %"5_1.0", %cond_12_case_1 ] - %17 = icmp ule i64 %"5_0.0", 0 - %18 = select i1 %17, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } - %19 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 0 - switch i32 %19, label %20 [ - i32 1, label %23 +cond_exit_17: ; preds = %cond_17_case_1, %cond_17_case_0 + %"011.0" = phi { i32, { i64 }, {} } [ %10, %cond_17_case_0 ], [ { i32 1, { i64 } poison, {} undef }, %cond_17_case_1 ] + %11 = extractvalue { i32, { i64 }, {} } %"011.0", 0 + switch i32 %11, label %12 [ + i32 1, label %15 ] -20: ; preds = %cond_exit_12 - %21 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 1 - %22 = extractvalue { i64 } %21, 0 +12: ; preds = %cond_exit_17 + %13 = extractvalue { i32, { i64 }, {} } %"011.0", 1 + %14 = extractvalue { i64 } %13, 0 br label %loop_body -23: ; preds = %cond_exit_12 - %24 = extractvalue { i32, { i64 }, { { {} } } } %"08.0", 2 - %25 = extractvalue { { {} } } %24, 0 +15: ; preds = %cond_exit_17 + %16 = extractvalue { i32, { i64 }, {} } %"011.0", 2 br label %loop_out } diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap index 4b5b4ccf4..6f9d1cb13 100644 --- a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14.snap @@ -5,164 +5,125 @@ expression: mod_str ; ModuleID = 'test_context' source_filename = "test_context" -define { { {} }, i64 } @_hl.main.1(i64 %0, i64 %1) { +define i64 @_hl.main.1() { alloca_block: - %"0" = alloca { {} }, align 8 - %"1" = alloca i64, align 8 - %"2_0" = alloca i64, align 8 - %"2_1" = alloca i64, align 8 - %"4_0" = alloca { {} }, align 8 - %"4_1" = alloca i64, align 8 + %"0" = alloca i64, align 8 + %"7_0" = alloca i64, align 8 %"5_0" = alloca i64, align 8 - %"5_1" = alloca i64, align 8 - %"12_0" = alloca { i32, { i64 }, { { {} } } }, align 8 - %"12_1" = alloca i64, align 8 %"8_0" = alloca i64, align 8 - %"10_0" = alloca { i32, { i64 }, { { {} } } }, align 8 - %"08" = alloca { i32, { i64 }, { { {} } } }, align 8 - %"19" = alloca i64, align 8 - %"012" = alloca i64, align 8 - %"113" = alloca i64, align 8 - %"19_0" = alloca i64, align 8 - %"17_0" = alloca i64, align 8 - %"14_0" = alloca i64, align 8 - %"14_1" = alloca i64, align 8 + %"9_0" = alloca i64, align 8 + %"9_1" = alloca i64, align 8 + %"17_0" = alloca { i32, { i64 }, {} }, align 8 + %"16_0" = alloca i64, align 8 + %"15_0" = alloca i64, align 8 + %"12_0" = alloca i64, align 8 + %"13_0" = alloca { i32, {}, {} }, align 8 + %"011" = alloca { i32, { i64 }, {} }, align 8 + %"013" = alloca i64, align 8 + %"23_0" = alloca i64, align 8 %"20_0" = alloca i64, align 8 - %"21_0" = alloca i64, align 8 - %"22_0" = alloca { i32, { i64 }, { { {} } } }, align 8 - %"023" = alloca { {} }, align 8 - %"124" = alloca i64, align 8 - %"27_0" = alloca { {} }, align 8 - %"28_0" = alloca { i32, { i64 }, { { {} } } }, align 8 - %"24_0" = alloca { {} }, align 8 - %"24_1" = alloca i64, align 8 - %"9_0" = alloca { i32, {}, {} }, align 8 + %"24_0" = alloca i64, align 8 + %"25_0" = alloca { i32, { i64 }, {} }, align 8 + %"019" = alloca i64, align 8 + %"29_0" = alloca { i32, { i64 }, {} }, align 8 + %"27_0" = alloca i64, align 8 br label %entry_block entry_block: ; preds = %alloca_block - store i64 %0, i64* %"2_0", align 4 - store i64 %1, i64* %"2_1", align 4 - %"2_01" = load i64, i64* %"2_0", align 4 - %"2_12" = load i64, i64* %"2_1", align 4 - store i64 %"2_01", i64* %"5_0", align 4 - store i64 %"2_12", i64* %"5_1", align 4 + store i64 7, i64* %"7_0", align 4 + store i64 3, i64* %"5_0", align 4 + %"5_01" = load i64, i64* %"5_0", align 4 + %"7_02" = load i64, i64* %"7_0", align 4 + store i64 %"5_01", i64* %"9_0", align 4 + store i64 %"7_02", i64* %"9_1", align 4 br label %loop_body -loop_body: ; preds = %20, %entry_block - %"5_03" = load i64, i64* %"5_0", align 4 - %"5_14" = load i64, i64* %"5_1", align 4 - store i64 0, i64* %"8_0", align 4 - store i64 %"5_03", i64* %"5_0", align 4 - store i64 %"5_14", i64* %"5_1", align 4 - %"5_05" = load i64, i64* %"5_0", align 4 - %2 = insertvalue { i64 } undef, i64 %"5_05", 0 - %3 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %2, 1 - store { i32, { i64 }, { { {} } } } %3, { i32, { i64 }, { { {} } } }* %"10_0", align 4 - %"10_06" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"10_0", align 4 - %"5_17" = load i64, i64* %"5_1", align 4 - %4 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 0 - switch i32 %4, label %5 [ - i32 1, label %8 +loop_body: ; preds = %12, %entry_block + %"9_03" = load i64, i64* %"9_0", align 4 + %"9_14" = load i64, i64* %"9_1", align 4 + store i64 2, i64* %"15_0", align 4 + store i64 0, i64* %"12_0", align 4 + store i64 %"9_03", i64* %"9_0", align 4 + store i64 %"9_14", i64* %"9_1", align 4 + %"9_15" = load i64, i64* %"9_1", align 4 + %"15_06" = load i64, i64* %"15_0", align 4 + %0 = mul i64 %"9_15", %"15_06" + store i64 %0, i64* %"16_0", align 4 + %"9_07" = load i64, i64* %"9_0", align 4 + %"12_08" = load i64, i64* %"12_0", align 4 + %1 = icmp eq i64 %"9_07", %"12_08" + %2 = select i1 %1, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } + store { i32, {}, {} } %2, { i32, {}, {} }* %"13_0", align 4 + %"13_09" = load { i32, {}, {} }, { i32, {}, {} }* %"13_0", align 4 + %"9_010" = load i64, i64* %"9_0", align 4 + %3 = extractvalue { i32, {}, {} } %"13_09", 0 + switch i32 %3, label %4 [ + i32 1, label %6 ] -5: ; preds = %loop_body - %6 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 1 - %7 = extractvalue { i64 } %6, 0 - store i64 %7, i64* %"012", align 4 - store i64 %"5_17", i64* %"113", align 4 - br label %cond_12_case_0 +4: ; preds = %loop_body + %5 = extractvalue { i32, {}, {} } %"13_09", 1 + store i64 %"9_010", i64* %"013", align 4 + br label %cond_17_case_0 -8: ; preds = %loop_body - %9 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 2 - %10 = extractvalue { { {} } } %9, 0 - store { {} } %10, { {} }* %"023", align 1 - store i64 %"5_17", i64* %"124", align 4 - br label %cond_12_case_1 +6: ; preds = %loop_body + %7 = extractvalue { i32, {}, {} } %"13_09", 2 + store i64 %"9_010", i64* %"019", align 4 + br label %cond_17_case_1 -loop_out: ; preds = %23 - %"4_036" = load { {} }, { {} }* %"4_0", align 1 - %"4_137" = load i64, i64* %"4_1", align 4 - store { {} } %"4_036", { {} }* %"0", align 1 - store i64 %"4_137", i64* %"1", align 4 - %"038" = load { {} }, { {} }* %"0", align 1 - %"139" = load i64, i64* %"1", align 4 - %mrv = insertvalue { { {} }, i64 } undef, { {} } %"038", 0 - %mrv40 = insertvalue { { {} }, i64 } %mrv, i64 %"139", 1 - ret { { {} }, i64 } %mrv40 +loop_out: ; preds = %15 + %"8_026" = load i64, i64* %"8_0", align 4 + store i64 %"8_026", i64* %"0", align 4 + %"027" = load i64, i64* %"0", align 4 + ret i64 %"027" -cond_12_case_0: ; preds = %5 - %"014" = load i64, i64* %"012", align 4 - %"115" = load i64, i64* %"113", align 4 - store i64 2, i64* %"19_0", align 4 - store i64 1, i64* %"17_0", align 4 - store i64 %"014", i64* %"14_0", align 4 - store i64 %"115", i64* %"14_1", align 4 - %"14_116" = load i64, i64* %"14_1", align 4 - %"19_017" = load i64, i64* %"19_0", align 4 - %11 = mul i64 %"14_116", %"19_017" - store i64 %11, i64* %"20_0", align 4 - %"14_018" = load i64, i64* %"14_0", align 4 - %"17_019" = load i64, i64* %"17_0", align 4 - %12 = sub i64 %"14_018", %"17_019" - store i64 %12, i64* %"21_0", align 4 - %"21_020" = load i64, i64* %"21_0", align 4 - %13 = insertvalue { i64 } undef, i64 %"21_020", 0 - %14 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %13, 1 - store { i32, { i64 }, { { {} } } } %14, { i32, { i64 }, { { {} } } }* %"22_0", align 4 - %"22_021" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"22_0", align 4 - %"20_022" = load i64, i64* %"20_0", align 4 - store { i32, { i64 }, { { {} } } } %"22_021", { i32, { i64 }, { { {} } } }* %"08", align 4 - store i64 %"20_022", i64* %"19", align 4 - br label %cond_exit_12 +cond_17_case_0: ; preds = %4 + %"014" = load i64, i64* %"013", align 4 + store i64 1, i64* %"23_0", align 4 + store i64 %"014", i64* %"20_0", align 4 + %"20_015" = load i64, i64* %"20_0", align 4 + %"23_016" = load i64, i64* %"23_0", align 4 + %8 = sub i64 %"20_015", %"23_016" + store i64 %8, i64* %"24_0", align 4 + %"24_017" = load i64, i64* %"24_0", align 4 + %9 = insertvalue { i64 } undef, i64 %"24_017", 0 + %10 = insertvalue { i32, { i64 }, {} } { i32 0, { i64 } poison, {} poison }, { i64 } %9, 1 + store { i32, { i64 }, {} } %10, { i32, { i64 }, {} }* %"25_0", align 4 + %"25_018" = load { i32, { i64 }, {} }, { i32, { i64 }, {} }* %"25_0", align 4 + store { i32, { i64 }, {} } %"25_018", { i32, { i64 }, {} }* %"011", align 4 + br label %cond_exit_17 -cond_12_case_1: ; preds = %8 - %"025" = load { {} }, { {} }* %"023", align 1 - %"126" = load i64, i64* %"124", align 4 - store { {} } undef, { {} }* %"27_0", align 1 - %"27_027" = load { {} }, { {} }* %"27_0", align 1 - %15 = insertvalue { { {} } } undef, { {} } %"27_027", 0 - %16 = insertvalue { i32, { i64 }, { { {} } } } { i32 1, { i64 } poison, { { {} } } poison }, { { {} } } %15, 2 - store { i32, { i64 }, { { {} } } } %16, { i32, { i64 }, { { {} } } }* %"28_0", align 4 - store { {} } %"025", { {} }* %"24_0", align 1 - store i64 %"126", i64* %"24_1", align 4 - %"28_028" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"28_0", align 4 - %"24_129" = load i64, i64* %"24_1", align 4 - store { i32, { i64 }, { { {} } } } %"28_028", { i32, { i64 }, { { {} } } }* %"08", align 4 - store i64 %"24_129", i64* %"19", align 4 - br label %cond_exit_12 +cond_17_case_1: ; preds = %6 + %"020" = load i64, i64* %"019", align 4 + store { i32, { i64 }, {} } { i32 1, { i64 } poison, {} undef }, { i32, { i64 }, {} }* %"29_0", align 4 + %"29_021" = load { i32, { i64 }, {} }, { i32, { i64 }, {} }* %"29_0", align 4 + store { i32, { i64 }, {} } %"29_021", { i32, { i64 }, {} }* %"011", align 4 + store i64 %"020", i64* %"27_0", align 4 + br label %cond_exit_17 -cond_exit_12: ; preds = %cond_12_case_1, %cond_12_case_0 - %"010" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"08", align 4 - %"111" = load i64, i64* %"19", align 4 - store { i32, { i64 }, { { {} } } } %"010", { i32, { i64 }, { { {} } } }* %"12_0", align 4 - store i64 %"111", i64* %"12_1", align 4 - %"12_030" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 - %"12_131" = load i64, i64* %"12_1", align 4 - store { i32, { i64 }, { { {} } } } %"12_030", { i32, { i64 }, { { {} } } }* %"12_0", align 4 - store i64 %"12_131", i64* %"12_1", align 4 - %"5_032" = load i64, i64* %"5_0", align 4 - %"8_033" = load i64, i64* %"8_0", align 4 - %17 = icmp ule i64 %"5_032", %"8_033" - %18 = select i1 %17, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } - store { i32, {}, {} } %18, { i32, {}, {} }* %"9_0", align 4 - %"12_034" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 - %"12_135" = load i64, i64* %"12_1", align 4 - %19 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 0 - switch i32 %19, label %20 [ - i32 1, label %23 +cond_exit_17: ; preds = %cond_17_case_1, %cond_17_case_0 + %"012" = load { i32, { i64 }, {} }, { i32, { i64 }, {} }* %"011", align 4 + store { i32, { i64 }, {} } %"012", { i32, { i64 }, {} }* %"17_0", align 4 + %"17_022" = load { i32, { i64 }, {} }, { i32, { i64 }, {} }* %"17_0", align 4 + %"16_023" = load i64, i64* %"16_0", align 4 + store { i32, { i64 }, {} } %"17_022", { i32, { i64 }, {} }* %"17_0", align 4 + store i64 %"16_023", i64* %"16_0", align 4 + %"17_024" = load { i32, { i64 }, {} }, { i32, { i64 }, {} }* %"17_0", align 4 + %"16_025" = load i64, i64* %"16_0", align 4 + %11 = extractvalue { i32, { i64 }, {} } %"17_024", 0 + switch i32 %11, label %12 [ + i32 1, label %15 ] -20: ; preds = %cond_exit_12 - %21 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 1 - %22 = extractvalue { i64 } %21, 0 - store i64 %22, i64* %"5_0", align 4 - store i64 %"12_135", i64* %"5_1", align 4 +12: ; preds = %cond_exit_17 + %13 = extractvalue { i32, { i64 }, {} } %"17_024", 1 + %14 = extractvalue { i64 } %13, 0 + store i64 %14, i64* %"9_0", align 4 + store i64 %"16_025", i64* %"9_1", align 4 br label %loop_body -23: ; preds = %cond_exit_12 - %24 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 2 - %25 = extractvalue { { {} } } %24, 0 - store { {} } %25, { {} }* %"4_0", align 1 - store i64 %"12_135", i64* %"4_1", align 4 +15: ; preds = %cond_exit_17 + %16 = extractvalue { i32, { i64 }, {} } %"17_024", 2 + store i64 %"16_025", i64* %"8_0", align 4 br label %loop_out } diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14_2.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14_2.snap new file mode 100644 index 000000000..4b5b4ccf4 --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop@pre-mem2reg@llvm14_2.snap @@ -0,0 +1,168 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { { {} }, i64 } @_hl.main.1(i64 %0, i64 %1) { +alloca_block: + %"0" = alloca { {} }, align 8 + %"1" = alloca i64, align 8 + %"2_0" = alloca i64, align 8 + %"2_1" = alloca i64, align 8 + %"4_0" = alloca { {} }, align 8 + %"4_1" = alloca i64, align 8 + %"5_0" = alloca i64, align 8 + %"5_1" = alloca i64, align 8 + %"12_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"12_1" = alloca i64, align 8 + %"8_0" = alloca i64, align 8 + %"10_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"08" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"19" = alloca i64, align 8 + %"012" = alloca i64, align 8 + %"113" = alloca i64, align 8 + %"19_0" = alloca i64, align 8 + %"17_0" = alloca i64, align 8 + %"14_0" = alloca i64, align 8 + %"14_1" = alloca i64, align 8 + %"20_0" = alloca i64, align 8 + %"21_0" = alloca i64, align 8 + %"22_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"023" = alloca { {} }, align 8 + %"124" = alloca i64, align 8 + %"27_0" = alloca { {} }, align 8 + %"28_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + %"24_0" = alloca { {} }, align 8 + %"24_1" = alloca i64, align 8 + %"9_0" = alloca { i32, {}, {} }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i64 %0, i64* %"2_0", align 4 + store i64 %1, i64* %"2_1", align 4 + %"2_01" = load i64, i64* %"2_0", align 4 + %"2_12" = load i64, i64* %"2_1", align 4 + store i64 %"2_01", i64* %"5_0", align 4 + store i64 %"2_12", i64* %"5_1", align 4 + br label %loop_body + +loop_body: ; preds = %20, %entry_block + %"5_03" = load i64, i64* %"5_0", align 4 + %"5_14" = load i64, i64* %"5_1", align 4 + store i64 0, i64* %"8_0", align 4 + store i64 %"5_03", i64* %"5_0", align 4 + store i64 %"5_14", i64* %"5_1", align 4 + %"5_05" = load i64, i64* %"5_0", align 4 + %2 = insertvalue { i64 } undef, i64 %"5_05", 0 + %3 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %2, 1 + store { i32, { i64 }, { { {} } } } %3, { i32, { i64 }, { { {} } } }* %"10_0", align 4 + %"10_06" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"10_0", align 4 + %"5_17" = load i64, i64* %"5_1", align 4 + %4 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 0 + switch i32 %4, label %5 [ + i32 1, label %8 + ] + +5: ; preds = %loop_body + %6 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 1 + %7 = extractvalue { i64 } %6, 0 + store i64 %7, i64* %"012", align 4 + store i64 %"5_17", i64* %"113", align 4 + br label %cond_12_case_0 + +8: ; preds = %loop_body + %9 = extractvalue { i32, { i64 }, { { {} } } } %"10_06", 2 + %10 = extractvalue { { {} } } %9, 0 + store { {} } %10, { {} }* %"023", align 1 + store i64 %"5_17", i64* %"124", align 4 + br label %cond_12_case_1 + +loop_out: ; preds = %23 + %"4_036" = load { {} }, { {} }* %"4_0", align 1 + %"4_137" = load i64, i64* %"4_1", align 4 + store { {} } %"4_036", { {} }* %"0", align 1 + store i64 %"4_137", i64* %"1", align 4 + %"038" = load { {} }, { {} }* %"0", align 1 + %"139" = load i64, i64* %"1", align 4 + %mrv = insertvalue { { {} }, i64 } undef, { {} } %"038", 0 + %mrv40 = insertvalue { { {} }, i64 } %mrv, i64 %"139", 1 + ret { { {} }, i64 } %mrv40 + +cond_12_case_0: ; preds = %5 + %"014" = load i64, i64* %"012", align 4 + %"115" = load i64, i64* %"113", align 4 + store i64 2, i64* %"19_0", align 4 + store i64 1, i64* %"17_0", align 4 + store i64 %"014", i64* %"14_0", align 4 + store i64 %"115", i64* %"14_1", align 4 + %"14_116" = load i64, i64* %"14_1", align 4 + %"19_017" = load i64, i64* %"19_0", align 4 + %11 = mul i64 %"14_116", %"19_017" + store i64 %11, i64* %"20_0", align 4 + %"14_018" = load i64, i64* %"14_0", align 4 + %"17_019" = load i64, i64* %"17_0", align 4 + %12 = sub i64 %"14_018", %"17_019" + store i64 %12, i64* %"21_0", align 4 + %"21_020" = load i64, i64* %"21_0", align 4 + %13 = insertvalue { i64 } undef, i64 %"21_020", 0 + %14 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %13, 1 + store { i32, { i64 }, { { {} } } } %14, { i32, { i64 }, { { {} } } }* %"22_0", align 4 + %"22_021" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"22_0", align 4 + %"20_022" = load i64, i64* %"20_0", align 4 + store { i32, { i64 }, { { {} } } } %"22_021", { i32, { i64 }, { { {} } } }* %"08", align 4 + store i64 %"20_022", i64* %"19", align 4 + br label %cond_exit_12 + +cond_12_case_1: ; preds = %8 + %"025" = load { {} }, { {} }* %"023", align 1 + %"126" = load i64, i64* %"124", align 4 + store { {} } undef, { {} }* %"27_0", align 1 + %"27_027" = load { {} }, { {} }* %"27_0", align 1 + %15 = insertvalue { { {} } } undef, { {} } %"27_027", 0 + %16 = insertvalue { i32, { i64 }, { { {} } } } { i32 1, { i64 } poison, { { {} } } poison }, { { {} } } %15, 2 + store { i32, { i64 }, { { {} } } } %16, { i32, { i64 }, { { {} } } }* %"28_0", align 4 + store { {} } %"025", { {} }* %"24_0", align 1 + store i64 %"126", i64* %"24_1", align 4 + %"28_028" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"28_0", align 4 + %"24_129" = load i64, i64* %"24_1", align 4 + store { i32, { i64 }, { { {} } } } %"28_028", { i32, { i64 }, { { {} } } }* %"08", align 4 + store i64 %"24_129", i64* %"19", align 4 + br label %cond_exit_12 + +cond_exit_12: ; preds = %cond_12_case_1, %cond_12_case_0 + %"010" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"08", align 4 + %"111" = load i64, i64* %"19", align 4 + store { i32, { i64 }, { { {} } } } %"010", { i32, { i64 }, { { {} } } }* %"12_0", align 4 + store i64 %"111", i64* %"12_1", align 4 + %"12_030" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 + %"12_131" = load i64, i64* %"12_1", align 4 + store { i32, { i64 }, { { {} } } } %"12_030", { i32, { i64 }, { { {} } } }* %"12_0", align 4 + store i64 %"12_131", i64* %"12_1", align 4 + %"5_032" = load i64, i64* %"5_0", align 4 + %"8_033" = load i64, i64* %"8_0", align 4 + %17 = icmp ule i64 %"5_032", %"8_033" + %18 = select i1 %17, { i32, {}, {} } { i32 1, {} poison, {} undef }, { i32, {}, {} } { i32 0, {} undef, {} poison } + store { i32, {}, {} } %18, { i32, {}, {} }* %"9_0", align 4 + %"12_034" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"12_0", align 4 + %"12_135" = load i64, i64* %"12_1", align 4 + %19 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 0 + switch i32 %19, label %20 [ + i32 1, label %23 + ] + +20: ; preds = %cond_exit_12 + %21 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 1 + %22 = extractvalue { i64 } %21, 0 + store i64 %22, i64* %"5_0", align 4 + store i64 %"12_135", i64* %"5_1", align 4 + br label %loop_body + +23: ; preds = %cond_exit_12 + %24 = extractvalue { i32, { i64 }, { { {} } } } %"12_034", 2 + %25 = extractvalue { { {} } } %24, 0 + store { {} } %25, { {} }* %"4_0", align 1 + store i64 %"12_135", i64* %"4_1", align 4 + br label %loop_out +} diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14_3.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14_3.snap new file mode 100644 index 000000000..7c1a36ea0 --- /dev/null +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__tail_loop_simple@pre-mem2reg@llvm14_3.snap @@ -0,0 +1,55 @@ +--- +source: hugr-llvm/src/emit/test.rs +expression: mod_str +--- +; ModuleID = 'test_context' +source_filename = "test_context" + +define { {} } @_hl.main.1(i64 %0) { +alloca_block: + %"0" = alloca { {} }, align 8 + %"2_0" = alloca i64, align 8 + %"4_0" = alloca { {} }, align 8 + %"5_0" = alloca i64, align 8 + %"7_0" = alloca { i32, { i64 }, { { {} } } }, align 8 + br label %entry_block + +entry_block: ; preds = %alloca_block + store i64 %0, i64* %"2_0", align 4 + %"2_01" = load i64, i64* %"2_0", align 4 + store i64 %"2_01", i64* %"5_0", align 4 + br label %loop_body + +loop_body: ; preds = %4, %entry_block + %"5_02" = load i64, i64* %"5_0", align 4 + store i64 %"5_02", i64* %"5_0", align 4 + %"5_03" = load i64, i64* %"5_0", align 4 + %1 = insertvalue { i64 } undef, i64 %"5_03", 0 + %2 = insertvalue { i32, { i64 }, { { {} } } } { i32 0, { i64 } poison, { { {} } } poison }, { i64 } %1, 1 + store { i32, { i64 }, { { {} } } } %2, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %"7_04" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + store { i32, { i64 }, { { {} } } } %"7_04", { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %"7_05" = load { i32, { i64 }, { { {} } } }, { i32, { i64 }, { { {} } } }* %"7_0", align 4 + %3 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 0 + switch i32 %3, label %4 [ + i32 1, label %7 + ] + +4: ; preds = %loop_body + %5 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 1 + %6 = extractvalue { i64 } %5, 0 + store i64 %6, i64* %"5_0", align 4 + br label %loop_body + +7: ; preds = %loop_body + %8 = extractvalue { i32, { i64 }, { { {} } } } %"7_05", 2 + %9 = extractvalue { { {} } } %8, 0 + store { {} } %9, { {} }* %"4_0", align 1 + br label %loop_out + +loop_out: ; preds = %7 + %"4_06" = load { {} }, { {} }* %"4_0", align 1 + store { {} } %"4_06", { {} }* %"0", align 1 + %"07" = load { {} }, { {} }* %"0", align 1 + ret { {} } %"07" +} diff --git a/hugr-llvm/src/emit/test.rs b/hugr-llvm/src/emit/test.rs index ad418bb84..7c0156e76 100644 --- a/hugr-llvm/src/emit/test.rs +++ b/hugr-llvm/src/emit/test.rs @@ -165,7 +165,7 @@ impl SimpleHugrConfig { // unvalidated. // println!("{}", mod_b.hugr().mermaid_string()); - mod_b.finish_hugr().unwrap() + mod_b.finish_hugr().unwrap_or_else(|e| panic!("{e}")) } } @@ -261,7 +261,7 @@ mod test_fns { use hugr_core::{type_row, Hugr}; use itertools::Itertools; - use rstest::rstest; + use rstest::{fixture, rstest}; use std::iter; use crate::test::*; @@ -551,15 +551,12 @@ mod test_fns { #[rstest] fn tail_loop_simple(mut llvm_ctx: TestContext) { - // Infinite loop let hugr = { let just_input = usize_t(); let just_output = Type::UNIT; let input_v = TypeRow::from(vec![just_input.clone()]); let output_v = TypeRow::from(vec![just_output.clone()]); - llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); - SimpleHugrConfig::new() .with_extensions(PRELUDE_REGISTRY.clone()) .with_ins(input_v) @@ -590,121 +587,155 @@ mod test_fns { builder.finish_with_outputs(outs).unwrap() }) }; + llvm_ctx.add_extensions(CodegenExtsBuilder::add_default_prelude_extensions); + check_emission!(hugr, llvm_ctx); } - #[rstest] - fn tail_loop(mut llvm_ctx: TestContext) { - // Implement the hugr equivalent of the program: - let hugr = { - let int_ty = int_types::int_type(6); - let just_input = int_ty.clone(); - let just_output = Type::UNIT; - let other_ty = int_ty.clone(); - let sum_ty = HugrSumType::new(vec![just_input.clone(), just_output.clone()]); - let input_v = TypeRow::from(vec![just_input.clone(), other_ty.clone()]); - let output_v = TypeRow::from(vec![just_output.clone(), other_ty.clone()]); - - llvm_ctx.add_extensions(add_int_extensions); - - let mut registry = PRELUDE_REGISTRY.clone(); - registry.register(int_ops::EXTENSION.clone()).unwrap(); - registry.register(int_types::EXTENSION.clone()).unwrap(); + #[fixture] + fn terminal_loop(#[default(3)] iters: u64, #[default(7)] input: u64) -> Hugr { + /* + Computes roughly the following: + ```python + def terminal_loop(counter: int, val: int) -> int: + while True: + val = val * 2 + if counter == 0: + break + else: + counter -= 1 + return val + ``` + */ + let int_ty = int_types::int_type(6); + let just_input = int_ty.clone(); + let other_ty = int_ty.clone(); + + let mut registry = PRELUDE_REGISTRY.clone(); + registry.register(int_ops::EXTENSION.clone()).unwrap(); + registry.register(int_types::EXTENSION.clone()).unwrap(); + + SimpleHugrConfig::new() + .with_extensions(registry) + .with_outs(int_ty.clone()) + .finish(|mut builder: DFGW| { + let just_in_w = builder.add_load_value(ConstInt::new_u(6, iters).unwrap()); + let other_w = builder.add_load_value(ConstInt::new_u(6, input).unwrap()); - SimpleHugrConfig::new() - .with_extensions(registry) - .with_ins(input_v) - .with_outs(output_v) - .finish(|mut builder: DFGW| { - let [just_in_w, other_w] = builder.input_wires_arr(); + let tail_l = { let mut tail_b = builder .tail_loop_builder( [(just_input.clone(), just_in_w)], [(other_ty.clone(), other_w)], - vec![just_output.clone()].into(), + type_row![], ) .unwrap(); - let [sum_inp_w, _other_w] = tail_b.input_wires_arr(); + let [loop_int_w, other_w] = tail_b.input_wires_arr(); let zero = ConstInt::new_u(6, 0).unwrap(); let zero_w = tail_b.add_load_value(zero); - let [_result] = tail_b + let [eq_0] = tail_b .add_dataflow_op( - int_ops::IntOpDef::ile_u.with_log_width(6), - [sum_inp_w, zero_w], + int_ops::IntOpDef::ieq.with_log_width(6), + [loop_int_w, zero_w], ) .unwrap() .outputs_arr(); - let input = tail_b.input(); - let [inp_w, other_w] = input.outputs_arr(); let loop_sig = tail_b.loop_signature().unwrap().clone(); - let sum_inp_w = tail_b.make_continue(loop_sig.clone(), [inp_w]).unwrap(); + let two = ConstInt::new_u(6, 2).unwrap(); + let two_w = tail_b.add_load_value(two); + let [other_mul_2] = tail_b + .add_dataflow_op( + int_ops::IntOpDef::imul.with_log_width(6), + [other_w, two_w], + ) + .unwrap() + .outputs_arr(); let cond = { let mut cond_b = tail_b .conditional_builder( - ([just_input.into(), just_output.into()], sum_inp_w), - vec![(other_ty.clone(), other_w)], - vec![sum_ty.into(), other_ty.clone()].into(), + ([type_row![], type_row![]], eq_0), + vec![(just_input.clone(), loop_int_w)], + vec![HugrSumType::new(vec![ + vec![just_input.clone()].into(), + vec![], + ]) + .into()] + .into(), ) .unwrap(); - // If the check is false, we add 1 and continue - let mut false_case_b = cond_b.case_builder(0).unwrap(); - let [counter, val] = false_case_b.input_wires_arr(); - let one = ConstInt::new_u(6, 1).unwrap(); - let one_w = false_case_b.add_load_value(one); - - let two = ConstInt::new_u(6, 2).unwrap(); - let two_w = false_case_b.add_load_value(two); - let [val] = false_case_b - .add_dataflow_op( - int_ops::IntOpDef::imul.with_log_width(6), - [val, two_w], - ) - .unwrap() - .outputs_arr(); + // If the check is false, we subtract 1 and continue + let _false_case = { + let mut false_case_b = cond_b.case_builder(0).unwrap(); + let [counter] = false_case_b.input_wires_arr(); + let one = ConstInt::new_u(6, 1).unwrap(); + let one_w = false_case_b.add_load_value(one); - let [counter] = false_case_b - .add_dataflow_op( - int_ops::IntOpDef::isub.with_log_width(6), - [counter, one_w], - ) - .unwrap() - .outputs_arr(); - let tagged_counter = false_case_b - .make_continue(loop_sig.clone(), [counter]) - .unwrap(); + let [counter] = false_case_b + .add_dataflow_op( + int_ops::IntOpDef::isub.with_log_width(6), + [counter, one_w], + ) + .unwrap() + .outputs_arr(); + let tag_continue = false_case_b + .make_continue(loop_sig.clone(), [counter]) + .unwrap(); - false_case_b - .finish_with_outputs([tagged_counter, val]) - .unwrap(); + false_case_b.finish_with_outputs([tag_continue]).unwrap() + }; + let _true_case = { + // In the true case, we break and output true along with the "other" input wire + let mut true_case_b = cond_b.case_builder(1).unwrap(); - // In the true case, we break and output true along with the "other" input wire - let mut true_case_b = cond_b.case_builder(1).unwrap(); + let [_counter] = true_case_b.input_wires_arr(); - let [_, val_w] = true_case_b.input_wires_arr(); - let unit_v = Value::unit_sum(0, 1).unwrap(); - let unit_w = true_case_b.add_load_value(unit_v); - let tagged_output = - true_case_b.make_break(loop_sig.clone(), [unit_w]).unwrap(); - true_case_b - .finish_with_outputs([tagged_output, val_w]) - .unwrap(); + let tagged_break = + true_case_b.make_break(loop_sig.clone(), []).unwrap(); + true_case_b.finish_with_outputs([tagged_break]).unwrap() + }; cond_b.finish_sub_container().unwrap() }; - let [sum, rest] = cond.outputs_arr(); - let outs @ [_, _] = tail_b - .finish_with_outputs(sum, [rest]) + tail_b + .finish_with_outputs(cond.out_wire(0), [other_mul_2]) .unwrap() - .outputs_arr(); - builder.finish_with_outputs(outs).unwrap() - }) - }; - check_emission!(hugr, llvm_ctx); + }; + let [out_int] = tail_l.outputs_arr(); + println!("{}", builder.hugr().mermaid_string()); + builder + .finish_with_outputs([out_int]) + .unwrap_or_else(|e| panic!("{e}")) + }) + } + + #[rstest] + fn tail_loop(mut llvm_ctx: TestContext, #[with(3, 7)] terminal_loop: Hugr) { + llvm_ctx.add_extensions(add_int_extensions); + println!("{}", terminal_loop.mermaid_string()); + + check_emission!(terminal_loop, llvm_ctx); + } + + #[rstest] + #[case(3, 7)] + #[case(2, 1)] + #[case(20, 0)] + fn tail_loop_exec( + mut exec_ctx: TestContext, + #[case] iters: u64, + #[case] input: u64, + #[with(iters, input)] terminal_loop: Hugr, + ) { + exec_ctx.add_extensions(add_int_extensions); + assert_eq!( + input * 1 << (iters + 1), + exec_ctx.exec_hugr_u64(terminal_loop, "main") + ); } #[rstest] From 2d6ac0c2f8b57b3b576a5be0ce774623229e7e4e Mon Sep 17 00:00:00 2001 From: Seyon Sivarajah Date: Wed, 11 Dec 2024 15:51:35 +0000 Subject: [PATCH 7/7] remove comments and print Co-authored-by: Douglas Wilson <141026920+doug-q@users.noreply.github.com> --- hugr-llvm/src/emit/ops.rs | 2 -- hugr-llvm/src/emit/test.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/hugr-llvm/src/emit/ops.rs b/hugr-llvm/src/emit/ops.rs index d84b62ba6..3989ecd4b 100644 --- a/hugr-llvm/src/emit/ops.rs +++ b/hugr-llvm/src/emit/ops.rs @@ -310,8 +310,6 @@ fn emit_tail_loop<'c, H: HugrView>( context: &mut EmitFuncContext<'c, '_, H>, args: EmitOpArgs<'c, '_, TailLoop, H>, ) -> Result<()> { - // TODO: Switch on the tag in loop_body to see where to go next - // TODO: Handle "other" args let node = args.node(); // Make a block to jump to when we `Break` diff --git a/hugr-llvm/src/emit/test.rs b/hugr-llvm/src/emit/test.rs index 7c0156e76..40e42d70b 100644 --- a/hugr-llvm/src/emit/test.rs +++ b/hugr-llvm/src/emit/test.rs @@ -716,7 +716,6 @@ mod test_fns { #[rstest] fn tail_loop(mut llvm_ctx: TestContext, #[with(3, 7)] terminal_loop: Hugr) { llvm_ctx.add_extensions(add_int_extensions); - println!("{}", terminal_loop.mermaid_string()); check_emission!(terminal_loop, llvm_ctx); }