Simplify branch arguments after splitting EBB arguments.
The EBB argument splitting may generate concat-split dependencies when it repairs branch arguments in EBBs that have not yet been fully legalized. Add a branch argument simplification step that can resolve these dependency chains. This means that all split and concatenation instructions will be dead after legalization for types that have no legal instructions using them.
This commit is contained in:
@@ -36,7 +36,8 @@ ebb0:
|
||||
; check: $(v1new=$V) = iconcat $v1l, $v1h
|
||||
; check: $v1 = copy $v1new
|
||||
jump ebb1(v1)
|
||||
; check: jump $ebb1($v1)
|
||||
; The v1 copy gets resolved by split::simplify_branch_arguments().
|
||||
; check: jump $ebb1($v1new)
|
||||
|
||||
ebb1(v10: i64):
|
||||
jump ebb1(v10)
|
||||
@@ -50,9 +51,9 @@ ebb0:
|
||||
; check: $ebb0:
|
||||
; nextln: $v1, $(v2l=$V), $(v2h=$V) = call $fn1()
|
||||
; check: $(v2new=$V) = iconcat $v2l, $v2h
|
||||
; check: $v2 -> $v2new
|
||||
jump ebb1(v1, v2)
|
||||
; check: jump $ebb1($v1, $v2)
|
||||
; The v2 -> v2new alias is resolved by split::simplify_branch_arguments().
|
||||
; check: jump $ebb1($v1, $v2new)
|
||||
|
||||
ebb1(v9: i32, v10: i64):
|
||||
jump ebb1(v9, v10)
|
||||
@@ -78,7 +79,8 @@ ebb0:
|
||||
; check: $(v1new=$V) = ireduce.i8 $rv
|
||||
; check: $v1 = copy $v1new
|
||||
jump ebb1(v1)
|
||||
; check: jump $ebb1($v1)
|
||||
; The v1 copy gets resolved by split::simplify_branch_arguments().
|
||||
; check: jump $ebb1($v1new)
|
||||
|
||||
ebb1(v10: i8):
|
||||
jump ebb1(v10)
|
||||
|
||||
@@ -38,3 +38,18 @@ ebb3(v4: i64):
|
||||
return v5
|
||||
; check: return $v5l, $v5h
|
||||
}
|
||||
|
||||
function loop(i64, i64) -> i64 {
|
||||
ebb0(v1: i64, v2: i64):
|
||||
; check: $ebb0($(v1l=$V): i32, $(v1h=$V): i32, $(v2l=$V): i32, $(v2h=$V): i32):
|
||||
jump ebb1(v1)
|
||||
; check: jump $ebb1($v1l, $v1h)
|
||||
|
||||
ebb1(v3: i64):
|
||||
; check: $ebb1($(v3l=$V): i32, $(v3h=$V): i32):
|
||||
v4 = band v3, v2
|
||||
; check: $(v4l=$V) = band $v3l, $v2l
|
||||
; check: $(v4h=$V) = band $v3h, $v2h
|
||||
jump ebb1(v4)
|
||||
; check: jump $ebb1($v4l, $v4h)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ pub fn legalize_function(func: &mut Function, cfg: &mut ControlFlowGraph, isa: &
|
||||
continue;
|
||||
}
|
||||
|
||||
if opcode.is_branch() {
|
||||
split::simplify_branch_arguments(&mut func.dfg, inst);
|
||||
}
|
||||
|
||||
match isa.encode(&func.dfg, &func.dfg[inst]) {
|
||||
Ok(encoding) => *func.encodings.ensure(inst) = encoding,
|
||||
Err(action) => {
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
//! instructions. These loops will remain in the program.
|
||||
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::{DataFlowGraph, Ebb, Cursor, Value, Type, Opcode, ValueDef, InstructionData, InstBuilder};
|
||||
use ir::{DataFlowGraph, Ebb, Inst, Cursor, Value, Type, Opcode, ValueDef, InstructionData,
|
||||
InstBuilder};
|
||||
use std::iter;
|
||||
|
||||
/// Split `value` into two values using the `isplit` semantics. Do this by reusing existing values
|
||||
@@ -263,3 +264,62 @@ fn add_repair(concat: Opcode,
|
||||
hi_num: hi_num,
|
||||
});
|
||||
}
|
||||
|
||||
/// Strip concat-split chains. Return a simpler way of computing the same value.
|
||||
///
|
||||
/// Given this input:
|
||||
///
|
||||
/// ```cton
|
||||
/// v10 = iconcat v1, v2
|
||||
/// v11, v12 = isplit v10
|
||||
/// ```
|
||||
///
|
||||
/// This function resolves `v11` to `v1` and `v12` to `v2`.
|
||||
fn resolve_splits(dfg: &DataFlowGraph, value: Value) -> Value {
|
||||
let value = dfg.resolve_copies(value);
|
||||
|
||||
// Deconstruct a split instruction.
|
||||
let split_res;
|
||||
let concat_opc;
|
||||
let split_arg;
|
||||
if let ValueDef::Res(inst, num) = dfg.value_def(value) {
|
||||
split_res = num;
|
||||
concat_opc = match dfg[inst].opcode() {
|
||||
Opcode::Isplit => Opcode::Iconcat,
|
||||
Opcode::Vsplit => Opcode::Vconcat,
|
||||
_ => return value,
|
||||
};
|
||||
split_arg = dfg[inst].arguments(&dfg.value_lists)[0];
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
||||
// See if split_arg is defined by a concatenation instruction.
|
||||
if let ValueDef::Res(inst, _) = dfg.value_def(split_arg) {
|
||||
if dfg[inst].opcode() == concat_opc {
|
||||
return dfg[inst].arguments(&dfg.value_lists)[split_res];
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
/// Simplify the arguments to a branch *after* the instructions leading up to the branch have been
|
||||
/// legalized.
|
||||
///
|
||||
/// The branch argument repairs performed by `split_any()` above may be performed on branches that
|
||||
/// have not yet been legalized. The repaired arguments can be defined by actual split
|
||||
/// instructions in that case.
|
||||
///
|
||||
/// After legalizing the instructions computing the value that was split, it is likely that we can
|
||||
/// avoid depending on the split instruction. Its input probably comes from a concatenation.
|
||||
pub fn simplify_branch_arguments(dfg: &mut DataFlowGraph, branch: Inst) {
|
||||
let mut new_args = Vec::new();
|
||||
|
||||
for &arg in dfg[branch].arguments(&dfg.value_lists) {
|
||||
let new_arg = resolve_splits(dfg, arg);
|
||||
new_args.push(new_arg);
|
||||
}
|
||||
|
||||
dfg.insts[branch].arguments_mut(&mut dfg.value_lists).copy_from_slice(&new_args);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user