* 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
44
cranelift/filetests/regalloc/gpr-deref-safe-335.clif
Normal file
44
cranelift/filetests/regalloc/gpr-deref-safe-335.clif
Normal file
@@ -0,0 +1,44 @@
|
||||
test regalloc
|
||||
target x86_64
|
||||
|
||||
function u0:587() fast {
|
||||
ebb0:
|
||||
v97 = iconst.i32 0
|
||||
v169 = iconst.i32 0
|
||||
v1729 = iconst.i32 0
|
||||
jump ebb100(v97, v97, v97, v97, v97)
|
||||
|
||||
ebb100(v1758: i32, v1784: i32, v1845: i32, v1856: i32, v1870: i32):
|
||||
v1762 = iconst.i32 0
|
||||
v1769 = iconst.i32 0
|
||||
v1774 = iconst.i32 0
|
||||
v1864 = iconst.i32 0
|
||||
v1897 = iconst.i32 0
|
||||
jump ebb102(v1774, v1784, v1845, v1856, v1870, v1758, v1762, v169, v1729, v97, v169, v169, v169, v169)
|
||||
|
||||
ebb102(v1785: i32, v1789: i32, v1843: i32, v1854: i32, v1868: i32, v1882: i32, v1890: i32, v1901: i32, v1921: i32, v1933: i32, v2058: i32, v2124: i32, v2236: i32, v2366: i32):
|
||||
v1929 = iconst.i32 0
|
||||
v1943 = iconst.i32 0
|
||||
v1949 = iconst.i32 0
|
||||
jump ebb123(v1897, v1769)
|
||||
|
||||
ebb123(v1950: i32, v1979: i32):
|
||||
v1955 = iconst.i32 0
|
||||
brz v1955, ebb125
|
||||
jump ebb122(v1929, v1843, v1864, v2058, v1882, v1897, v1943, v1868, v2124, v1901)
|
||||
|
||||
ebb125:
|
||||
v1961 = iadd_imm.i32 v1949, 0
|
||||
v1952 = iconst.i32 0
|
||||
v1962 = iconst.i64 0
|
||||
v1963 = load.i32 v1962
|
||||
brz v1963, ebb123(v1952, v1961)
|
||||
jump ebb127
|
||||
|
||||
ebb127:
|
||||
v1966 = iconst.i32 0
|
||||
jump ebb122(v1963, v1966, v1966, v1966, v1966, v1966, v1966, v1966, v1966, v1966)
|
||||
|
||||
ebb122(v1967: i32, v1971: i32, v1972: i32, v1978: i32, v2032: i32, v2041: i32, v2053: i32, v2076: i32, v2085: i32, v2096: i32):
|
||||
trap user0
|
||||
}
|
||||
@@ -316,7 +316,8 @@ class EncRecipe(object):
|
||||
:param name: Short mnemonic name for this recipe.
|
||||
:param format: All encoded instructions must have this
|
||||
:py:class:`InstructionFormat`.
|
||||
:param size: Number of bytes in the binary encoded instruction.
|
||||
:param base_size: Base number of bytes in the binary encoded instruction.
|
||||
:param compute_size: Function name to use when computing actual size.
|
||||
:param ins: Tuple of register constraints for value operands.
|
||||
:param outs: Tuple of register constraints for results.
|
||||
:param branch_range: `(origin, bits)` range for branches.
|
||||
@@ -330,9 +331,10 @@ class EncRecipe(object):
|
||||
self,
|
||||
name, # type: str
|
||||
format, # type: InstructionFormat
|
||||
size, # type: int
|
||||
base_size, # type: int
|
||||
ins, # type: ConstraintSeq
|
||||
outs, # type: ConstraintSeq
|
||||
compute_size=None, # type: str
|
||||
branch_range=None, # type: BranchRange
|
||||
clobbers_flags=True, # type: bool
|
||||
instp=None, # type: PredNode
|
||||
@@ -342,8 +344,10 @@ class EncRecipe(object):
|
||||
# type: (...) -> None
|
||||
self.name = name
|
||||
self.format = format
|
||||
assert size >= 0
|
||||
self.size = size
|
||||
assert base_size >= 0
|
||||
self.base_size = base_size
|
||||
self.compute_size = compute_size if compute_size is not None \
|
||||
else 'base_size'
|
||||
self.branch_range = branch_range
|
||||
self.clobbers_flags = clobbers_flags
|
||||
self.instp = instp
|
||||
|
||||
@@ -832,7 +832,8 @@ def emit_recipe_sizing(isa, fmt):
|
||||
for r in isa.all_recipes:
|
||||
fmt.comment('Code size information for recipe {}:'.format(r.name))
|
||||
with fmt.indented('RecipeSizing {', '},'):
|
||||
fmt.format('bytes: {},', r.size)
|
||||
fmt.format('base_size: {},', r.base_size)
|
||||
fmt.format('compute_size: {},', r.compute_size)
|
||||
if r.branch_range:
|
||||
fmt.format(
|
||||
'branch_range: '
|
||||
|
||||
@@ -93,33 +93,33 @@ def LUI():
|
||||
# R-type 32-bit instructions: These are mostly binary arithmetic instructions.
|
||||
# The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8)
|
||||
R = EncRecipe(
|
||||
'R', Binary, size=4, ins=(GPR, GPR), outs=GPR,
|
||||
'R', Binary, base_size=4, ins=(GPR, GPR), outs=GPR,
|
||||
emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
|
||||
|
||||
# R-type with an immediate shift amount instead of rs2.
|
||||
Rshamt = EncRecipe(
|
||||
'Rshamt', BinaryImm, size=4, ins=GPR, outs=GPR,
|
||||
'Rshamt', BinaryImm, base_size=4, ins=GPR, outs=GPR,
|
||||
emit='put_rshamt(bits, in_reg0, imm.into(), out_reg0, sink);')
|
||||
|
||||
# R-type encoding of an integer comparison.
|
||||
Ricmp = EncRecipe(
|
||||
'Ricmp', IntCompare, size=4, ins=(GPR, GPR), outs=GPR,
|
||||
'Ricmp', IntCompare, base_size=4, ins=(GPR, GPR), outs=GPR,
|
||||
emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
|
||||
|
||||
Ii = EncRecipe(
|
||||
'Ii', BinaryImm, size=4, ins=GPR, outs=GPR,
|
||||
'Ii', BinaryImm, base_size=4, ins=GPR, outs=GPR,
|
||||
instp=IsSignedInt(BinaryImm.imm, 12),
|
||||
emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
|
||||
|
||||
# I-type instruction with a hardcoded %x0 rs1.
|
||||
Iz = EncRecipe(
|
||||
'Iz', UnaryImm, size=4, ins=(), outs=GPR,
|
||||
'Iz', UnaryImm, base_size=4, ins=(), outs=GPR,
|
||||
instp=IsSignedInt(UnaryImm.imm, 12),
|
||||
emit='put_i(bits, 0, imm.into(), out_reg0, sink);')
|
||||
|
||||
# I-type encoding of an integer comparison.
|
||||
Iicmp = EncRecipe(
|
||||
'Iicmp', IntCompareImm, size=4, ins=GPR, outs=GPR,
|
||||
'Iicmp', IntCompareImm, base_size=4, ins=GPR, outs=GPR,
|
||||
instp=IsSignedInt(IntCompareImm.imm, 12),
|
||||
emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
|
||||
|
||||
@@ -127,7 +127,7 @@ Iicmp = EncRecipe(
|
||||
# immediate offset.
|
||||
# The variable return values are not encoded.
|
||||
Iret = EncRecipe(
|
||||
'Iret', MultiAry, size=4, ins=(), outs=(),
|
||||
'Iret', MultiAry, base_size=4, ins=(), outs=(),
|
||||
emit='''
|
||||
// Return instructions are always a jalr to %x1.
|
||||
// The return address is provided as a special-purpose link argument.
|
||||
@@ -142,7 +142,7 @@ Iret = EncRecipe(
|
||||
|
||||
# I-type encoding for `jalr` as a call_indirect.
|
||||
Icall = EncRecipe(
|
||||
'Icall', CallIndirect, size=4, ins=GPR, outs=(),
|
||||
'Icall', CallIndirect, base_size=4, ins=GPR, outs=(),
|
||||
emit='''
|
||||
// call_indirect instructions are jalr with rd=%x1.
|
||||
put_i(
|
||||
@@ -157,23 +157,23 @@ Icall = EncRecipe(
|
||||
|
||||
# Copy of a GPR is implemented as addi x, 0.
|
||||
Icopy = EncRecipe(
|
||||
'Icopy', Unary, size=4, ins=GPR, outs=GPR,
|
||||
'Icopy', Unary, base_size=4, ins=GPR, outs=GPR,
|
||||
emit='put_i(bits, in_reg0, 0, out_reg0, sink);')
|
||||
|
||||
# Same for a GPR regmove.
|
||||
Irmov = EncRecipe(
|
||||
'Irmov', RegMove, size=4, ins=GPR, outs=(),
|
||||
'Irmov', RegMove, base_size=4, ins=GPR, outs=(),
|
||||
emit='put_i(bits, src, 0, dst, sink);')
|
||||
|
||||
# U-type instructions have a 20-bit immediate that targets bits 12-31.
|
||||
U = EncRecipe(
|
||||
'U', UnaryImm, size=4, ins=(), outs=GPR,
|
||||
'U', UnaryImm, base_size=4, ins=(), outs=GPR,
|
||||
instp=IsSignedInt(UnaryImm.imm, 32, 12),
|
||||
emit='put_u(bits, imm.into(), out_reg0, sink);')
|
||||
|
||||
# UJ-type unconditional branch instructions.
|
||||
UJ = EncRecipe(
|
||||
'UJ', Jump, size=4, ins=(), outs=(), branch_range=(0, 21),
|
||||
'UJ', Jump, base_size=4, ins=(), outs=(), branch_range=(0, 21),
|
||||
emit='''
|
||||
let dest = i64::from(func.offsets[destination]);
|
||||
let disp = dest - i64::from(sink.offset());
|
||||
@@ -181,7 +181,7 @@ UJ = EncRecipe(
|
||||
''')
|
||||
|
||||
UJcall = EncRecipe(
|
||||
'UJcall', Call, size=4, ins=(), outs=(),
|
||||
'UJcall', Call, base_size=4, ins=(), outs=(),
|
||||
emit='''
|
||||
sink.reloc_external(Reloc::RiscvCall,
|
||||
&func.dfg.ext_funcs[func_ref].name,
|
||||
@@ -192,7 +192,7 @@ UJcall = EncRecipe(
|
||||
|
||||
# SB-type branch instructions.
|
||||
SB = EncRecipe(
|
||||
'SB', BranchIcmp, size=4,
|
||||
'SB', BranchIcmp, base_size=4,
|
||||
ins=(GPR, GPR), outs=(),
|
||||
branch_range=(0, 13),
|
||||
emit='''
|
||||
@@ -203,7 +203,7 @@ SB = EncRecipe(
|
||||
|
||||
# SB-type branch instruction with rs2 fixed to zero.
|
||||
SBzero = EncRecipe(
|
||||
'SBzero', Branch, size=4,
|
||||
'SBzero', Branch, base_size=4,
|
||||
ins=(GPR), outs=(),
|
||||
branch_range=(0, 13),
|
||||
emit='''
|
||||
@@ -214,12 +214,12 @@ SBzero = EncRecipe(
|
||||
|
||||
# Spill of a GPR.
|
||||
GPsp = EncRecipe(
|
||||
'GPsp', Unary, size=4,
|
||||
'GPsp', Unary, base_size=4,
|
||||
ins=GPR, outs=Stack(GPR),
|
||||
emit='unimplemented!();')
|
||||
|
||||
# Fill of a GPR.
|
||||
GPfi = EncRecipe(
|
||||
'GPfi', Unary, size=4,
|
||||
'GPfi', Unary, base_size=4,
|
||||
ins=Stack(GPR), outs=GPR,
|
||||
emit='unimplemented!();')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,14 +46,7 @@ FlagRegs = RegBank(
|
||||
names=['rflags'])
|
||||
|
||||
GPR = RegClass(IntRegs)
|
||||
# Certain types of deref encodings cannot be used with all registers.
|
||||
# R13/RBP cannot be used with zero-offset load or store instructions.
|
||||
# R12 cannot be used with a non-SIB-byte encoding of all derefs.
|
||||
GPR_DEREF_SAFE = GPR.without(GPR.rsp, GPR.r12)
|
||||
GPR_ZERO_DEREF_SAFE = GPR_DEREF_SAFE.without(GPR.rbp, GPR.r13)
|
||||
GPR8 = GPR[0:8]
|
||||
GPR8_DEREF_SAFE = GPR8.without(GPR.rsp)
|
||||
GPR8_ZERO_DEREF_SAFE = GPR8_DEREF_SAFE.without(GPR.rbp)
|
||||
ABCD = GPR[0:4]
|
||||
FPR = RegClass(FloatRegs)
|
||||
FPR8 = FPR[0:8]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -149,7 +149,8 @@ impl SubTest for TestBinEmit {
|
||||
|
||||
if opt_level == OptLevel::Best {
|
||||
// Get the smallest legal encoding
|
||||
legal_encodings.min_by_key(|&e| encinfo.bytes(e))
|
||||
legal_encodings
|
||||
.min_by_key(|&e| encinfo.byte_size(e, inst, &divert, &func))
|
||||
} else {
|
||||
// If not optimizing, just use the first encoding.
|
||||
legal_encodings.next()
|
||||
@@ -204,7 +205,7 @@ impl SubTest for TestBinEmit {
|
||||
"Inconsistent {} header offset",
|
||||
ebb
|
||||
);
|
||||
for (offset, inst, enc_bytes) in func.inst_offsets(ebb, &encinfo) {
|
||||
for (offset, inst, enc_bytes) in func.inst_offsets(&func, ebb, &encinfo) {
|
||||
assert_eq!(sink.offset, offset);
|
||||
sink.text.clear();
|
||||
let enc = func.encodings[inst];
|
||||
|
||||
Reference in New Issue
Block a user