When splitting a const, insert prior to the terminal branch group. (#1325)
* When splitting a const, insert prior to the terminal branch group. Closes #1159 Given code like the following, on x86_64, which does not have i128 registers: ebb0(v0: i64): v1 = iconst.i128 0 v2 = icmp_imm eq v0, 1 brnz v2, ebb1 jump ebb2(v1) It would be split to: ebb0(v0: i64): v1 = iconst.i128 0 v2 = icmp_imm eq v0, 1 brnz v2, ebb1 v3, v4 = isplit.i128 v1 jump ebb2(v3, v4) But that fails basic-block invariants. This patch changes that to: ebb0(v0: i64): v1 = iconst.i128 0 v2 = icmp_imm eq v0, 1 v3, v4 = isplit.i128 v1 brnz v2, ebb1 jump ebb2(v3, v4) * Add isplit-bb.clif testcase
This commit is contained in:
committed by
Benjamin Bouvier
parent
d6134a6f3a
commit
b4c6bfd371
@@ -4,6 +4,7 @@
|
|||||||
//! determined by the `Layout` data structure defined in this module.
|
//! determined by the `Layout` data structure defined in this module.
|
||||||
|
|
||||||
use crate::entity::SecondaryMap;
|
use crate::entity::SecondaryMap;
|
||||||
|
use crate::ir::dfg::DataFlowGraph;
|
||||||
use crate::ir::progpoint::{ExpandedProgramPoint, ProgramOrder};
|
use crate::ir::progpoint::{ExpandedProgramPoint, ProgramOrder};
|
||||||
use crate::ir::{Ebb, Inst};
|
use crate::ir::{Ebb, Inst};
|
||||||
use crate::packed_option::PackedOption;
|
use crate::packed_option::PackedOption;
|
||||||
@@ -573,6 +574,19 @@ impl Layout {
|
|||||||
self.insts[inst].prev.expand()
|
self.insts[inst].prev.expand()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch the first instruction in an ebb's terminal branch group.
|
||||||
|
pub fn canonical_branch_inst(&self, dfg: &DataFlowGraph, ebb: Ebb) -> Option<Inst> {
|
||||||
|
// Basic blocks permit at most two terminal branch instructions.
|
||||||
|
// If two, the former is conditional and the latter is unconditional.
|
||||||
|
let last = self.last_inst(ebb)?;
|
||||||
|
if let Some(prev) = self.prev_inst(last) {
|
||||||
|
if dfg[prev].opcode().is_branch() {
|
||||||
|
return Some(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(last)
|
||||||
|
}
|
||||||
|
|
||||||
/// Insert `inst` before the instruction `before` in the same EBB.
|
/// Insert `inst` before the instruction `before` in the same EBB.
|
||||||
pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
|
pub fn insert_inst(&mut self, inst: Inst, before: Inst) {
|
||||||
debug_assert_eq!(self.inst_ebb(inst), None);
|
debug_assert_eq!(self.inst_ebb(inst), None);
|
||||||
|
|||||||
@@ -189,6 +189,17 @@ fn perform_repairs(pos: &mut FuncCursor, cfg: &ControlFlowGraph, mut repairs: Ve
|
|||||||
|
|
||||||
// Split the old argument, possibly causing more repairs to be scheduled.
|
// Split the old argument, possibly causing more repairs to be scheduled.
|
||||||
pos.goto_inst(inst);
|
pos.goto_inst(inst);
|
||||||
|
#[cfg(feature = "basic-blocks")]
|
||||||
|
{
|
||||||
|
let inst_ebb = pos.func.layout.inst_ebb(inst).expect("inst in ebb");
|
||||||
|
|
||||||
|
// Insert split values prior to the terminal branch group.
|
||||||
|
let dfg = &pos.func.dfg;
|
||||||
|
let canonical = pos.func.layout.canonical_branch_inst(dfg, inst_ebb);
|
||||||
|
if let Some(first_branch) = canonical {
|
||||||
|
pos.goto_inst(first_branch);
|
||||||
|
}
|
||||||
|
}
|
||||||
let (lo, hi) = split_value(pos, old_arg, repair.concat, &mut repairs);
|
let (lo, hi) = split_value(pos, old_arg, repair.concat, &mut repairs);
|
||||||
|
|
||||||
// The `lo` part replaces the original argument.
|
// The `lo` part replaces the original argument.
|
||||||
@@ -248,8 +259,8 @@ fn split_value(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ValueDef::Param(ebb, num) => {
|
ValueDef::Param(ebb, num) => {
|
||||||
// This is an EBB parameter. We can split the parameter value unless this is the entry
|
// This is an EBB parameter.
|
||||||
// block.
|
// We can split the parameter value unless this is the entry block.
|
||||||
if pos.func.layout.entry_block() != Some(ebb) {
|
if pos.func.layout.entry_block() != Some(ebb) {
|
||||||
reuse = Some(split_ebb_param(pos, ebb, num, value, concat, repairs));
|
reuse = Some(split_ebb_param(pos, ebb, num, value, concat, repairs));
|
||||||
}
|
}
|
||||||
|
|||||||
28
cranelift/filetests/filetests/verifier/isplit-bb.clif
Normal file
28
cranelift/filetests/filetests/verifier/isplit-bb.clif
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
test compile
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
function u0:0(i128, i128, i64) -> i128 system_v {
|
||||||
|
ebb0(v0: i128, v1: i128, v2: i64):
|
||||||
|
trap user0
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
v10 = iconst.i64 0
|
||||||
|
v11 = iconst.i64 0
|
||||||
|
v17 = iconcat v10, v11
|
||||||
|
v12 = iconst.i64 0
|
||||||
|
v13 = iconst.i64 0
|
||||||
|
v20 = iconcat v12, v13
|
||||||
|
trap user0
|
||||||
|
|
||||||
|
ebb79:
|
||||||
|
v425 = iconst.i64 0
|
||||||
|
v426 = icmp_imm eq v425, 1
|
||||||
|
brnz v426, ebb80
|
||||||
|
jump ebb85(v20, v17)
|
||||||
|
|
||||||
|
ebb80:
|
||||||
|
trap user0
|
||||||
|
|
||||||
|
ebb85(v462: i128, v874: i128):
|
||||||
|
trap user0
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user