use crate::binemit::CodeOffset;
use crate::ir::{Function, Inst, ValueLoc};
use crate::isa::{RegClass, RegUnit};
use crate::regalloc::RegDiversions;
#[derive(PartialEq, Debug)]
pub struct OperandConstraint {
pub kind: ConstraintKind,
pub regclass: RegClass,
}
impl OperandConstraint {
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) | ConstraintKind::FixedTied(reg) => {
loc == ValueLoc::Reg(reg) && self.regclass.contains(reg)
}
ConstraintKind::Stack => {
if let ValueLoc::Stack(_) = loc {
true
} else {
false
}
}
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ConstraintKind {
Reg,
FixedReg(RegUnit),
Tied(u8),
FixedTied(RegUnit),
Stack,
}
#[derive(PartialEq, Clone)]
pub struct RecipeConstraints {
pub ins: &'static [OperandConstraint],
pub outs: &'static [OperandConstraint],
pub fixed_ins: bool,
pub fixed_outs: bool,
pub tied_ops: bool,
pub clobbers_flags: bool,
}
impl RecipeConstraints {
pub fn satisfied(&self, inst: Inst, divert: &RegDiversions, func: &Function) -> bool {
for (&arg, constraint) in func.dfg.inst_args(inst).iter().zip(self.ins) {
let loc = divert.get(arg, &func.locations);
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 = divert.get(arg, &func.locations);
if !constraint.satisfied(loc) {
return false;
}
}
true
}
}
#[derive(Clone, Copy, Debug)]
pub struct BranchRange {
pub origin: u8,
pub bits: u8,
}
impl BranchRange {
pub fn contains(self, branch: CodeOffset, dest: CodeOffset) -> bool {
let d = dest.wrapping_sub(branch + CodeOffset::from(self.origin)) as i32;
let s = 32 - self.bits;
d == d << s >> s
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn branch_range() {
let t1 = BranchRange { origin: 4, bits: 9 };
assert!(t1.contains(0, 0));
assert!(t1.contains(0, 2));
assert!(t1.contains(2, 0));
assert!(t1.contains(1000, 1000));
assert!(t1.contains(1000, 1258));
assert!(!t1.contains(1000, 1260));
assert!(t1.contains(1000, 748));
assert!(!t1.contains(1000, 746));
}
}