diff --git a/cranelift/filetests/isa/riscv/legalize-abi.cton b/cranelift/filetests/isa/riscv/legalize-abi.cton index 926a3c2820..06fcfd5f6c 100644 --- a/cranelift/filetests/isa/riscv/legalize-abi.cton +++ b/cranelift/filetests/isa/riscv/legalize-abi.cton @@ -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) diff --git a/cranelift/filetests/isa/riscv/split-args.cton b/cranelift/filetests/isa/riscv/split-args.cton index 1cecb85c10..8c69378f42 100644 --- a/cranelift/filetests/isa/riscv/split-args.cton +++ b/cranelift/filetests/isa/riscv/split-args.cton @@ -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) +} diff --git a/lib/cretonne/src/legalizer/mod.rs b/lib/cretonne/src/legalizer/mod.rs index deb0bbc6b1..b9dc493527 100644 --- a/lib/cretonne/src/legalizer/mod.rs +++ b/lib/cretonne/src/legalizer/mod.rs @@ -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) => { diff --git a/lib/cretonne/src/legalizer/split.rs b/lib/cretonne/src/legalizer/split.rs index d58c7ed285..43a2c4d385 100644 --- a/lib/cretonne/src/legalizer/split.rs +++ b/lib/cretonne/src/legalizer/split.rs @@ -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); +}