Emit compressed instruction encodings for instructions where constraints allow
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
2d4c860187
commit
3b66c0be40
@@ -1,6 +1,7 @@
|
|||||||
; binary emission of 64-bit code.
|
; binary emission of 64-bit code.
|
||||||
test binemit
|
test binemit
|
||||||
set is_64bit
|
set is_64bit
|
||||||
|
set is_compressed
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
; The binary encodings can be verified with the command:
|
; The binary encodings can be verified with the command:
|
||||||
|
|||||||
@@ -104,16 +104,32 @@ impl SubTest for TestBinEmit {
|
|||||||
// value locations. The current error reporting is just crashing...
|
// value locations. The current error reporting is just crashing...
|
||||||
let mut func = func.into_owned();
|
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.
|
// Give an encoding to any instruction that doesn't already have one.
|
||||||
for ebb in func.layout.ebbs() {
|
for ebb in func.layout.ebbs() {
|
||||||
for inst in func.layout.ebb_insts(ebb) {
|
for inst in func.layout.ebb_insts(ebb) {
|
||||||
if !func.encodings[inst].is_legal() {
|
if !func.encodings[inst].is_legal() {
|
||||||
if let Ok(enc) = isa.encode(
|
let mut legal_encodings = isa.legal_encodings(
|
||||||
&func.dfg,
|
&func.dfg,
|
||||||
&func.dfg[inst],
|
&func.dfg[inst],
|
||||||
func.dfg.ctrl_typevar(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;
|
func.encodings[inst] = enc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from .registers import GPR, ABCD, FPR
|
|||||||
try:
|
try:
|
||||||
from typing import Tuple, Dict # noqa
|
from typing import Tuple, Dict # noqa
|
||||||
from cdsl.instructions import InstructionFormat # 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:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
use binemit::CodeOffset;
|
use binemit::CodeOffset;
|
||||||
use isa::{RegClass, RegUnit};
|
use isa::{RegClass, RegUnit};
|
||||||
|
use ir::{Function, ValueLoc, Inst};
|
||||||
|
|
||||||
/// Register constraint for a single value operand or instruction result.
|
/// Register constraint for a single value operand or instruction result.
|
||||||
pub struct OperandConstraint {
|
pub struct OperandConstraint {
|
||||||
@@ -21,6 +22,34 @@ pub struct OperandConstraint {
|
|||||||
pub regclass: RegClass,
|
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.
|
/// The different kinds of operand constraints.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ConstraintKind {
|
pub enum ConstraintKind {
|
||||||
@@ -78,6 +107,36 @@ pub struct RecipeConstraints {
|
|||||||
pub tied_ops: bool,
|
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.
|
/// Constraints on the range of a branch instruction.
|
||||||
///
|
///
|
||||||
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.
|
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.
|
||||||
|
|||||||
Reference in New Issue
Block a user