[WIP]
This commit is contained in:
@@ -21,6 +21,7 @@ use crate::ir::{self, InstBuilder, MemFlags};
|
|||||||
use crate::isa::TargetIsa;
|
use crate::isa::TargetIsa;
|
||||||
use crate::predicates;
|
use crate::predicates;
|
||||||
use crate::timing;
|
use crate::timing;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
mod boundary;
|
mod boundary;
|
||||||
mod call;
|
mod call;
|
||||||
@@ -36,24 +37,29 @@ use self::heap::expand_heap_addr;
|
|||||||
use self::libcall::expand_as_libcall;
|
use self::libcall::expand_as_libcall;
|
||||||
use self::table::expand_table_addr;
|
use self::table::expand_table_addr;
|
||||||
|
|
||||||
/// Legalize `inst` for `isa`. Return true if any changes to the code were
|
enum LegalizeInstResult {
|
||||||
/// made; return false if the instruction was successfully encoded as is.
|
Done,
|
||||||
|
Legalized,
|
||||||
|
SplitLegalizePending,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Legalize `inst` for `isa`.
|
||||||
fn legalize_inst(
|
fn legalize_inst(
|
||||||
inst: ir::Inst,
|
inst: ir::Inst,
|
||||||
pos: &mut FuncCursor,
|
pos: &mut FuncCursor,
|
||||||
cfg: &mut ControlFlowGraph,
|
cfg: &mut ControlFlowGraph,
|
||||||
isa: &dyn TargetIsa,
|
isa: &dyn TargetIsa,
|
||||||
) -> bool {
|
) -> LegalizeInstResult {
|
||||||
let opcode = pos.func.dfg[inst].opcode();
|
let opcode = pos.func.dfg[inst].opcode();
|
||||||
|
|
||||||
// Check for ABI boundaries that need to be converted to the legalized signature.
|
// Check for ABI boundaries that need to be converted to the legalized signature.
|
||||||
if opcode.is_call() {
|
if opcode.is_call() {
|
||||||
if boundary::handle_call_abi(inst, pos.func, cfg) {
|
if boundary::handle_call_abi(inst, pos.func, cfg) {
|
||||||
return true;
|
return LegalizeInstResult::Legalized;
|
||||||
}
|
}
|
||||||
} else if opcode.is_return() {
|
} else if opcode.is_return() {
|
||||||
if boundary::handle_return_abi(inst, pos.func, cfg) {
|
if boundary::handle_return_abi(inst, pos.func, cfg) {
|
||||||
return true;
|
return LegalizeInstResult::Legalized;
|
||||||
}
|
}
|
||||||
} else if opcode.is_branch() {
|
} else if opcode.is_branch() {
|
||||||
split::simplify_branch_arguments(&mut pos.func.dfg, inst);
|
split::simplify_branch_arguments(&mut pos.func.dfg, inst);
|
||||||
@@ -65,48 +71,48 @@ fn legalize_inst(
|
|||||||
_ => panic!("Expected isplit: {}", pos.func.dfg.display_inst(inst, None)),
|
_ => panic!("Expected isplit: {}", pos.func.dfg.display_inst(inst, None)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let should_replace = match pos.func.dfg.value_def(arg) {
|
match pos.func.dfg.value_def(arg) {
|
||||||
ir::ValueDef::Result(inst, num) => {
|
ir::ValueDef::Result(inst, num) => {
|
||||||
if let ir::InstructionData::Binary { opcode, args, .. } = pos.func.dfg[inst] {
|
if let ir::InstructionData::Binary { opcode, args, .. } = pos.func.dfg[inst] {
|
||||||
opcode == ir::Opcode::Iconcat
|
if opcode != ir::Opcode::Iconcat {
|
||||||
|
return LegalizeInstResult::SplitLegalizePending;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// `arg` was not created by an `iconcat` instruction. Don't try to resolve it,
|
// `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
|
// as otherwise `split::isplit` will re-insert the original `isplit`, causing
|
||||||
// an endless loop.
|
// an endless loop.
|
||||||
false
|
return LegalizeInstResult::SplitLegalizePending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir::ValueDef::Param(ebb, num) => true,
|
ir::ValueDef::Param(ebb, num) => {},
|
||||||
};
|
|
||||||
|
|
||||||
if should_replace {
|
|
||||||
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
|
|
||||||
|
|
||||||
dbg!(pos.position());
|
|
||||||
|
|
||||||
// Remove old isplit
|
|
||||||
pos.func.dfg.clear_results(inst);
|
|
||||||
pos.remove_inst();
|
|
||||||
|
|
||||||
dbg!(pos.position());
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
dbg!(&pos.func);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
dbg!(pos.position());
|
||||||
|
|
||||||
|
// Remove old isplit
|
||||||
|
pos.func.dfg.clear_results(inst);
|
||||||
|
pos.remove_inst();
|
||||||
|
|
||||||
|
dbg!(pos.position());
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
dbg!(&pos.func);
|
||||||
|
|
||||||
|
return LegalizeInstResult::Legalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
match pos.func.update_encoding(inst, isa) {
|
match pos.func.update_encoding(inst, isa) {
|
||||||
Ok(()) => false,
|
Ok(()) => LegalizeInstResult::Done,
|
||||||
Err(action) => {
|
Err(action) => {
|
||||||
// We should transform the instruction into legal equivalents.
|
// We should transform the instruction into legal equivalents.
|
||||||
// If the current instruction was replaced, we need to double back and revisit
|
// If the current instruction was replaced, we need to double back and revisit
|
||||||
@@ -115,12 +121,16 @@ fn legalize_inst(
|
|||||||
// There's a risk of infinite looping here if the legalization patterns are
|
// There's a risk of infinite looping here if the legalization patterns are
|
||||||
// unsound. Should we attempt to detect that?
|
// unsound. Should we attempt to detect that?
|
||||||
if action(inst, pos.func, cfg, isa) {
|
if action(inst, pos.func, cfg, isa) {
|
||||||
return true;
|
return LegalizeInstResult::Legalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have any pattern expansion for this instruction either.
|
// We don't have any pattern expansion for this instruction either.
|
||||||
// Try converting it to a library call as a last resort.
|
// Try converting it to a library call as a last resort.
|
||||||
expand_as_libcall(inst, pos.func, isa)
|
if expand_as_libcall(inst, pos.func, isa) {
|
||||||
|
LegalizeInstResult::Legalized
|
||||||
|
} else {
|
||||||
|
LegalizeInstResult::Done
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,6 +149,7 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is
|
|||||||
func.encodings.resize(func.dfg.num_insts());
|
func.encodings.resize(func.dfg.num_insts());
|
||||||
|
|
||||||
let mut pos = FuncCursor::new(func);
|
let mut pos = FuncCursor::new(func);
|
||||||
|
let mut pending_splits = Vec::new();
|
||||||
|
|
||||||
// Process EBBs in layout order. Some legalization actions may split the current EBB or append
|
// Process EBBs in layout order. Some legalization actions may split the current EBB or append
|
||||||
// new ones to the end. We need to make sure we visit those new EBBs too.
|
// new ones to the end. We need to make sure we visit those new EBBs too.
|
||||||
@@ -148,16 +159,27 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is
|
|||||||
let mut prev_pos = pos.position();
|
let mut prev_pos = pos.position();
|
||||||
|
|
||||||
while let Some(inst) = pos.next_inst() {
|
while let Some(inst) = pos.next_inst() {
|
||||||
if legalize_inst(inst, &mut pos, cfg, isa) {
|
match legalize_inst(inst, &mut pos, cfg, isa) {
|
||||||
// Go back and legalize the inserted return value conversion instructions.
|
|
||||||
pos.set_position(prev_pos);
|
|
||||||
} else {
|
|
||||||
// Remember this position in case we need to double back.
|
// Remember this position in case we need to double back.
|
||||||
prev_pos = pos.position();
|
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.push(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.
|
// Now that we've lowered all br_tables, we don't need the jump tables anymore.
|
||||||
if !isa.flags().jump_tables_enabled() {
|
if !isa.flags().jump_tables_enabled() {
|
||||||
pos.func.jump_tables.clear();
|
pos.func.jump_tables.clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user