diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/cretonne/meta/gen_legalizer.py index 10e9641df7..9131b5d19e 100644 --- a/lib/cretonne/meta/gen_legalizer.py +++ b/lib/cretonne/meta/gen_legalizer.py @@ -140,7 +140,7 @@ def emit_dst_inst(node, fmt): # special functions in the `legalizer::split` module. These functions # will eliminate concat-split patterns. fmt.line( - 'let {} = split::{}(dfg, pos, {});' + 'let {} = split::{}(dfg, cfg, pos, {});' .format( wrap_tup(node.defs), node.expr.inst.snake_name(), @@ -220,9 +220,10 @@ def gen_xform_group(xgrp, fmt): fmt.doc_comment("Legalize the instruction pointed to by `pos`.") fmt.line('#[allow(unused_variables,unused_assignments)]') with fmt.indented( - 'fn ' + xgrp.name + - '(pos: &mut Cursor, dfg: &mut DataFlowGraph) -> bool {', - '}'): + 'fn {}(dfg: &mut DataFlowGraph, ' + 'cfg: &mut ControlFlowGraph, pos: &mut Cursor) -> ' + 'bool {{'.format(xgrp.name), '}'): + # Gen the instruction to be legalized. The cursor we're passed must be # pointing at an instruction. fmt.line('let inst = pos.current_inst().expect("need instruction");') diff --git a/lib/cretonne/src/context.rs b/lib/cretonne/src/context.rs index a4fc155c41..9ce9d4912e 100644 --- a/lib/cretonne/src/context.rs +++ b/lib/cretonne/src/context.rs @@ -47,7 +47,7 @@ impl Context { /// Run the legalizer for `isa` on the function. pub fn legalize(&mut self, isa: &TargetIsa) { - legalize_function(&mut self.func, isa); + legalize_function(&mut self.func, &mut self.cfg, isa); } /// Recompute the control flow graph and dominator tree. diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/cretonne/src/legalizer/boundary.rs index a53526232a..893e9097b7 100644 --- a/lib/cretonne/src/legalizer/boundary.rs +++ b/lib/cretonne/src/legalizer/boundary.rs @@ -18,6 +18,7 @@ //! intermediate state doesn't type check. use abi::{legalize_abi_value, ValueConversion}; +use flowgraph::ControlFlowGraph; use ir::{Function, Cursor, DataFlowGraph, Inst, InstBuilder, Ebb, Type, Value, Signature, SigRef, ArgumentType}; use ir::instructions::CallInfo; @@ -257,6 +258,7 @@ fn convert_from_abi(dfg: &mut DataFlowGraph, /// return the `Err(ArgumentType)` that is needed. /// fn convert_to_abi(dfg: &mut DataFlowGraph, + cfg: &ControlFlowGraph, pos: &mut Cursor, value: Value, put_arg: &mut PutArg) @@ -272,28 +274,28 @@ fn convert_to_abi(dfg: &mut DataFlowGraph, let ty = dfg.value_type(value); match legalize_abi_value(ty, &arg_type) { ValueConversion::IntSplit => { - let (lo, hi) = isplit(dfg, pos, value); - convert_to_abi(dfg, pos, lo, put_arg); - convert_to_abi(dfg, pos, hi, put_arg); + let (lo, hi) = isplit(dfg, cfg, pos, value); + convert_to_abi(dfg, cfg, pos, lo, put_arg); + convert_to_abi(dfg, cfg, pos, hi, put_arg); } ValueConversion::VectorSplit => { - let (lo, hi) = vsplit(dfg, pos, value); - convert_to_abi(dfg, pos, lo, put_arg); - convert_to_abi(dfg, pos, hi, put_arg); + let (lo, hi) = vsplit(dfg, cfg, pos, value); + convert_to_abi(dfg, cfg, pos, lo, put_arg); + convert_to_abi(dfg, cfg, pos, hi, put_arg); } ValueConversion::IntBits => { assert!(!ty.is_int()); let abi_ty = Type::int(ty.bits()).expect("Invalid type for conversion"); let arg = dfg.ins(pos).bitcast(abi_ty, value); - convert_to_abi(dfg, pos, arg, put_arg); + convert_to_abi(dfg, cfg, pos, arg, put_arg); } ValueConversion::Sext(abi_ty) => { let arg = dfg.ins(pos).sextend(abi_ty, value); - convert_to_abi(dfg, pos, arg, put_arg); + convert_to_abi(dfg, cfg, pos, arg, put_arg); } ValueConversion::Uext(abi_ty) => { let arg = dfg.ins(pos).uextend(abi_ty, value); - convert_to_abi(dfg, pos, arg, put_arg); + convert_to_abi(dfg, cfg, pos, arg, put_arg); } } } @@ -361,6 +363,7 @@ fn check_return_signature(dfg: &DataFlowGraph, inst: Inst, sig: &Signature) -> b /// argument number in `0..abi_args`. /// fn legalize_inst_arguments(dfg: &mut DataFlowGraph, + cfg: &ControlFlowGraph, pos: &mut Cursor, abi_args: usize, mut get_abi_type: ArgType) @@ -419,7 +422,7 @@ fn legalize_inst_arguments(dfg: &mut DataFlowGraph, Err(abi_type) } }; - convert_to_abi(dfg, pos, old_value, &mut put_arg); + convert_to_abi(dfg, cfg, pos, old_value, &mut put_arg); } // Put the modified value list back. @@ -436,7 +439,7 @@ fn legalize_inst_arguments(dfg: &mut DataFlowGraph, /// original return values. The call's result values will be adapted to match the new signature. /// /// Returns `true` if any instructions were inserted. -pub fn handle_call_abi(dfg: &mut DataFlowGraph, pos: &mut Cursor) -> bool { +pub fn handle_call_abi(dfg: &mut DataFlowGraph, cfg: &ControlFlowGraph, pos: &mut Cursor) -> bool { let mut inst = pos.current_inst().expect("Cursor must point to a call instruction"); // Start by checking if the argument types already match the signature. @@ -448,6 +451,7 @@ pub fn handle_call_abi(dfg: &mut DataFlowGraph, pos: &mut Cursor) -> bool { // OK, we need to fix the call arguments to match the ABI signature. let abi_args = dfg.signatures[sig_ref].argument_types.len(); legalize_inst_arguments(dfg, + cfg, pos, abi_args, |dfg, abi_arg| dfg.signatures[sig_ref].argument_types[abi_arg]); @@ -471,7 +475,11 @@ pub fn handle_call_abi(dfg: &mut DataFlowGraph, pos: &mut Cursor) -> bool { /// Insert ABI conversion code before and after the call instruction at `pos`. /// /// Return `true` if any instructions were inserted. -pub fn handle_return_abi(dfg: &mut DataFlowGraph, pos: &mut Cursor, sig: &Signature) -> bool { +pub fn handle_return_abi(dfg: &mut DataFlowGraph, + cfg: &ControlFlowGraph, + pos: &mut Cursor, + sig: &Signature) + -> bool { let inst = pos.current_inst().expect("Cursor must point to a return instruction"); // Check if the returned types already match the signature. @@ -480,7 +488,11 @@ pub fn handle_return_abi(dfg: &mut DataFlowGraph, pos: &mut Cursor, sig: &Signat } let abi_args = sig.return_types.len(); - legalize_inst_arguments(dfg, pos, abi_args, |_, abi_arg| sig.return_types[abi_arg]); + legalize_inst_arguments(dfg, + cfg, + pos, + abi_args, + |_, abi_arg| sig.return_types[abi_arg]); debug_assert!(check_return_signature(dfg, inst, sig), "Signature still wrong: {}, sig{}", diff --git a/lib/cretonne/src/legalizer/mod.rs b/lib/cretonne/src/legalizer/mod.rs index 56e3e10dd6..deb0bbc6b1 100644 --- a/lib/cretonne/src/legalizer/mod.rs +++ b/lib/cretonne/src/legalizer/mod.rs @@ -13,6 +13,7 @@ //! The legalizer does not deal with register allocation constraints. These constraints are derived //! from the encoding recipes, and solved later by the register allocator. +use flowgraph::ControlFlowGraph; use ir::{Function, Cursor, DataFlowGraph, InstructionData, Opcode, InstBuilder}; use ir::condcodes::IntCC; use isa::{TargetIsa, Legalize}; @@ -25,7 +26,7 @@ mod split; /// - Transform any instructions that don't have a legal representation in `isa`. /// - Fill out `func.encodings`. /// -pub fn legalize_function(func: &mut Function, isa: &TargetIsa) { +pub fn legalize_function(func: &mut Function, cfg: &mut ControlFlowGraph, isa: &TargetIsa) { boundary::legalize_signatures(func, isa); // TODO: This is very simplified and incomplete. @@ -40,14 +41,14 @@ pub fn legalize_function(func: &mut Function, isa: &TargetIsa) { let opcode = func.dfg[inst].opcode(); // Check for ABI boundaries that need to be converted to the legalized signature. - if opcode.is_call() && boundary::handle_call_abi(&mut func.dfg, &mut pos) { + if opcode.is_call() && boundary::handle_call_abi(&mut func.dfg, cfg, &mut pos) { // Go back and legalize the inserted argument conversion instructions. pos.set_position(prev_pos); continue; } if opcode.is_return() && - boundary::handle_return_abi(&mut func.dfg, &mut pos, &func.signature) { + boundary::handle_return_abi(&mut func.dfg, cfg, &mut pos, &func.signature) { // Go back and legalize the inserted return value conversion instructions. pos.set_position(prev_pos); continue; @@ -70,8 +71,8 @@ pub fn legalize_function(func: &mut Function, isa: &TargetIsa) { // 4. TODO: Convert to library calls. For example, floating point operations on // an ISA with no IEEE 754 support. let changed = match action { - Legalize::Expand => expand(&mut pos, &mut func.dfg), - Legalize::Narrow => narrow(&mut pos, &mut func.dfg), + Legalize::Expand => expand(&mut func.dfg, cfg, &mut pos), + Legalize::Narrow => narrow(&mut func.dfg, cfg, &mut pos), }; // If the current instruction was replaced, we need to double back and revisit // the expanded sequence. This is both to assign encodings and possible to diff --git a/lib/cretonne/src/legalizer/split.rs b/lib/cretonne/src/legalizer/split.rs index b8323a59fb..7b36c4997e 100644 --- a/lib/cretonne/src/legalizer/split.rs +++ b/lib/cretonne/src/legalizer/split.rs @@ -64,17 +64,26 @@ //! It is possible to have circular dependencies of EBB arguments that are never used by any real //! instructions. These loops will remain in the program. +use flowgraph::ControlFlowGraph; use ir::{DataFlowGraph, Cursor, Value, Opcode, ValueDef, InstructionData, InstBuilder}; /// Split `value` into two values using the `isplit` semantics. Do this by reusing existing values /// if possible. -pub fn isplit(dfg: &mut DataFlowGraph, pos: &mut Cursor, value: Value) -> (Value, Value) { +pub fn isplit(dfg: &mut DataFlowGraph, + _cfg: &ControlFlowGraph, + pos: &mut Cursor, + value: Value) + -> (Value, Value) { split_value(dfg, pos, value, Opcode::Iconcat) } /// Split `value` into halves using the `vsplit` semantics. Do this by reusing existing values if /// possible. -pub fn vsplit(dfg: &mut DataFlowGraph, pos: &mut Cursor, value: Value) -> (Value, Value) { +pub fn vsplit(dfg: &mut DataFlowGraph, + _cfg: &ControlFlowGraph, + pos: &mut Cursor, + value: Value) + -> (Value, Value) { split_value(dfg, pos, value, Opcode::Vconcat) } diff --git a/src/filetest/legalizer.rs b/src/filetest/legalizer.rs index b7c3345436..25247a5aba 100644 --- a/src/filetest/legalizer.rs +++ b/src/filetest/legalizer.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use cretonne::{legalize_function, write_function}; +use cretonne::flowgraph::ControlFlowGraph; use cretonne::ir::Function; use cton_reader::TestCommand; use filetest::subtest::{SubTest, Context, Result, run_filecheck}; @@ -36,7 +37,8 @@ impl SubTest for TestLegalizer { fn run(&self, func: Cow, context: &Context) -> Result<()> { let mut func = func.into_owned(); let isa = context.isa.expect("legalizer needs an ISA"); - legalize_function(&mut func, isa); + let mut cfg = ControlFlowGraph::with_function(&func); + legalize_function(&mut func, &mut cfg, isa); let mut text = String::new(); write_function(&mut text, &func, Some(isa)).map_err(|e| e.to_string())?; diff --git a/src/filetest/regalloc.rs b/src/filetest/regalloc.rs index 90796c1b85..f64d7bb830 100644 --- a/src/filetest/regalloc.rs +++ b/src/filetest/regalloc.rs @@ -42,10 +42,9 @@ impl SubTest for TestRegalloc { let mut comp_ctx = cretonne::Context::new(); comp_ctx.func = func.into_owned(); + comp_ctx.flowgraph(); // TODO: Should we have an option to skip legalization? comp_ctx.legalize(isa); - - comp_ctx.flowgraph(); comp_ctx.regalloc(isa); let mut text = String::new();