Insert split-edge of conditional branches before the destination.
This commit is contained in:
committed by
Nicolas B. Pierron
parent
093b3b3426
commit
e0005f1e6c
@@ -22,7 +22,6 @@ pub fn run(
|
|||||||
) {
|
) {
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
has_new_blocks: false,
|
has_new_blocks: false,
|
||||||
has_fallthrough_return: None,
|
|
||||||
cur: EncCursor::new(func, isa),
|
cur: EncCursor::new(func, isa),
|
||||||
domtree,
|
domtree,
|
||||||
topo,
|
topo,
|
||||||
@@ -35,12 +34,6 @@ struct Context<'a> {
|
|||||||
/// True if new blocks were inserted.
|
/// True if new blocks were inserted.
|
||||||
has_new_blocks: bool,
|
has_new_blocks: bool,
|
||||||
|
|
||||||
/// Record whether newly inserted empty blocks should be inserted last, or before the last, to
|
|
||||||
/// avoid disturbing the expected control flow of `fallthroug_return` statements.
|
|
||||||
///
|
|
||||||
/// This value is computed when needed. The Option wraps the computed value if any.
|
|
||||||
has_fallthrough_return: Option<bool>,
|
|
||||||
|
|
||||||
/// Current instruction as well as reference to function and ISA.
|
/// Current instruction as well as reference to function and ISA.
|
||||||
cur: EncCursor<'a>,
|
cur: EncCursor<'a>,
|
||||||
|
|
||||||
@@ -89,7 +82,13 @@ impl<'a> Context<'a> {
|
|||||||
// If there are any parameters, split the edge.
|
// If there are any parameters, split the edge.
|
||||||
if self.should_split_edge(target) {
|
if self.should_split_edge(target) {
|
||||||
// Create the block the branch will jump to.
|
// Create the block the branch will jump to.
|
||||||
let new_ebb = self.make_empty_ebb();
|
let new_ebb = self.cur.func.dfg.make_ebb();
|
||||||
|
|
||||||
|
// Insert the new block before the destination, such that it can fallthrough in the
|
||||||
|
// target block.
|
||||||
|
assert_ne!(Some(target), self.cur.layout().entry_block());
|
||||||
|
self.cur.layout_mut().insert_ebb(new_ebb, target);
|
||||||
|
self.has_new_blocks = true;
|
||||||
|
|
||||||
// Extract the arguments of the branch instruction, split the Ebb parameters and the
|
// Extract the arguments of the branch instruction, split the Ebb parameters and the
|
||||||
// branch arguments
|
// branch arguments
|
||||||
@@ -157,28 +156,6 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A new ebb must be inserted before the last ebb because the last ebb may have a
|
|
||||||
// fallthrough_return and can't have anything after it.
|
|
||||||
fn make_empty_ebb(&mut self) -> Ebb {
|
|
||||||
let last_ebb = self.cur.layout().last_ebb().unwrap();
|
|
||||||
if self.has_fallthrough_return == None {
|
|
||||||
let last_inst = self.cur.layout().last_inst(last_ebb).unwrap();
|
|
||||||
self.has_fallthrough_return =
|
|
||||||
Some(self.cur.func.dfg[last_inst].opcode() == Opcode::FallthroughReturn);
|
|
||||||
}
|
|
||||||
let new_ebb = self.cur.func.dfg.make_ebb();
|
|
||||||
if self.has_fallthrough_return == Some(true) {
|
|
||||||
// Insert before the last block which has a fallthrough_return
|
|
||||||
// instruction.
|
|
||||||
self.cur.layout_mut().insert_ebb(new_ebb, last_ebb);
|
|
||||||
} else {
|
|
||||||
// Insert after the last block.
|
|
||||||
self.cur.layout_mut().insert_ebb_after(new_ebb, last_ebb);
|
|
||||||
}
|
|
||||||
self.has_new_blocks = true;
|
|
||||||
new_ebb
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether we should introduce a new branch.
|
/// Returns whether we should introduce a new branch.
|
||||||
fn should_split_edge(&self, target: Ebb) -> bool {
|
fn should_split_edge(&self, target: Ebb) -> bool {
|
||||||
// We should split the edge if the target has any parameters.
|
// We should split the edge if the target has any parameters.
|
||||||
|
|||||||
@@ -103,21 +103,21 @@ ebb0(v0: i32):
|
|||||||
v2 = iconst.i32 2
|
v2 = iconst.i32 2
|
||||||
jump ebb1(v1, v2)
|
jump ebb1(v1, v2)
|
||||||
|
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; check: $(nv11b=$V) = copy.i32 v11
|
||||||
|
; not: copy
|
||||||
|
; check: jump ebb1($nv11b, v12)
|
||||||
|
|
||||||
ebb1(v10: i32, v11: i32):
|
ebb1(v10: i32, v11: i32):
|
||||||
; v11 needs to be isolated because it interferes with v10.
|
; v11 needs to be isolated because it interferes with v10.
|
||||||
; check: ebb1(v10: i32 [$LOC], $(nv11a=$V): i32 [$LOC])
|
; check: ebb1(v10: i32 [$LOC], $(nv11a=$V): i32 [$LOC])
|
||||||
; check: v11 = copy $nv11a
|
; check: v11 = copy $nv11a
|
||||||
v12 = iadd v10, v11
|
v12 = iadd v10, v11
|
||||||
v13 = icmp ult v12, v0
|
v13 = icmp ult v12, v0
|
||||||
; check: brnz v13, $(splitEdge=$EBB)
|
; check: brnz v13, $splitEdge
|
||||||
brnz v13, ebb1(v11, v12)
|
brnz v13, ebb1(v11, v12)
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; check: $(nv11b=$V) = copy.i32 v11
|
|
||||||
; not: copy
|
|
||||||
; check: jump ebb1($nv11b, v12)
|
|
||||||
|
|
||||||
ebb2:
|
ebb2:
|
||||||
return v12
|
return v12
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ ebb5:
|
|||||||
brnz v6, ebb2
|
brnz v6, ebb2
|
||||||
jump ebb3(v4)
|
jump ebb3(v4)
|
||||||
|
|
||||||
|
; check: ebb5:
|
||||||
|
; check: jump ebb3(v4)
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; nextln: jump ebb3(v9)
|
||||||
|
|
||||||
ebb3(v7: i32):
|
ebb3(v7: i32):
|
||||||
call fn1(v0, v7)
|
call fn1(v0, v7)
|
||||||
v26 = iconst.i32 0x4ffe
|
v26 = iconst.i32 0x4ffe
|
||||||
@@ -61,13 +66,10 @@ ebb6:
|
|||||||
v8 = iadd v25, v23
|
v8 = iadd v25, v23
|
||||||
v9 = load.i32 v8+56
|
v9 = load.i32 v8+56
|
||||||
; check: v9 = spill
|
; check: v9 = spill
|
||||||
; check: brnz $V, $(splitEdge=$EBB)
|
; check: brnz $V, $splitEdge
|
||||||
brnz v9, ebb3(v9)
|
brnz v9, ebb3(v9)
|
||||||
jump ebb4
|
jump ebb4
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; nextln: jump ebb3(v9)
|
|
||||||
|
|
||||||
ebb4:
|
ebb4:
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ ebb0(v0: i32):
|
|||||||
v3 = iconst.i32 0
|
v3 = iconst.i32 0
|
||||||
jump ebb2(v3, v2, v0)
|
jump ebb2(v3, v2, v0)
|
||||||
|
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; check: jump ebb2($V, $V, v9)
|
||||||
|
|
||||||
ebb2(v4: i32, v5: i32, v7: i32):
|
ebb2(v4: i32, v5: i32, v7: i32):
|
||||||
; check: ebb2
|
; check: ebb2
|
||||||
v6 = iadd v4, v5
|
v6 = iadd v4, v5
|
||||||
@@ -33,11 +36,9 @@ ebb2(v4: i32, v5: i32, v7: i32):
|
|||||||
;
|
;
|
||||||
; We should be able to handle this situation without making copies of v9.
|
; We should be able to handle this situation without making copies of v9.
|
||||||
brnz v9, ebb2(v5, v6, v9)
|
brnz v9, ebb2(v5, v6, v9)
|
||||||
; check: brnz v9, $(splitEdge=$EBB)
|
; check: brnz v9, $splitEdge
|
||||||
jump ebb3
|
jump ebb3
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; check: jump ebb2($V, $V, v9)
|
|
||||||
ebb3:
|
ebb3:
|
||||||
return v5
|
return v5
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,20 @@ function %test(i32, r64, r64) -> r64 {
|
|||||||
; nextln: v10 = copy v0
|
; nextln: v10 = copy v0
|
||||||
; nextln: jump ebb1(v10)
|
; nextln: jump ebb1(v10)
|
||||||
; nextln:
|
; nextln:
|
||||||
|
; nextln: ebb7:
|
||||||
|
; nextln: regmove.i32 v5, %rcx -> %rax
|
||||||
|
; nextln: jump ebb1(v5)
|
||||||
|
; nextln:
|
||||||
; nextln: ebb1(v3: i32 [%rax]):
|
; nextln: ebb1(v3: i32 [%rax]):
|
||||||
; nextln: v8 = iconst.i32 1
|
; nextln: v8 = iconst.i32 1
|
||||||
; nextln: v4 = isub v8, v3
|
; nextln: v4 = isub v8, v3
|
||||||
; nextln: jump ebb2(v4)
|
; nextln: jump ebb2(v4)
|
||||||
; nextln:
|
; nextln:
|
||||||
|
; nextln: ebb8:
|
||||||
|
; nextln: v9 = copy.i32 v0
|
||||||
|
; nextln: regmove v9, %rax -> %rcx
|
||||||
|
; nextln: jump ebb2(v9)
|
||||||
|
; nextln:
|
||||||
; nextln: ebb2(v5: i32 [%rcx]):
|
; nextln: ebb2(v5: i32 [%rcx]):
|
||||||
; nextln: safepoint v1, v2
|
; nextln: safepoint v1, v2
|
||||||
; nextln: resumable_trap interrupt
|
; nextln: resumable_trap interrupt
|
||||||
@@ -60,13 +69,4 @@ function %test(i32, r64, r64) -> r64 {
|
|||||||
; nextln: ebb6:
|
; nextln: ebb6:
|
||||||
; nextln: regmove.r64 v2, %rdx -> %rax
|
; nextln: regmove.r64 v2, %rdx -> %rax
|
||||||
; nextln: return v2
|
; nextln: return v2
|
||||||
; nextln:
|
|
||||||
; nextln: ebb7:
|
|
||||||
; nextln: regmove.i32 v5, %rcx -> %rax
|
|
||||||
; nextln: jump ebb1(v5)
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb8:
|
|
||||||
; nextln: v9 = copy.i32 v0
|
|
||||||
; nextln: regmove v9, %rax -> %rcx
|
|
||||||
; nextln: jump ebb2(v9)
|
|
||||||
; nextln: }
|
; nextln: }
|
||||||
|
|||||||
Reference in New Issue
Block a user