Browse Source

Add a ControlFlowGraph argument to legalize_function.

Legalizing some instructions may require modifications to the control
flow graph, and some operations need to use the CFG analysis.

The CFG reference is threaded through all the legalization functions to
reach the generated expansion functions as well as the legalizer::split
module where it will be used first.
pull/3/head
Jakob Stoklund Olesen 8 years ago
parent
commit
e941a7db5f
  1. 9
      lib/cretonne/meta/gen_legalizer.py
  2. 2
      lib/cretonne/src/context.rs
  3. 38
      lib/cretonne/src/legalizer/boundary.rs
  4. 11
      lib/cretonne/src/legalizer/mod.rs
  5. 13
      lib/cretonne/src/legalizer/split.rs
  6. 4
      src/filetest/legalizer.rs
  7. 3
      src/filetest/regalloc.rs

9
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");')

2
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.

38
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<GetArg>(dfg: &mut DataFlowGraph,
/// return the `Err(ArgumentType)` that is needed.
///
fn convert_to_abi<PutArg>(dfg: &mut DataFlowGraph,
cfg: &ControlFlowGraph,
pos: &mut Cursor,
value: Value,
put_arg: &mut PutArg)
@ -272,28 +274,28 @@ fn convert_to_abi<PutArg>(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<ArgType>(dfg: &mut DataFlowGraph,
cfg: &ControlFlowGraph,
pos: &mut Cursor,
abi_args: usize,
mut get_abi_type: ArgType)
@ -419,7 +422,7 @@ fn legalize_inst_arguments<ArgType>(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<ArgType>(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{}",

11
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

13
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)
}

4
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<Function>, 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())?;

3
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();

Loading…
Cancel
Save