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.
|
||||
|
||||
.. autoinst:: jump
|
||||
.. autoinst:: fallthrough
|
||||
.. autoinst:: brz
|
||||
.. autoinst:: brnz
|
||||
.. autoinst:: br_icmp
|
||||
|
||||
@@ -107,7 +107,7 @@ ebb1:
|
||||
; bgeu 0x004
|
||||
br_icmp uge, v2, v1, ebb2 ; bin: 00aaf263
|
||||
|
||||
jump ebb2
|
||||
fallthrough ebb2
|
||||
|
||||
ebb2:
|
||||
; beq x, %x0
|
||||
|
||||
@@ -49,6 +49,19 @@ jump = Instruction(
|
||||
""",
|
||||
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', r"""
|
||||
Branch when zero.
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
|
||||
use binemit::CodeOffset;
|
||||
use entity_map::EntityMap;
|
||||
use ir::{Function, DataFlowGraph, Cursor, Inst};
|
||||
use ir::{Function, DataFlowGraph, Cursor, Inst, InstructionData, Opcode};
|
||||
use isa::{TargetIsa, EncInfo, Encoding};
|
||||
use iterators::IteratorExtras;
|
||||
|
||||
/// 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.resize(func.dfg.num_ebbs());
|
||||
|
||||
// Start by inserting fall through instructions.
|
||||
fallthroughs(func);
|
||||
|
||||
// The relaxation algorithm iterates to convergence.
|
||||
let mut go_again = true;
|
||||
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`.
|
||||
///
|
||||
/// Return the size of the replacement instructions up to and including the location where `pos` is
|
||||
|
||||
Reference in New Issue
Block a user