use crate::isa::arm32::inst::*;
use regalloc::{PrettyPrint, RealRegUniverse, Reg};
use std::string::String;
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum ShiftOp {
LSL = 0b00,
LSR = 0b01,
ASR = 0b10,
ROR = 0b11,
}
impl ShiftOp {
pub fn bits(self) -> u8 {
self as u8
}
}
#[derive(Clone, Copy, Debug)]
pub struct ShiftOpShiftImm(u8);
impl ShiftOpShiftImm {
pub const MAX_SHIFT: u32 = 31;
pub fn maybe_from_shift(shift: u32) -> Option<ShiftOpShiftImm> {
if shift <= Self::MAX_SHIFT {
Some(ShiftOpShiftImm(shift as u8))
} else {
None
}
}
pub fn value(self) -> u8 {
self.0
}
}
#[derive(Clone, Debug)]
pub struct ShiftOpAndAmt {
op: ShiftOp,
shift: ShiftOpShiftImm,
}
impl ShiftOpAndAmt {
pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt {
ShiftOpAndAmt { op, shift }
}
pub fn op(&self) -> ShiftOp {
self.op
}
pub fn amt(&self) -> ShiftOpShiftImm {
self.shift
}
}
#[derive(Clone, Copy, Debug)]
pub struct UImm8 {
value: u8,
}
impl UImm8 {
pub fn maybe_from_i64(value: i64) -> Option<UImm8> {
if 0 <= value && value < (1 << 8) {
Some(UImm8 { value: value as u8 })
} else {
None
}
}
pub fn bits(&self) -> u32 {
u32::from(self.value)
}
}
#[derive(Clone, Copy, Debug)]
pub struct UImm12 {
value: u16,
}
impl UImm12 {
pub fn maybe_from_i64(value: i64) -> Option<UImm12> {
if 0 <= value && value < (1 << 12) {
Some(UImm12 {
value: value as u16,
})
} else {
None
}
}
pub fn bits(&self) -> u32 {
u32::from(self.value)
}
}
#[derive(Clone, Debug)]
pub enum AMode {
RegReg(Reg, Reg, u8),
RegOffset12(Reg, UImm12),
PCRel(i32),
RegOffset(Reg, i64),
SPOffset(i64, Type),
FPOffset(i64, Type),
NominalSPOffset(i64, Type),
}
impl AMode {
pub fn reg_plus_reg(reg1: Reg, reg2: Reg, shift_amt: u8) -> AMode {
assert!(shift_amt <= 3);
AMode::RegReg(reg1, reg2, shift_amt)
}
pub fn reg_plus_imm(reg: Reg, offset: i64) -> AMode {
AMode::RegOffset(reg, offset)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum Cond {
Eq = 0,
Ne = 1,
Hs = 2,
Lo = 3,
Mi = 4,
Pl = 5,
Vs = 6,
Vc = 7,
Hi = 8,
Ls = 9,
Ge = 10,
Lt = 11,
Gt = 12,
Le = 13,
Al = 14,
}
impl Cond {
pub fn invert(self) -> Cond {
match self {
Cond::Eq => Cond::Ne,
Cond::Ne => Cond::Eq,
Cond::Hs => Cond::Lo,
Cond::Lo => Cond::Hs,
Cond::Mi => Cond::Pl,
Cond::Pl => Cond::Mi,
Cond::Vs => Cond::Vc,
Cond::Vc => Cond::Vs,
Cond::Hi => Cond::Ls,
Cond::Ls => Cond::Hi,
Cond::Ge => Cond::Lt,
Cond::Lt => Cond::Ge,
Cond::Gt => Cond::Le,
Cond::Le => Cond::Gt,
Cond::Al => panic!("Cannot inverse {:?} condition", self),
}
}
pub fn bits(self) -> u16 {
self as u16
}
}
#[derive(Clone, Copy, Debug)]
pub enum BranchTarget {
Label(MachLabel),
ResolvedOffset(i32),
}
impl BranchTarget {
pub fn as_label(self) -> Option<MachLabel> {
match self {
BranchTarget::Label(l) => Some(l),
_ => None,
}
}
fn as_offset(self, inst_16_bit: bool) -> i32 {
match self {
BranchTarget::ResolvedOffset(off) => {
if inst_16_bit {
(off - 2) >> 1
} else {
off >> 1
}
}
_ => 0,
}
}
pub fn as_off24(self) -> u32 {
let off = self.as_offset(false);
assert!(off < (1 << 24));
assert!(off >= -(1 << 24));
(off as u32) & ((1 << 24) - 1)
}
pub fn as_off20(self) -> u32 {
let off = self.as_offset(false);
assert!(off < (1 << 20));
assert!(off >= -(1 << 20));
(off as u32) & ((1 << 20) - 1)
}
}
impl PrettyPrint for ShiftOpAndAmt {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
let op = match self.op() {
ShiftOp::LSL => "lsl",
ShiftOp::LSR => "lsr",
ShiftOp::ASR => "asr",
ShiftOp::ROR => "ror",
};
format!("{} #{}", op, self.amt().value())
}
}
impl PrettyPrint for UImm8 {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
format!("#{}", self.value)
}
}
impl PrettyPrint for UImm12 {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
format!("#{}", self.value)
}
}
impl PrettyPrint for AMode {
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
match self {
&AMode::RegReg(rn, rm, imm2) => {
let shift = if imm2 != 0 {
format!(", lsl #{}", imm2)
} else {
"".to_string()
};
format!(
"[{}, {}{}]",
rn.show_rru(mb_rru),
rm.show_rru(mb_rru),
shift
)
}
&AMode::RegOffset12(rn, off) => {
format!("[{}, {}]", rn.show_rru(mb_rru), off.show_rru(mb_rru))
}
&AMode::PCRel(off) => format!("[pc, #{}]", off),
&AMode::RegOffset(..)
| &AMode::SPOffset(..)
| &AMode::FPOffset(..)
| &AMode::NominalSPOffset(..) => panic!("unexpected mem mode"),
}
}
}
impl PrettyPrint for Cond {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
let mut s = format!("{:?}", self);
s.make_ascii_lowercase();
s
}
}
impl PrettyPrint for BranchTarget {
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
match self {
&BranchTarget::Label(label) => format!("label{:?}", label.get()),
&BranchTarget::ResolvedOffset(off) => format!("{}", off),
}
}
}