* Rename size to base_size and introduce a compute_size function; * Add infra to inspect in/outs registers when computing the size of an instruction; * Remove the GPR_SAFE_DEREF and GPR_ZERO_DEREF_SAFE register classes on x86 (fixes #335);
This commit is contained in:
committed by
Dan Gohman
parent
c2069762ef
commit
9d6821d6d9
@@ -32,6 +32,7 @@ use cursor::{Cursor, FuncCursor};
|
||||
use ir::{Function, InstructionData, Opcode};
|
||||
use isa::{EncInfo, TargetIsa};
|
||||
use iterators::IteratorExtras;
|
||||
use regalloc::RegDiversions;
|
||||
use timing;
|
||||
use CodegenResult;
|
||||
|
||||
@@ -51,6 +52,7 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
|
||||
fallthroughs(func);
|
||||
|
||||
let mut offset = 0;
|
||||
let mut divert = RegDiversions::new();
|
||||
|
||||
// The relaxation algorithm iterates to convergence.
|
||||
let mut go_again = true;
|
||||
@@ -61,6 +63,8 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
|
||||
// Visit all instructions in layout order
|
||||
let mut cur = FuncCursor::new(func);
|
||||
while let Some(ebb) = cur.next_ebb() {
|
||||
divert.clear();
|
||||
|
||||
// Record the offset for `ebb` and make sure we iterate until offsets are stable.
|
||||
if cur.func.offsets[ebb] != offset {
|
||||
debug_assert!(
|
||||
@@ -72,8 +76,9 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
|
||||
}
|
||||
|
||||
while let Some(inst) = cur.next_inst() {
|
||||
divert.apply(&cur.func.dfg[inst]);
|
||||
|
||||
let enc = cur.func.encodings[inst];
|
||||
let size = encinfo.bytes(enc);
|
||||
|
||||
// See if this might be a branch that is out of range.
|
||||
if let Some(range) = encinfo.branch_range(enc) {
|
||||
@@ -84,13 +89,14 @@ pub fn relax_branches(func: &mut Function, isa: &TargetIsa) -> CodegenResult<Cod
|
||||
if !range.contains(offset, dest_offset)
|
||||
&& (dest_offset != 0 || Some(dest) == cur.func.layout.entry_block())
|
||||
{
|
||||
offset += relax_branch(&mut cur, offset, dest_offset, &encinfo, isa);
|
||||
offset +=
|
||||
relax_branch(&mut cur, &divert, offset, dest_offset, &encinfo, isa);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += size;
|
||||
offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,6 +147,7 @@ fn fallthroughs(func: &mut Function) {
|
||||
/// left.
|
||||
fn relax_branch(
|
||||
cur: &mut FuncCursor,
|
||||
divert: &RegDiversions,
|
||||
offset: CodeOffset,
|
||||
dest_offset: CodeOffset,
|
||||
encinfo: &EncInfo,
|
||||
@@ -181,7 +188,7 @@ fn relax_branch(
|
||||
}
|
||||
}) {
|
||||
cur.func.encodings[inst] = enc;
|
||||
return encinfo.bytes(enc);
|
||||
return encinfo.byte_size(enc, inst, &divert, &cur.func);
|
||||
}
|
||||
|
||||
// Note: On some RISC ISAs, conditional branches have shorter range than unconditional
|
||||
|
||||
@@ -48,7 +48,7 @@ pub fn shrink_instructions(func: &mut Function, isa: &TargetIsa) {
|
||||
let best_enc = isa
|
||||
.legal_encodings(func, &func.dfg[inst], ctrl_type)
|
||||
.filter(|e| encinfo.constraints[e.recipe()].satisfied(inst, &divert, &func))
|
||||
.min_by_key(|e| encinfo.bytes(*e))
|
||||
.min_by_key(|e| encinfo.byte_size(*e, inst, &divert, &func))
|
||||
.unwrap();
|
||||
|
||||
if best_enc != enc {
|
||||
@@ -59,8 +59,8 @@ pub fn shrink_instructions(func: &mut Function, isa: &TargetIsa) {
|
||||
encinfo.display(enc),
|
||||
encinfo.display(best_enc),
|
||||
func.dfg.display_inst(inst, isa),
|
||||
encinfo.bytes(enc),
|
||||
encinfo.bytes(best_enc)
|
||||
encinfo.byte_size(enc, inst, &divert, &func),
|
||||
encinfo.byte_size(best_enc, inst, &divert, &func)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,6 @@ impl Context {
|
||||
let code_size = relax_branches(&mut self.func, isa)?;
|
||||
self.verify_if(isa)?;
|
||||
self.verify_locations_if(isa)?;
|
||||
|
||||
Ok(code_size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use ir::{
|
||||
use ir::{EbbOffsets, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
||||
use ir::{JumpTableOffsets, JumpTables};
|
||||
use isa::{EncInfo, Encoding, Legalize, TargetIsa};
|
||||
use regalloc::RegDiversions;
|
||||
use settings::CallConv;
|
||||
use std::fmt;
|
||||
use write::write_function;
|
||||
@@ -177,13 +178,20 @@ impl Function {
|
||||
///
|
||||
/// This function can only be used after the code layout has been computed by the
|
||||
/// `binemit::relax_branches()` function.
|
||||
pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
|
||||
pub fn inst_offsets<'a>(
|
||||
&'a self,
|
||||
func: &'a Function,
|
||||
ebb: Ebb,
|
||||
encinfo: &EncInfo,
|
||||
) -> InstOffsetIter<'a> {
|
||||
assert!(
|
||||
!self.offsets.is_empty(),
|
||||
"Code layout must be computed first"
|
||||
);
|
||||
InstOffsetIter {
|
||||
encinfo: encinfo.clone(),
|
||||
func,
|
||||
divert: RegDiversions::new(),
|
||||
encodings: &self.encodings,
|
||||
offset: self.offsets[ebb],
|
||||
iter: self.layout.ebb_insts(ebb),
|
||||
@@ -226,6 +234,8 @@ impl fmt::Debug for Function {
|
||||
/// Iterator returning instruction offsets and sizes: `(offset, inst, size)`.
|
||||
pub struct InstOffsetIter<'a> {
|
||||
encinfo: EncInfo,
|
||||
divert: RegDiversions,
|
||||
func: &'a Function,
|
||||
encodings: &'a InstEncodings,
|
||||
offset: CodeOffset,
|
||||
iter: ir::layout::Insts<'a>,
|
||||
@@ -236,10 +246,13 @@ impl<'a> Iterator for InstOffsetIter<'a> {
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|inst| {
|
||||
let size = self.encinfo.bytes(self.encodings[inst]);
|
||||
self.divert.apply(&self.func.dfg[inst]);
|
||||
let byte_size =
|
||||
self.encinfo
|
||||
.byte_size(self.encodings[inst], inst, &self.divert, self.func);
|
||||
let offset = self.offset;
|
||||
self.offset += size;
|
||||
(offset, inst, size)
|
||||
self.offset += byte_size;
|
||||
(offset, inst, byte_size)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ pub enum StackSlotKind {
|
||||
/// An emergency spill slot.
|
||||
///
|
||||
/// Emergency slots are allocated late when the register's constraint solver needs extra space
|
||||
/// to shuffle registers around. The are only used briefly, and can be reused.
|
||||
/// to shuffle registers around. They are only used briefly, and can be reused.
|
||||
EmergencySlot,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
//! The `Encoding` struct.
|
||||
|
||||
use binemit::CodeOffset;
|
||||
use ir::{Function, Inst};
|
||||
use isa::constraints::{BranchRange, RecipeConstraints};
|
||||
use regalloc::RegDiversions;
|
||||
use std::fmt;
|
||||
|
||||
/// Bits needed to encode an instruction as binary machine code.
|
||||
@@ -78,12 +80,24 @@ impl fmt::Display for DisplayEncoding {
|
||||
}
|
||||
}
|
||||
|
||||
type SizeCalculatorFn = fn(&RecipeSizing, Inst, &RegDiversions, &Function) -> u8;
|
||||
|
||||
/// Returns the base size of the Recipe, assuming it's fixed. This is the default for most
|
||||
/// encodings; others can be variable and longer than this base size, depending on the registers
|
||||
/// they're using and use a different function, specific per platform.
|
||||
pub fn base_size(sizing: &RecipeSizing, _: Inst, _2: &RegDiversions, _3: &Function) -> u8 {
|
||||
sizing.base_size
|
||||
}
|
||||
|
||||
/// Code size information for an encoding recipe.
|
||||
///
|
||||
/// All encoding recipes correspond to an exact instruction size.
|
||||
pub struct RecipeSizing {
|
||||
/// Size in bytes of instructions encoded with this recipe.
|
||||
pub bytes: u8,
|
||||
pub base_size: u8,
|
||||
|
||||
/// Method computing the real instruction's size, given inputs and outputs.
|
||||
pub compute_size: SizeCalculatorFn,
|
||||
|
||||
/// Allowed branch range in this recipe, if any.
|
||||
///
|
||||
@@ -118,13 +132,20 @@ impl EncInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the exact size in bytes of instructions encoded with `enc`.
|
||||
/// Get the precise size in bytes of instructions encoded with `enc`.
|
||||
///
|
||||
/// Returns 0 for illegal encodings.
|
||||
pub fn bytes(&self, enc: Encoding) -> CodeOffset {
|
||||
self.sizing
|
||||
.get(enc.recipe())
|
||||
.map_or(0, |s| CodeOffset::from(s.bytes))
|
||||
pub fn byte_size(
|
||||
&self,
|
||||
enc: Encoding,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> CodeOffset {
|
||||
self.sizing.get(enc.recipe()).map_or(0, |s| {
|
||||
let compute_size = s.compute_size;
|
||||
CodeOffset::from(compute_size(&s, inst, divert, func))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the branch range that is supported by `enc`, if any.
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
//! concurrent function compilations.
|
||||
|
||||
pub use isa::constraints::{BranchRange, ConstraintKind, OperandConstraint, RecipeConstraints};
|
||||
pub use isa::encoding::{EncInfo, Encoding};
|
||||
pub use isa::encoding::{base_size, EncInfo, Encoding};
|
||||
pub use isa::registers::{regs_overlap, RegClass, RegClassIndex, RegInfo, RegUnit};
|
||||
pub use isa::stack::{StackBase, StackBaseMask, StackRef};
|
||||
|
||||
@@ -204,7 +204,7 @@ pub trait TargetIsa: fmt::Display {
|
||||
/// Get a data structure describing the registers in this ISA.
|
||||
fn register_info(&self) -> RegInfo;
|
||||
|
||||
/// Returns an iterartor over legal encodings for the instruction.
|
||||
/// Returns an iterator over legal encodings for the instruction.
|
||||
fn legal_encodings<'a>(
|
||||
&'a self,
|
||||
func: &'a ir::Function,
|
||||
|
||||
@@ -5,7 +5,7 @@ use ir;
|
||||
use isa;
|
||||
use isa::constraints::*;
|
||||
use isa::enc_tables::*;
|
||||
use isa::encoding::RecipeSizing;
|
||||
use isa::encoding::{base_size, RecipeSizing};
|
||||
|
||||
// Include the generated encoding tables:
|
||||
// - `LEVEL1_RV32`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Emitting binary x86 machine code.
|
||||
|
||||
use super::enc_tables::{needs_offset, needs_sib_byte};
|
||||
use super::registers::RU;
|
||||
use binemit::{bad_encoding, CodeSink, Reloc};
|
||||
use ir::condcodes::{CondCode, FloatCC, IntCC};
|
||||
|
||||
@@ -5,15 +5,73 @@ use bitset::BitSet;
|
||||
use cursor::{Cursor, FuncCursor};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::condcodes::IntCC;
|
||||
use ir::{self, InstBuilder};
|
||||
use ir::{self, Function, Inst, InstBuilder};
|
||||
use isa;
|
||||
use isa::constraints::*;
|
||||
use isa::enc_tables::*;
|
||||
use isa::encoding::base_size;
|
||||
use isa::encoding::RecipeSizing;
|
||||
use isa::RegUnit;
|
||||
use regalloc::RegDiversions;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/encoding-x86.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/legalize-x86.rs"));
|
||||
|
||||
pub fn needs_sib_byte(reg: RegUnit) -> bool {
|
||||
reg == RU::r12 as RegUnit || reg == RU::rsp as RegUnit
|
||||
}
|
||||
pub fn needs_offset(reg: RegUnit) -> bool {
|
||||
reg == RU::r13 as RegUnit || reg == RU::rbp as RegUnit
|
||||
}
|
||||
|
||||
fn additional_size_if(
|
||||
op_index: usize,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
condition_func: fn(RegUnit) -> bool,
|
||||
) -> u8 {
|
||||
let addr_reg = divert.reg(func.dfg.inst_args(inst)[op_index], &func.locations);
|
||||
if condition_func(addr_reg) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn size_plus_maybe_offset_for_in_reg_0(
|
||||
sizing: &RecipeSizing,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(0, inst, divert, func, needs_offset)
|
||||
}
|
||||
fn size_plus_maybe_offset_for_in_reg_1(
|
||||
sizing: &RecipeSizing,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(1, inst, divert, func, needs_offset)
|
||||
}
|
||||
fn size_plus_maybe_sib_for_in_reg_0(
|
||||
sizing: &RecipeSizing,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(0, inst, divert, func, needs_sib_byte)
|
||||
}
|
||||
fn size_plus_maybe_sib_for_in_reg_1(
|
||||
sizing: &RecipeSizing,
|
||||
inst: Inst,
|
||||
divert: &RegDiversions,
|
||||
func: &Function,
|
||||
) -> u8 {
|
||||
sizing.base_size + additional_size_if(1, inst, divert, func, needs_sib_byte)
|
||||
}
|
||||
|
||||
/// Expand the `sdiv` and `srem` instructions using `x86_sdivmodx`.
|
||||
fn expand_sdivrem(
|
||||
inst: ir::Inst,
|
||||
|
||||
Reference in New Issue
Block a user