Remove ancient register allocation (#3401)

This commit is contained in:
Benjamin Bouvier
2021-09-30 21:27:23 +02:00
committed by GitHub
parent 80336f4535
commit bae4ec6427
66 changed files with 112 additions and 15380 deletions

View File

@@ -19,179 +19,14 @@ use crate::ir::types::I32;
use crate::ir::{self, InstBuilder, MemFlags};
use crate::isa::TargetIsa;
use crate::timing;
use alloc::collections::BTreeSet;
mod boundary;
mod globalvalue;
mod heap;
mod libcall;
mod split;
mod table;
use self::globalvalue::expand_global_value;
use self::heap::expand_heap_addr;
pub(crate) use self::libcall::expand_as_libcall;
use self::table::expand_table_addr;
enum LegalizeInstResult {
Done,
Legalized,
SplitLegalizePending,
}
/// Legalize `inst` for `isa`.
fn legalize_inst(
inst: ir::Inst,
pos: &mut FuncCursor,
cfg: &mut ControlFlowGraph,
isa: &dyn TargetIsa,
) -> LegalizeInstResult {
let opcode = pos.func.dfg[inst].opcode();
// Check for ABI boundaries that need to be converted to the legalized signature.
if opcode.is_call() {
if boundary::handle_call_abi(isa, inst, pos.func, cfg) {
return LegalizeInstResult::Legalized;
}
} else if opcode.is_return() {
if boundary::handle_return_abi(inst, pos.func, cfg) {
return LegalizeInstResult::Legalized;
}
} else if opcode.is_branch() {
split::simplify_branch_arguments(&mut pos.func.dfg, inst);
} else if opcode == ir::Opcode::Isplit {
pos.use_srcloc(inst);
let arg = match pos.func.dfg[inst] {
ir::InstructionData::Unary { arg, .. } => pos.func.dfg.resolve_aliases(arg),
_ => panic!("Expected isplit: {}", pos.func.dfg.display_inst(inst, None)),
};
match pos.func.dfg.value_def(arg) {
ir::ValueDef::Result(inst, _num) => {
if let ir::InstructionData::Binary {
opcode: ir::Opcode::Iconcat,
..
} = pos.func.dfg[inst]
{
// `arg` was created by an `iconcat` instruction.
} else {
// `arg` was not created by an `iconcat` instruction. Don't try to resolve it,
// as otherwise `split::isplit` will re-insert the original `isplit`, causing
// an endless loop.
return LegalizeInstResult::SplitLegalizePending;
}
}
ir::ValueDef::Param(_block, _num) => {}
}
let res = pos.func.dfg.inst_results(inst).to_vec();
assert_eq!(res.len(), 2);
let (resl, resh) = (res[0], res[1]); // Prevent borrowck error
// Remove old isplit
pos.func.dfg.clear_results(inst);
pos.remove_inst();
let curpos = pos.position();
let srcloc = pos.srcloc();
let (xl, xh) = split::isplit(pos.func, cfg, curpos, srcloc, arg);
pos.func.dfg.change_to_alias(resl, xl);
pos.func.dfg.change_to_alias(resh, xh);
return LegalizeInstResult::Legalized;
}
match pos.func.update_encoding(inst, isa) {
Ok(()) => LegalizeInstResult::Done,
Err(action) => {
// We should transform the instruction into legal equivalents.
// 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.
// There's a risk of infinite looping here if the legalization patterns are
// unsound. Should we attempt to detect that?
if action(inst, pos.func, cfg, isa) {
return LegalizeInstResult::Legalized;
}
// We don't have any pattern expansion for this instruction either.
// Try converting it to a library call as a last resort.
if expand_as_libcall(inst, pos.func, isa) {
LegalizeInstResult::Legalized
} else {
LegalizeInstResult::Done
}
}
}
}
/// Legalize `func` for `isa`.
///
/// - Transform any instructions that don't have a legal representation in `isa`.
/// - Fill out `func.encodings`.
///
pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa) {
let _tt = timing::legalize();
debug_assert!(cfg.is_valid());
boundary::legalize_signatures(func, isa);
func.encodings.resize(func.dfg.num_insts());
let mut pos = FuncCursor::new(func);
let func_begin = pos.position();
// Split block params before trying to legalize instructions, so that the newly introduced
// isplit instructions get legalized.
while let Some(block) = pos.next_block() {
split::split_block_params(pos.func, cfg, block);
}
pos.set_position(func_begin);
// This must be a set to prevent trying to legalize `isplit` and `vsplit` twice in certain cases.
let mut pending_splits = BTreeSet::new();
// Process blocks in layout order. Some legalization actions may split the current block or append
// new ones to the end. We need to make sure we visit those new blocks too.
while let Some(_block) = pos.next_block() {
// Keep track of the cursor position before the instruction being processed, so we can
// double back when replacing instructions.
let mut prev_pos = pos.position();
while let Some(inst) = pos.next_inst() {
match legalize_inst(inst, &mut pos, cfg, isa) {
// Remember this position in case we need to double back.
LegalizeInstResult::Done => prev_pos = pos.position(),
// Go back and legalize the inserted return value conversion instructions.
LegalizeInstResult::Legalized => pos.set_position(prev_pos),
// The argument of a `isplit` or `vsplit` instruction didn't resolve to a
// `iconcat` or `vconcat` instruction. Try again after legalizing the rest of
// the instructions.
LegalizeInstResult::SplitLegalizePending => {
pending_splits.insert(inst);
}
}
}
}
// Try legalizing `isplit` and `vsplit` instructions, which could not previously be legalized.
for inst in pending_splits {
pos.goto_inst(inst);
legalize_inst(inst, &mut pos, cfg, isa);
}
// Now that we've lowered all br_tables, we don't need the jump tables anymore.
if !isa.flags().enable_jump_tables() {
pos.func.jump_tables.clear();
}
}
/// Perform a simple legalization by expansion of the function, without
/// platform-specific transforms.
pub fn simple_legalize(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa) {