Emit compressed instruction encodings for instructions where constraints allow

This commit is contained in:
Angus Holder
2017-09-22 00:40:43 +01:00
committed by Jakob Stoklund Olesen
parent 2d4c860187
commit 3b66c0be40
4 changed files with 80 additions and 4 deletions

View File

@@ -1,6 +1,7 @@
; binary emission of 64-bit code.
test binemit
set is_64bit
set is_compressed
isa intel haswell
; The binary encodings can be verified with the command:

View File

@@ -104,16 +104,32 @@ impl SubTest for TestBinEmit {
// value locations. The current error reporting is just crashing...
let mut func = func.into_owned();
let is_compressed = isa.flags().is_compressed();
// Give an encoding to any instruction that doesn't already have one.
for ebb in func.layout.ebbs() {
for inst in func.layout.ebb_insts(ebb) {
if !func.encodings[inst].is_legal() {
if let Ok(enc) = isa.encode(
let mut legal_encodings = isa.legal_encodings(
&func.dfg,
&func.dfg[inst],
func.dfg.ctrl_typevar(inst),
)
{
);
let enc = if is_compressed {
// Get the smallest legal encoding
legal_encodings
.filter(|e| {
let recipe_constraints = &encinfo.constraints[e.recipe()];
recipe_constraints.satisfied(inst, &func)
})
.min_by_key(|&e| encinfo.bytes(e))
} else {
// If not using compressed, just use the first encoding.
legal_encodings.next()
};
if let Some(enc) = enc {
func.encodings[inst] = enc;
}
}

View File

@@ -13,7 +13,7 @@ from .registers import GPR, ABCD, FPR
try:
from typing import Tuple, Dict # noqa
from cdsl.instructions import InstructionFormat # noqa
from cdsl.isa import ConstraintSeq, BranchRange, PredNode # noqa
from cdsl.isa import ConstraintSeq, BranchRange, PredNode, OperandConstraint # noqa
except ImportError:
pass

View File

@@ -9,6 +9,7 @@
use binemit::CodeOffset;
use isa::{RegClass, RegUnit};
use ir::{Function, ValueLoc, Inst};
/// Register constraint for a single value operand or instruction result.
pub struct OperandConstraint {
@@ -21,6 +22,34 @@ pub struct OperandConstraint {
pub regclass: RegClass,
}
impl OperandConstraint {
/// Check if this operand constraint is satisfied by the given value location.
/// For tied constraints, this only checks the register class, not that the
/// counterpart operand has the same value location.
pub fn satisfied(&self, loc: ValueLoc) -> bool {
match self.kind {
ConstraintKind::Reg |
ConstraintKind::Tied(_) => {
if let ValueLoc::Reg(reg) = loc {
self.regclass.contains(reg)
} else {
false
}
}
ConstraintKind::FixedReg(reg) => {
loc == ValueLoc::Reg(reg) && self.regclass.contains(reg)
}
ConstraintKind::Stack => {
if let ValueLoc::Stack(_) = loc {
true
} else {
false
}
}
}
}
}
/// The different kinds of operand constraints.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ConstraintKind {
@@ -78,6 +107,36 @@ pub struct RecipeConstraints {
pub tied_ops: bool,
}
impl RecipeConstraints {
/// Check that these constraints are satisfied by the operands on `inst`.
pub fn satisfied(&self, inst: Inst, func: &Function) -> bool {
for (&arg, constraint) in func.dfg.inst_args(inst).iter().zip(self.ins) {
let loc = func.locations[arg];
if let ConstraintKind::Tied(out_index) = constraint.kind {
let out_val = func.dfg.inst_results(inst)[out_index as usize];
let out_loc = func.locations[out_val];
if loc != out_loc {
return false;
}
}
if !constraint.satisfied(loc) {
return false;
}
}
for (&arg, constraint) in func.dfg.inst_results(inst).iter().zip(self.outs) {
let loc = func.locations[arg];
if !constraint.satisfied(loc) {
return false;
}
}
true
}
}
/// Constraints on the range of a branch instruction.
///
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.