Add a fallthrough instruction.
Change jumps to fallthroughs in the branch relaxation pass before computing the EBB offsets.
This commit is contained in:
@@ -319,6 +319,7 @@ condition is satisfied, otherwise execution continues at the following
|
|||||||
instruction in the EBB.
|
instruction in the EBB.
|
||||||
|
|
||||||
.. autoinst:: jump
|
.. autoinst:: jump
|
||||||
|
.. autoinst:: fallthrough
|
||||||
.. autoinst:: brz
|
.. autoinst:: brz
|
||||||
.. autoinst:: brnz
|
.. autoinst:: brnz
|
||||||
.. autoinst:: br_icmp
|
.. autoinst:: br_icmp
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ ebb1:
|
|||||||
; bgeu 0x004
|
; bgeu 0x004
|
||||||
br_icmp uge, v2, v1, ebb2 ; bin: 00aaf263
|
br_icmp uge, v2, v1, ebb2 ; bin: 00aaf263
|
||||||
|
|
||||||
jump ebb2
|
fallthrough ebb2
|
||||||
|
|
||||||
ebb2:
|
ebb2:
|
||||||
; beq x, %x0
|
; beq x, %x0
|
||||||
|
|||||||
@@ -49,6 +49,19 @@ jump = Instruction(
|
|||||||
""",
|
""",
|
||||||
ins=(EBB, args), is_branch=True, is_terminator=True)
|
ins=(EBB, args), is_branch=True, is_terminator=True)
|
||||||
|
|
||||||
|
fallthrough = Instruction(
|
||||||
|
'fallthrough', r"""
|
||||||
|
Fall through to the next EBB.
|
||||||
|
|
||||||
|
This is the same as :inst:`jump`, except the destination EBB must be
|
||||||
|
the next one in the layout.
|
||||||
|
|
||||||
|
Jumps are turned into fall-through instructions by the branch
|
||||||
|
relaxation pass. There is no reason to use this instruction outside
|
||||||
|
that pass.
|
||||||
|
""",
|
||||||
|
ins=(EBB, args), is_branch=True, is_terminator=True)
|
||||||
|
|
||||||
brz = Instruction(
|
brz = Instruction(
|
||||||
'brz', r"""
|
'brz', r"""
|
||||||
Branch when zero.
|
Branch when zero.
|
||||||
|
|||||||
@@ -29,8 +29,9 @@
|
|||||||
|
|
||||||
use binemit::CodeOffset;
|
use binemit::CodeOffset;
|
||||||
use entity_map::EntityMap;
|
use entity_map::EntityMap;
|
||||||
use ir::{Function, DataFlowGraph, Cursor, Inst};
|
use ir::{Function, DataFlowGraph, Cursor, Inst, InstructionData, Opcode};
|
||||||
use isa::{TargetIsa, EncInfo, Encoding};
|
use isa::{TargetIsa, EncInfo, Encoding};
|
||||||
|
use iterators::IteratorExtras;
|
||||||
|
|
||||||
/// Relax branches and compute the final layout of EBB headers in `func`.
|
/// Relax branches and compute the final layout of EBB headers in `func`.
|
||||||
///
|
///
|
||||||
@@ -42,6 +43,9 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) {
|
|||||||
func.offsets.clear();
|
func.offsets.clear();
|
||||||
func.offsets.resize(func.dfg.num_ebbs());
|
func.offsets.resize(func.dfg.num_ebbs());
|
||||||
|
|
||||||
|
// Start by inserting fall through instructions.
|
||||||
|
fallthroughs(func);
|
||||||
|
|
||||||
// The relaxation algorithm iterates to convergence.
|
// The relaxation algorithm iterates to convergence.
|
||||||
let mut go_again = true;
|
let mut go_again = true;
|
||||||
while go_again {
|
while go_again {
|
||||||
@@ -89,6 +93,37 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any
|
||||||
|
/// existing `fallthrough` instructions are correct.
|
||||||
|
fn fallthroughs(func: &mut Function) {
|
||||||
|
for (ebb, succ) in func.layout.ebbs().adjacent_pairs() {
|
||||||
|
let term = func.layout
|
||||||
|
.last_inst(ebb)
|
||||||
|
.expect("EBB has no terminator.");
|
||||||
|
if let InstructionData::Jump {
|
||||||
|
ref mut opcode,
|
||||||
|
destination,
|
||||||
|
..
|
||||||
|
} = func.dfg[term] {
|
||||||
|
match *opcode {
|
||||||
|
Opcode::Fallthrough => {
|
||||||
|
// Somebody used a fall-through instruction before the branch relaxation pass.
|
||||||
|
// Make sure it is correct, i.e. the destination is the layout successor.
|
||||||
|
assert_eq!(destination, succ, "Illegal fall-through in {}", ebb)
|
||||||
|
}
|
||||||
|
Opcode::Jump => {
|
||||||
|
// If this is a jump to the successor EBB, change it to a fall-through.
|
||||||
|
if destination == succ {
|
||||||
|
*opcode = Opcode::Fallthrough;
|
||||||
|
func.encodings[term] = Default::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Relax the branch instruction at `pos` so it can cover the range `offset - dest_offset`.
|
/// Relax the branch instruction at `pos` so it can cover the range `offset - dest_offset`.
|
||||||
///
|
///
|
||||||
/// Return the size of the replacement instructions up to and including the location where `pos` is
|
/// Return the size of the replacement instructions up to and including the location where `pos` is
|
||||||
|
|||||||
Reference in New Issue
Block a user