From e5e5b30315098c7f382c7cc873866921fd0bef3c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Thu, 6 Apr 2017 14:22:32 -0700 Subject: [PATCH] Add a fallthrough instruction. Change jumps to fallthroughs in the branch relaxation pass before computing the EBB offsets. --- docs/langref.rst | 1 + filetests/isa/riscv/binary32.cton | 2 +- lib/cretonne/meta/base/instructions.py | 13 +++++++++ lib/cretonne/src/binemit/relaxation.rs | 37 +++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/langref.rst b/docs/langref.rst index 47a0dae37c..398141fb5b 100644 --- a/docs/langref.rst +++ b/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 diff --git a/filetests/isa/riscv/binary32.cton b/filetests/isa/riscv/binary32.cton index bdcbde9dd2..4c9f9439b9 100644 --- a/filetests/isa/riscv/binary32.cton +++ b/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 diff --git a/lib/cretonne/meta/base/instructions.py b/lib/cretonne/meta/base/instructions.py index 4776f576c1..d9eda7a220 100644 --- a/lib/cretonne/meta/base/instructions.py +++ b/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. diff --git a/lib/cretonne/src/binemit/relaxation.rs b/lib/cretonne/src/binemit/relaxation.rs index ef3bfdb257..179540dad0 100644 --- a/lib/cretonne/src/binemit/relaxation.rs +++ b/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