Browse Source

Add a fallthrough instruction.

Change jumps to fallthroughs in the branch relaxation pass before
computing the EBB offsets.
pull/3/head
Jakob Stoklund Olesen 8 years ago
parent
commit
e5e5b30315
  1. 1
      docs/langref.rst
  2. 2
      filetests/isa/riscv/binary32.cton
  3. 13
      lib/cretonne/meta/base/instructions.py
  4. 37
      lib/cretonne/src/binemit/relaxation.rs

1
docs/langref.rst

@ -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

2
filetests/isa/riscv/binary32.cton

@ -107,7 +107,7 @@ ebb1:
; bgeu 0x004
br_icmp uge, v2, v1, ebb2 ; bin: 00aaf263
jump ebb2
fallthrough ebb2
ebb2:
; beq x, %x0

13
lib/cretonne/meta/base/instructions.py

@ -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.

37
lib/cretonne/src/binemit/relaxation.rs

@ -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

Loading…
Cancel
Save