arm64: Add support for CCmp
Also add a test for SUBS/ADDS with XZR, as CMP/CMN are aliases. Copyright (c) 2020, Arm Limited.
This commit is contained in:
committed by
Benjamin Bouvier
parent
9364eb1d98
commit
3638f8a764
@@ -525,4 +525,11 @@ impl InstSize {
|
|||||||
InstSize::Size64
|
InstSize::Size64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sf_bit(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
InstSize::Size32 => 0,
|
||||||
|
InstSize::Size64 => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,6 +257,15 @@ fn enc_cset(rd: Writable<Reg>, cond: Cond) -> u32 {
|
|||||||
| (cond.invert().bits() << 12)
|
| (cond.invert().bits() << 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enc_ccmp_imm(size: InstSize, rn: Reg, imm: UImm5, nzcv: NZCV, cond: Cond) -> u32 {
|
||||||
|
0b0_1_1_11010010_00000_0000_10_00000_0_0000
|
||||||
|
| size.sf_bit() << 31
|
||||||
|
| imm.bits() << 16
|
||||||
|
| cond.bits() << 12
|
||||||
|
| machreg_to_gpr(rn) << 5
|
||||||
|
| nzcv.bits()
|
||||||
|
}
|
||||||
|
|
||||||
fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
|
fn enc_vecmov(is_16b: bool, rd: Writable<Reg>, rn: Reg) -> u32 {
|
||||||
debug_assert!(!is_16b); // to be supported later.
|
debug_assert!(!is_16b); // to be supported later.
|
||||||
0b00001110_101_00000_00011_1_00000_00000
|
0b00001110_101_00000_00011_1_00000_00000
|
||||||
@@ -831,6 +840,15 @@ impl<O: MachSectionOutput> MachInstEmit<O> for Inst {
|
|||||||
&Inst::CSet { rd, cond } => {
|
&Inst::CSet { rd, cond } => {
|
||||||
sink.put4(enc_cset(rd, cond));
|
sink.put4(enc_cset(rd, cond));
|
||||||
}
|
}
|
||||||
|
&Inst::CCmpImm {
|
||||||
|
size,
|
||||||
|
rn,
|
||||||
|
imm,
|
||||||
|
nzcv,
|
||||||
|
cond,
|
||||||
|
} => {
|
||||||
|
sink.put4(enc_ccmp_imm(size, rn, imm, nzcv, cond));
|
||||||
|
}
|
||||||
&Inst::FpuMove64 { rd, rn } => {
|
&Inst::FpuMove64 { rd, rn } => {
|
||||||
sink.put4(enc_vecmov(/* 16b = */ false, rd, rn));
|
sink.put4(enc_vecmov(/* 16b = */ false, rd, rn));
|
||||||
}
|
}
|
||||||
@@ -1419,6 +1437,17 @@ mod test {
|
|||||||
"A400068A",
|
"A400068A",
|
||||||
"and x4, x5, x6",
|
"and x4, x5, x6",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AluRRR {
|
||||||
|
alu_op: ALUOp::SubS32,
|
||||||
|
rd: writable_zero_reg(),
|
||||||
|
rn: xreg(2),
|
||||||
|
rm: xreg(3),
|
||||||
|
},
|
||||||
|
"5F00036B",
|
||||||
|
// TODO: Display as cmp
|
||||||
|
"subs wzr, w2, w3",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::AluRRR {
|
Inst::AluRRR {
|
||||||
alu_op: ALUOp::SubS32,
|
alu_op: ALUOp::SubS32,
|
||||||
@@ -1459,6 +1488,17 @@ mod test {
|
|||||||
"A40006AB",
|
"A40006AB",
|
||||||
"adds x4, x5, x6",
|
"adds x4, x5, x6",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::AluRRImm12 {
|
||||||
|
alu_op: ALUOp::AddS64,
|
||||||
|
rd: writable_zero_reg(),
|
||||||
|
rn: xreg(5),
|
||||||
|
imm12: Imm12::maybe_from_u64(1).unwrap(),
|
||||||
|
},
|
||||||
|
"BF0400B1",
|
||||||
|
// TODO: Display as cmn.
|
||||||
|
"adds xzr, x5, #1",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::AluRRR {
|
Inst::AluRRR {
|
||||||
alu_op: ALUOp::SDiv64,
|
alu_op: ALUOp::SDiv64,
|
||||||
@@ -3053,6 +3093,28 @@ mod test {
|
|||||||
"EFB79F9A",
|
"EFB79F9A",
|
||||||
"cset x15, ge",
|
"cset x15, ge",
|
||||||
));
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::CCmpImm {
|
||||||
|
size: InstSize::Size64,
|
||||||
|
rn: xreg(22),
|
||||||
|
imm: UImm5::maybe_from_u8(5).unwrap(),
|
||||||
|
nzcv: NZCV::new(false, false, true, true),
|
||||||
|
cond: Cond::Eq,
|
||||||
|
},
|
||||||
|
"C30A45FA",
|
||||||
|
"ccmp x22, #5, #nzCV, eq",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::CCmpImm {
|
||||||
|
size: InstSize::Size32,
|
||||||
|
rn: xreg(3),
|
||||||
|
imm: UImm5::maybe_from_u8(30).unwrap(),
|
||||||
|
nzcv: NZCV::new(true, true, true, true),
|
||||||
|
cond: Cond::Gt,
|
||||||
|
},
|
||||||
|
"6FC85E7A",
|
||||||
|
"ccmp w3, #30, #NZCV, gt",
|
||||||
|
));
|
||||||
insns.push((
|
insns.push((
|
||||||
Inst::MovToVec64 {
|
Inst::MovToVec64 {
|
||||||
rd: writable_vreg(20),
|
rd: writable_vreg(20),
|
||||||
|
|||||||
@@ -11,6 +11,55 @@ use regalloc::RealRegUniverse;
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
|
||||||
|
/// An immediate that represents the NZCV flags.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct NZCV {
|
||||||
|
/// The negative condition flag.
|
||||||
|
n: bool,
|
||||||
|
/// The zero condition flag.
|
||||||
|
z: bool,
|
||||||
|
/// The carry condition flag.
|
||||||
|
c: bool,
|
||||||
|
/// The overflow condition flag.
|
||||||
|
v: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NZCV {
|
||||||
|
pub fn new(n: bool, z: bool, c: bool, v: bool) -> NZCV {
|
||||||
|
NZCV { n, z, c, v }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bits for encoding.
|
||||||
|
pub fn bits(&self) -> u32 {
|
||||||
|
(u32::from(self.n) << 3)
|
||||||
|
| (u32::from(self.z) << 2)
|
||||||
|
| (u32::from(self.c) << 1)
|
||||||
|
| u32::from(self.v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An unsigned 5-bit immediate.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct UImm5 {
|
||||||
|
/// The value.
|
||||||
|
value: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UImm5 {
|
||||||
|
pub fn maybe_from_u8(value: u8) -> Option<UImm5> {
|
||||||
|
if value < 32 {
|
||||||
|
Some(UImm5 { value })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bits for encoding.
|
||||||
|
pub fn bits(&self) -> u32 {
|
||||||
|
u32::from(self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A signed, scaled 7-bit offset.
|
/// A signed, scaled 7-bit offset.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct SImm7Scaled {
|
pub struct SImm7Scaled {
|
||||||
@@ -483,6 +532,25 @@ impl MoveWideConst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShowWithRRU for NZCV {
|
||||||
|
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||||
|
let fmt = |c: char, v| if v { c.to_ascii_uppercase() } else { c };
|
||||||
|
format!(
|
||||||
|
"#{}{}{}{}",
|
||||||
|
fmt('n', self.n),
|
||||||
|
fmt('z', self.z),
|
||||||
|
fmt('c', self.c),
|
||||||
|
fmt('v', self.v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShowWithRRU for UImm5 {
|
||||||
|
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||||
|
format!("#{}", self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ShowWithRRU for Imm12 {
|
impl ShowWithRRU for Imm12 {
|
||||||
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String {
|
||||||
let shift = if self.shift12 { 12 } else { 0 };
|
let shift = if self.shift12 { 12 } else { 0 };
|
||||||
|
|||||||
@@ -436,6 +436,15 @@ pub enum Inst {
|
|||||||
cond: Cond,
|
cond: Cond,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A conditional comparison with an immediate.
|
||||||
|
CCmpImm {
|
||||||
|
size: InstSize,
|
||||||
|
rn: Reg,
|
||||||
|
imm: UImm5,
|
||||||
|
nzcv: NZCV,
|
||||||
|
cond: Cond,
|
||||||
|
},
|
||||||
|
|
||||||
/// FPU move. Note that this is distinct from a vector-register
|
/// FPU move. Note that this is distinct from a vector-register
|
||||||
/// move; moving just 64 bits seems to be significantly faster.
|
/// move; moving just 64 bits seems to be significantly faster.
|
||||||
FpuMove64 {
|
FpuMove64 {
|
||||||
@@ -958,6 +967,9 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
&Inst::CSet { rd, .. } => {
|
&Inst::CSet { rd, .. } => {
|
||||||
collector.add_def(rd);
|
collector.add_def(rd);
|
||||||
}
|
}
|
||||||
|
&Inst::CCmpImm { rn, .. } => {
|
||||||
|
collector.add_use(rn);
|
||||||
|
}
|
||||||
&Inst::FpuMove64 { rd, rn } => {
|
&Inst::FpuMove64 { rd, rn } => {
|
||||||
collector.add_def(rd);
|
collector.add_def(rd);
|
||||||
collector.add_use(rn);
|
collector.add_use(rn);
|
||||||
@@ -1388,6 +1400,9 @@ fn aarch64_map_regs(
|
|||||||
&mut Inst::CSet { ref mut rd, .. } => {
|
&mut Inst::CSet { ref mut rd, .. } => {
|
||||||
map_wr(d, rd);
|
map_wr(d, rd);
|
||||||
}
|
}
|
||||||
|
&mut Inst::CCmpImm { ref mut rn, .. } => {
|
||||||
|
map(u, rn);
|
||||||
|
}
|
||||||
&mut Inst::FpuMove64 {
|
&mut Inst::FpuMove64 {
|
||||||
ref mut rd,
|
ref mut rd,
|
||||||
ref mut rn,
|
ref mut rn,
|
||||||
@@ -2177,6 +2192,19 @@ impl ShowWithRRU for Inst {
|
|||||||
let cond = cond.show_rru(mb_rru);
|
let cond = cond.show_rru(mb_rru);
|
||||||
format!("cset {}, {}", rd, cond)
|
format!("cset {}, {}", rd, cond)
|
||||||
}
|
}
|
||||||
|
&Inst::CCmpImm {
|
||||||
|
size,
|
||||||
|
rn,
|
||||||
|
imm,
|
||||||
|
nzcv,
|
||||||
|
cond,
|
||||||
|
} => {
|
||||||
|
let rn = show_ireg_sized(rn, mb_rru, size);
|
||||||
|
let imm = imm.show_rru(mb_rru);
|
||||||
|
let nzcv = nzcv.show_rru(mb_rru);
|
||||||
|
let cond = cond.show_rru(mb_rru);
|
||||||
|
format!("ccmp {}, {}, {}, {}", rn, imm, nzcv, cond)
|
||||||
|
}
|
||||||
&Inst::FpuMove64 { rd, rn } => {
|
&Inst::FpuMove64 { rd, rn } => {
|
||||||
let rd = rd.to_reg().show_rru(mb_rru);
|
let rd = rd.to_reg().show_rru(mb_rru);
|
||||||
let rn = rn.show_rru(mb_rru);
|
let rn = rn.show_rru(mb_rru);
|
||||||
|
|||||||
Reference in New Issue
Block a user