Switch to a FuncCursor in the top-level legalizer loop.

Stop passing Cursor references to legalizer functions. Give them the
whole &mut Function instead. Given the whole Function reference, these
functions can create their own cursors.

This lets legalizer actions access other Function data structures like
the global variables.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-17 15:45:21 -07:00
parent 5566c99dba
commit 4b94ea21ed
4 changed files with 43 additions and 54 deletions

View File

@@ -353,16 +353,12 @@ def gen_xform_group(xgrp, fmt, type_sets):
fmt.doc_comment("Legalize the instruction pointed to by `pos`.")
fmt.line('#[allow(unused_variables,unused_assignments)]')
with fmt.indented(
'pub fn {}(dfg: &mut ir::DataFlowGraph, '
'cfg: &mut ::flowgraph::ControlFlowGraph, '
'pos: &mut ir::Cursor) -> '
'pub fn {}(inst: ir::Inst, '
'func: &mut ir::Function, '
'cfg: &mut ::flowgraph::ControlFlowGraph) -> '
'bool {{'.format(xgrp.name), '}'):
fmt.line('use ir::{InstBuilder, CursorBase};')
# 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");')
# Group the xforms by opcode so we can generate a big switch.
# Preserve ordering.
xforms = defaultdict(list) # type: DefaultDict[str, List[XForm]]
@@ -370,18 +366,23 @@ def gen_xform_group(xgrp, fmt, type_sets):
inst = xform.src.rtl[0].expr.inst
xforms[inst.camel_name].append(xform)
with fmt.indented('match dfg[inst].opcode() {', '}'):
for camel_name in sorted(xforms.keys()):
with fmt.indented(
'ir::Opcode::{} => {{'.format(camel_name), '}'):
for xform in xforms[camel_name]:
gen_xform(xform, fmt, type_sets)
# We'll assume there are uncovered opcodes.
fmt.line('_ => {},')
with fmt.indented('{', '}'):
fmt.line(
'let pos = &mut ir::Cursor::new(&mut func.layout)'
'.at_inst(inst);')
fmt.line('let dfg = &mut func.dfg;')
with fmt.indented('match dfg[inst].opcode() {', '}'):
for camel_name in sorted(xforms.keys()):
with fmt.indented(
'ir::Opcode::{} => {{'.format(camel_name), '}'):
for xform in xforms[camel_name]:
gen_xform(xform, fmt, type_sets)
# We'll assume there are uncovered opcodes.
fmt.line('_ => {},')
# If we fall through, nothing was expanded. Call the chain if any.
if xgrp.chain:
fmt.format('{}(dfg, cfg, pos)', xgrp.chain.rust_name())
fmt.format('{}(inst, func, cfg)', xgrp.chain.rust_name())
else:
fmt.line('false')

View File

@@ -138,9 +138,9 @@ impl settings::Configurable for Builder {
/// legalize it?
///
/// The `Encodings` iterator returns a legalization function to call.
pub type Legalize = fn(&mut ir::DataFlowGraph,
&mut flowgraph::ControlFlowGraph,
&mut ir::Cursor)
pub type Legalize = fn(ir::Inst,
&mut ir::Function,
&mut flowgraph::ControlFlowGraph)
-> bool;
/// Methods that are specialized to a target ISA.

View File

@@ -452,18 +452,13 @@ 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,
locations: &mut ValueLocations,
stack_slots: &mut StackSlots,
cfg: &ControlFlowGraph,
pos: &mut Cursor)
-> bool {
let mut inst = pos.current_inst()
.expect("Cursor must point to a call instruction");
pub fn handle_call_abi(mut inst: Inst, func: &mut Function, cfg: &ControlFlowGraph) -> bool {
let dfg = &mut func.dfg;
let pos = &mut Cursor::new(&mut func.layout).at_inst(inst);
// Start by checking if the argument types already match the signature.
let sig_ref = match check_call_signature(dfg, inst) {
Ok(_) => return spill_call_arguments(dfg, locations, stack_slots, pos),
Ok(_) => return spill_call_arguments(dfg, &mut func.locations, &mut func.stack_slots, pos),
Err(s) => s,
};
@@ -489,22 +484,19 @@ pub fn handle_call_abi(dfg: &mut DataFlowGraph,
// Go back and insert spills for any stack arguments.
pos.goto_inst(inst);
spill_call_arguments(dfg, locations, stack_slots, pos);
spill_call_arguments(dfg, &mut func.locations, &mut func.stack_slots, pos);
// Yes, we changed stuff.
true
}
/// Insert ABI conversion code before and after the return instruction at `pos`.
/// Insert ABI conversion code before and after the return instruction at `inst`.
///
/// Return `true` if any instructions were inserted.
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");
pub fn handle_return_abi(inst: Inst, func: &mut Function, cfg: &ControlFlowGraph) -> bool {
let dfg = &mut func.dfg;
let sig = &mut func.signature;
let pos = &mut Cursor::new(&mut func.layout).at_inst(inst);
// Check if the returned types already match the signature.
if check_return_signature(dfg, inst, sig) {

View File

@@ -13,9 +13,10 @@
//! 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 cursor::{Cursor, FuncCursor};
use dominator_tree::DominatorTree;
use flowgraph::ControlFlowGraph;
use ir::{self, Function, Cursor, CursorBase};
use ir;
use ir::condcodes::IntCC;
use isa::TargetIsa;
use bitset::BitSet;
@@ -28,7 +29,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,
pub fn legalize_function(func: &mut ir::Function,
cfg: &mut ControlFlowGraph,
domtree: &DominatorTree,
isa: &TargetIsa) {
@@ -36,7 +37,7 @@ pub fn legalize_function(func: &mut Function,
func.encodings.resize(func.dfg.num_insts());
let mut pos = Cursor::new(&mut func.layout);
let mut pos = FuncCursor::new(func);
// Process EBBs in a reverse post-order. This minimizes the number of split instructions we
// need.
@@ -48,36 +49,32 @@ pub fn legalize_function(func: &mut Function,
let mut prev_pos = pos.position();
while let Some(inst) = pos.next_inst() {
let opcode = func.dfg[inst].opcode();
let opcode = pos.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 func.locations,
&mut func.stack_slots,
cfg,
&mut pos) {
if opcode.is_call() && boundary::handle_call_abi(inst, pos.func, cfg) {
// 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, cfg, &mut pos, &func.signature) {
if opcode.is_return() && boundary::handle_return_abi(inst, pos.func, cfg) {
// Go back and legalize the inserted return value conversion instructions.
pos.set_position(prev_pos);
continue;
}
if opcode.is_branch() {
split::simplify_branch_arguments(&mut func.dfg, inst);
split::simplify_branch_arguments(&mut pos.func.dfg, inst);
}
match isa.encode(&func.dfg, &func.dfg[inst], func.dfg.ctrl_typevar(inst)) {
Ok(encoding) => *func.encodings.ensure(inst) = encoding,
match isa.encode(&pos.func.dfg,
&pos.func.dfg[inst],
pos.func.dfg.ctrl_typevar(inst)) {
Ok(encoding) => *pos.func.encodings.ensure(inst) = encoding,
Err(action) => {
// We should transform the instruction into legal equivalents.
let changed = action(&mut func.dfg, cfg, &mut pos);
let changed = action(inst, pos.func, cfg);
// 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
// expand further.
@@ -94,7 +91,6 @@ pub fn legalize_function(func: &mut Function,
prev_pos = pos.position();
}
}
func.encodings.resize(func.dfg.num_insts());
}
// Include legalization patterns that were generated by `gen_legalizer.py` from the `XForms` in