cranelift: Add newtype wrappers for x64 register classes
This primary motivation of this large commit (apologies for its size!) is to
introduce `Gpr` and `Xmm` newtypes over `Reg`. This should help catch
difficult-to-diagnose register class mixup bugs in x64 lowerings.
But having a newtype for `Gpr` and `Xmm` themselves isn't enough to catch all of
our operand-with-wrong-register-class bugs, because about 50% of operands on x64
aren't just a register, but a register or memory address or even an
immediate! So we have `{Gpr,Xmm}Mem[Imm]` newtypes as well.
Unfortunately, `GprMem` et al can't be `enum`s and are therefore a little bit
noisier to work with from ISLE. They need to maintain the invariant that their
registers really are of the claimed register class, so they need to encapsulate
the inner data. If they exposed the underlying `enum` variants, then anyone
could just change register classes or construct a `GprMem` that holds an XMM
register, defeating the whole point of these newtypes. So when working with
these newtypes from ISLE, we rely on external constructors like `(gpr_to_gpr_mem
my_gpr)` instead of `(GprMem.Gpr my_gpr)`.
A bit of extra lines of code are included to add support for register mapping
for all of these newtypes as well. Ultimately this is all a bit wordier than I'd
hoped it would be when I first started authoring this commit, but I think it is
all worth it nonetheless!
In the process of adding these newtypes, I didn't want to have to update both
the ISLE `extern` type definition of `MInst` and the Rust definition, so I move
the definition fully into ISLE, similar as aarch64.
Finally, this process isn't complete. I've introduced the newtypes here, and
I've made most XMM-using instructions switch from `Reg` to `Xmm`, as well as
register class-converting instructions, but I haven't moved all of the GPR-using
instructions over to the newtypes yet. I figured this commit was big enough as
it was, and I can continue the adoption of these newtypes in follow up commits.
Part of #3685.
This commit is contained in:
@@ -13,6 +13,309 @@ use smallvec::{smallvec, SmallVec};
|
||||
use std::fmt;
|
||||
use std::string::String;
|
||||
|
||||
/// An extenstion trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`.
|
||||
pub trait ToWritableReg {
|
||||
fn to_writable_reg(&self) -> Writable<Reg>;
|
||||
}
|
||||
|
||||
/// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`.
|
||||
pub trait FromWritableReg: Sized {
|
||||
fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// An extension trait for mapping register uses on `{Xmm,Gpr}`.
|
||||
pub trait MapUseExt {
|
||||
fn map_use<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper;
|
||||
}
|
||||
|
||||
/// An extension trait for mapping register mods and defs on
|
||||
/// `Writable{Xmm,Gpr}`.
|
||||
pub trait MapDefModExt {
|
||||
fn map_def<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper;
|
||||
|
||||
fn map_mod<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper;
|
||||
}
|
||||
|
||||
/// A macro for defining a newtype of `Reg` that enforces some invariant about
|
||||
/// the wrapped `Reg` (such as that it is of a particular register class).
|
||||
macro_rules! newtype_of_reg {
|
||||
(
|
||||
$newtype_reg:ident,
|
||||
$newtype_writable_reg:ident,
|
||||
$newtype_reg_mem:ident,
|
||||
$newtype_reg_mem_imm:ident,
|
||||
|$check_reg:ident| $check:expr
|
||||
) => {
|
||||
/// A newtype wrapper around `Reg`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct $newtype_reg(Reg);
|
||||
|
||||
impl PartialEq<Reg> for $newtype_reg {
|
||||
fn eq(&self, other: &Reg) -> bool {
|
||||
self.0 == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$newtype_reg> for Reg {
|
||||
fn from(r: $newtype_reg) -> Self {
|
||||
r.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for $newtype_reg {
|
||||
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
self.0.show_rru(mb_rru)
|
||||
}
|
||||
}
|
||||
|
||||
impl $newtype_reg {
|
||||
/// Create this newtype from the given register, or return `None` if the register
|
||||
/// is not a valid instance of this newtype.
|
||||
pub fn new($check_reg: Reg) -> Option<Self> {
|
||||
if $check {
|
||||
Some(Self($check_reg))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get this newtype's underlying `Reg`.
|
||||
pub fn to_reg(self) -> Reg {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience impl so that people working with this newtype can use it
|
||||
// "just like" a plain `Reg`.
|
||||
//
|
||||
// NB: We cannot implement `DerefMut` because that would let people do
|
||||
// nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the
|
||||
// invariants that `Gpr` provides.
|
||||
impl std::ops::Deref for $newtype_reg {
|
||||
type Target = Reg;
|
||||
|
||||
fn deref(&self) -> &Reg {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl MapUseExt for $newtype_reg {
|
||||
fn map_use<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
let mut reg = self.0;
|
||||
mapper.map_use(&mut reg);
|
||||
debug_assert!({
|
||||
let $check_reg = reg;
|
||||
$check
|
||||
});
|
||||
*self = $newtype_reg(reg);
|
||||
}
|
||||
}
|
||||
|
||||
pub type $newtype_writable_reg = Writable<$newtype_reg>;
|
||||
|
||||
impl ToWritableReg for $newtype_writable_reg {
|
||||
fn to_writable_reg(&self) -> Writable<Reg> {
|
||||
Writable::from_reg(self.to_reg().to_reg())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWritableReg for $newtype_writable_reg {
|
||||
fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
|
||||
Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl MapDefModExt for $newtype_writable_reg {
|
||||
fn map_def<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
let mut reg = self.to_writable_reg();
|
||||
mapper.map_def(&mut reg);
|
||||
debug_assert!({
|
||||
let $check_reg = reg.to_reg();
|
||||
$check
|
||||
});
|
||||
*self = Writable::from_reg($newtype_reg(reg.to_reg()));
|
||||
}
|
||||
|
||||
fn map_mod<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
let mut reg = self.to_writable_reg();
|
||||
mapper.map_mod(&mut reg);
|
||||
debug_assert!({
|
||||
let $check_reg = reg.to_reg();
|
||||
$check
|
||||
});
|
||||
*self = Writable::from_reg($newtype_reg(reg.to_reg()));
|
||||
}
|
||||
}
|
||||
|
||||
/// A newtype wrapper around `RegMem` for general-purpose registers.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct $newtype_reg_mem(RegMem);
|
||||
|
||||
impl From<$newtype_reg_mem> for RegMem {
|
||||
fn from(rm: $newtype_reg_mem) -> Self {
|
||||
rm.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$newtype_reg> for $newtype_reg_mem {
|
||||
fn from(r: $newtype_reg) -> Self {
|
||||
$newtype_reg_mem(RegMem::reg(r.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl $newtype_reg_mem {
|
||||
/// Construct a `RegMem` newtype from the given `RegMem`, or return
|
||||
/// `None` if the `RegMem` is not a valid instance of this `RegMem`
|
||||
/// newtype.
|
||||
pub fn new(rm: RegMem) -> Option<Self> {
|
||||
match rm {
|
||||
RegMem::Mem { addr: _ } => Some(Self(rm)),
|
||||
RegMem::Reg { reg: $check_reg } if $check => Some(Self(rm)),
|
||||
RegMem::Reg { reg: _ } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this newtype into its underlying `RegMem`.
|
||||
pub fn to_reg_mem(self) -> RegMem {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by some newtypes and not others.
|
||||
pub fn map_uses<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
self.0.map_uses(mapper);
|
||||
debug_assert!(match self.0 {
|
||||
RegMem::Reg { reg: $check_reg } => $check,
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by some newtypes and not others.
|
||||
pub fn map_as_def<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
self.0.map_as_def(mapper);
|
||||
debug_assert!(match self.0 {
|
||||
RegMem::Reg { reg: $check_reg } => $check,
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for $newtype_reg_mem {
|
||||
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
self.0.show_rru(mb_rru)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrintSized for $newtype_reg_mem {
|
||||
fn show_rru_sized(&self, mb_rru: Option<&RealRegUniverse>, size: u8) -> String {
|
||||
self.0.show_rru_sized(mb_rru, size)
|
||||
}
|
||||
}
|
||||
|
||||
/// A newtype wrapper around `RegMemImm`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct $newtype_reg_mem_imm(RegMemImm);
|
||||
|
||||
impl From<$newtype_reg_mem_imm> for RegMemImm {
|
||||
fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
|
||||
rmi.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$newtype_reg> for $newtype_reg_mem_imm {
|
||||
fn from(r: $newtype_reg) -> Self {
|
||||
$newtype_reg_mem_imm(RegMemImm::reg(r.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl $newtype_reg_mem_imm {
|
||||
/// Construct this newtype from the given `RegMemImm`, or return
|
||||
/// `None` if the `RegMemImm` is not a valid instance of this
|
||||
/// newtype.
|
||||
pub fn new(rmi: RegMemImm) -> Option<Self> {
|
||||
match rmi {
|
||||
RegMemImm::Imm { .. } => Some(Self(rmi)),
|
||||
RegMemImm::Mem { addr: _ } => Some(Self(rmi)),
|
||||
RegMemImm::Reg { reg: $check_reg } if $check => Some(Self(rmi)),
|
||||
RegMemImm::Reg { reg: _ } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this newtype into its underlying `RegMemImm`.
|
||||
#[allow(dead_code)] // Used by some newtypes and not others.
|
||||
pub fn to_reg_mem_imm(self) -> RegMemImm {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by some newtypes and not others.
|
||||
pub fn map_uses<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
self.0.map_uses(mapper);
|
||||
debug_assert!(match self.0 {
|
||||
RegMemImm::Reg { reg: $check_reg } => $check,
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Used by some newtypes and not others.
|
||||
pub fn map_as_def<RM>(&mut self, mapper: &RM)
|
||||
where
|
||||
RM: RegMapper,
|
||||
{
|
||||
self.0.map_as_def(mapper);
|
||||
debug_assert!(match self.0 {
|
||||
RegMemImm::Reg { reg: $check_reg } => $check,
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrint for $newtype_reg_mem_imm {
|
||||
fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String {
|
||||
self.0.show_rru(mb_rru)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyPrintSized for $newtype_reg_mem_imm {
|
||||
fn show_rru_sized(&self, mb_rru: Option<&RealRegUniverse>, size: u8) -> String {
|
||||
self.0.show_rru_sized(mb_rru, size)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Define a newtype of `Reg` for general-purpose registers.
|
||||
newtype_of_reg!(Gpr, WritableGpr, GprMem, GprMemImm, |reg| {
|
||||
reg.get_class() == RegClass::I64
|
||||
});
|
||||
|
||||
// Define a newtype of `Reg` for XMM registers.
|
||||
newtype_of_reg!(Xmm, WritableXmm, XmmMem, XmmMemImm, |reg| {
|
||||
reg.get_class() == RegClass::V128
|
||||
});
|
||||
|
||||
/// A possible addressing mode (amode) that can be used in instructions.
|
||||
/// These denote a 64-bit value only.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -27,8 +330,8 @@ pub enum Amode {
|
||||
/// sign-extend-32-to-64(Immediate) + Register1 + (Register2 << Shift)
|
||||
ImmRegRegShift {
|
||||
simm32: u32,
|
||||
base: Reg,
|
||||
index: Reg,
|
||||
base: Gpr,
|
||||
index: Gpr,
|
||||
shift: u8, /* 0 .. 3 only */
|
||||
flags: MemFlags,
|
||||
},
|
||||
@@ -48,7 +351,7 @@ impl Amode {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn imm_reg_reg_shift(simm32: u32, base: Reg, index: Reg, shift: u8) -> Self {
|
||||
pub(crate) fn imm_reg_reg_shift(simm32: u32, base: Gpr, index: Gpr, shift: u8) -> Self {
|
||||
debug_assert!(base.get_class() == RegClass::I64);
|
||||
debug_assert!(index.get_class() == RegClass::I64);
|
||||
debug_assert!(shift <= 3);
|
||||
@@ -96,8 +399,8 @@ impl Amode {
|
||||
collector.add_use(*base);
|
||||
}
|
||||
Amode::ImmRegRegShift { base, index, .. } => {
|
||||
collector.add_use(*base);
|
||||
collector.add_use(*index);
|
||||
collector.add_use(base.to_reg());
|
||||
collector.add_use(index.to_reg());
|
||||
}
|
||||
Amode::RipRelative { .. } => {
|
||||
// RIP isn't involved in regalloc.
|
||||
@@ -225,7 +528,7 @@ impl PrettyPrint for SyntheticAmode {
|
||||
/// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only
|
||||
/// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by
|
||||
/// `simm32` is its sign-extension out to 64 bits.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RegMemImm {
|
||||
Reg { reg: Reg },
|
||||
Mem { addr: SyntheticAmode },
|
||||
|
||||
@@ -298,14 +298,14 @@ pub(crate) fn emit(
|
||||
Popcnt => (0x0fb8, 2),
|
||||
};
|
||||
|
||||
match src {
|
||||
match src.clone().into() {
|
||||
RegMem::Reg { reg: src } => emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
dst.to_reg(),
|
||||
*src,
|
||||
dst.to_reg().to_reg(),
|
||||
src,
|
||||
rex_flags,
|
||||
),
|
||||
RegMem::Mem { addr: src } => {
|
||||
@@ -317,7 +317,7 @@ pub(crate) fn emit(
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
dst.to_reg(),
|
||||
dst.to_reg().to_reg(),
|
||||
&amode,
|
||||
rex_flags,
|
||||
);
|
||||
@@ -327,7 +327,7 @@ pub(crate) fn emit(
|
||||
|
||||
Inst::Not { size, src, dst } => {
|
||||
debug_assert_eq!(*src, dst.to_reg());
|
||||
let rex_flags = RexFlags::from((*size, dst.to_reg()));
|
||||
let rex_flags = RexFlags::from((*size, dst.to_writable_reg().to_reg()));
|
||||
let (opcode, prefix) = match size {
|
||||
OperandSize::Size8 => (0xF6, LegacyPrefixes::None),
|
||||
OperandSize::Size16 => (0xF7, LegacyPrefixes::_66),
|
||||
@@ -342,7 +342,7 @@ pub(crate) fn emit(
|
||||
|
||||
Inst::Neg { size, src, dst } => {
|
||||
debug_assert_eq!(*src, dst.to_reg());
|
||||
let rex_flags = RexFlags::from((*size, dst.to_reg()));
|
||||
let rex_flags = RexFlags::from((*size, dst.to_writable_reg().to_reg()));
|
||||
let (opcode, prefix) = match size {
|
||||
OperandSize::Size8 => (0xF6, LegacyPrefixes::None),
|
||||
OperandSize::Size16 => (0xF7, LegacyPrefixes::_66),
|
||||
@@ -728,7 +728,7 @@ pub(crate) fn emit(
|
||||
LegacyPrefixes::None,
|
||||
0x8D,
|
||||
1,
|
||||
dst.to_reg(),
|
||||
dst.to_reg().to_reg(),
|
||||
&amode,
|
||||
RexFlags::set_w(),
|
||||
);
|
||||
@@ -884,6 +884,7 @@ pub(crate) fn emit(
|
||||
debug_assert_eq!(*src1, dst.to_reg());
|
||||
let rex = RexFlags::clear_w();
|
||||
let prefix = LegacyPrefixes::_66;
|
||||
let src2 = src2.clone().to_reg_mem_imm();
|
||||
if let RegMemImm::Imm { simm32 } = src2 {
|
||||
let (opcode_bytes, reg_digit) = match opcode {
|
||||
SseOpcode::Psllw => (0x0F71, 6),
|
||||
@@ -898,7 +899,7 @@ pub(crate) fn emit(
|
||||
};
|
||||
let dst_enc = reg_enc(dst.to_reg());
|
||||
emit_std_enc_enc(sink, prefix, opcode_bytes, 2, reg_digit, dst_enc, rex);
|
||||
let imm = (*simm32)
|
||||
let imm = (simm32)
|
||||
.try_into()
|
||||
.expect("the immediate must be convertible to a u8");
|
||||
sink.put1(imm);
|
||||
@@ -917,7 +918,15 @@ pub(crate) fn emit(
|
||||
|
||||
match src2 {
|
||||
RegMemImm::Reg { reg } => {
|
||||
emit_std_reg_reg(sink, prefix, opcode_bytes, 2, dst.to_reg(), *reg, rex);
|
||||
emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode_bytes,
|
||||
2,
|
||||
dst.to_reg().to_reg(),
|
||||
reg,
|
||||
rex,
|
||||
);
|
||||
}
|
||||
RegMemImm::Mem { addr } => {
|
||||
let addr = &addr.finalize(state, sink);
|
||||
@@ -928,7 +937,7 @@ pub(crate) fn emit(
|
||||
prefix,
|
||||
opcode_bytes,
|
||||
2,
|
||||
dst.to_reg(),
|
||||
dst.to_reg().to_reg(),
|
||||
addr,
|
||||
rex,
|
||||
);
|
||||
@@ -1335,7 +1344,12 @@ pub(crate) fn emit(
|
||||
// might be negative; use a sign-extension.
|
||||
let inst = Inst::movsx_rm_r(
|
||||
ExtMode::LQ,
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(0, tmp1.to_reg(), tmp2.to_reg(), 2)),
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
0,
|
||||
Gpr::new(tmp1.to_reg()).unwrap(),
|
||||
Gpr::new(tmp2.to_reg()).unwrap(),
|
||||
2,
|
||||
)),
|
||||
*tmp2,
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
@@ -1424,15 +1438,15 @@ pub(crate) fn emit(
|
||||
_ => unimplemented!("Opcode {:?} not implemented", op),
|
||||
};
|
||||
|
||||
match src_e {
|
||||
match src_e.clone().to_reg_mem() {
|
||||
RegMem::Reg { reg: reg_e } => {
|
||||
emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
reg_g.to_reg(),
|
||||
*reg_e,
|
||||
reg_g.to_reg().to_reg(),
|
||||
reg_e,
|
||||
rex,
|
||||
);
|
||||
}
|
||||
@@ -1445,7 +1459,7 @@ pub(crate) fn emit(
|
||||
prefix,
|
||||
opcode,
|
||||
num_opcodes,
|
||||
reg_g.to_reg(),
|
||||
reg_g.to_reg().to_reg(),
|
||||
addr,
|
||||
rex,
|
||||
);
|
||||
@@ -1460,7 +1474,7 @@ pub(crate) fn emit(
|
||||
Avx512Opcode::Vpopcntb => (LegacyPrefixes::_66, OpcodeMap::_0F38, false, 0x54),
|
||||
_ => unimplemented!("Opcode {:?} not implemented", op),
|
||||
};
|
||||
match src {
|
||||
match src.clone().to_reg_mem() {
|
||||
RegMem::Reg { reg: src } => EvexInstruction::new()
|
||||
.length(EvexVectorLength::V128)
|
||||
.prefix(prefix)
|
||||
@@ -1587,9 +1601,17 @@ pub(crate) fn emit(
|
||||
_ => unimplemented!("Opcode {:?} not implemented", op),
|
||||
};
|
||||
|
||||
match src_e {
|
||||
match src_e.clone().to_reg_mem() {
|
||||
RegMem::Reg { reg: reg_e } => {
|
||||
emit_std_reg_reg(sink, prefix, opcode, length, reg_g.to_reg(), *reg_e, rex);
|
||||
emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
length,
|
||||
reg_g.to_reg().to_reg(),
|
||||
reg_e,
|
||||
rex,
|
||||
);
|
||||
}
|
||||
RegMem::Mem { addr } => {
|
||||
let addr = &addr.finalize(state, sink);
|
||||
@@ -1600,7 +1622,7 @@ pub(crate) fn emit(
|
||||
prefix,
|
||||
opcode,
|
||||
length,
|
||||
reg_g.to_reg(),
|
||||
reg_g.to_reg().to_reg(),
|
||||
addr,
|
||||
rex,
|
||||
);
|
||||
@@ -1619,7 +1641,7 @@ pub(crate) fn emit(
|
||||
Avx512Opcode::Vpmullq => (true, 0x40),
|
||||
_ => unimplemented!("Opcode {:?} not implemented", op),
|
||||
};
|
||||
match src1 {
|
||||
match src1.clone().to_reg_mem() {
|
||||
RegMem::Reg { reg: src } => EvexInstruction::new()
|
||||
.length(EvexVectorLength::V128)
|
||||
.prefix(LegacyPrefixes::_66)
|
||||
@@ -1845,9 +1867,9 @@ pub(crate) fn emit(
|
||||
};
|
||||
let rex = RexFlags::from(*dst_size);
|
||||
let (src, dst) = if dst_first {
|
||||
(dst.to_reg(), *src)
|
||||
(dst.to_reg().to_reg(), src.to_reg())
|
||||
} else {
|
||||
(*src, dst.to_reg())
|
||||
(src.to_reg(), dst.to_reg().to_reg())
|
||||
};
|
||||
|
||||
emit_std_reg_reg(sink, prefix, opcode, 2, src, dst, rex);
|
||||
@@ -1870,7 +1892,15 @@ pub(crate) fn emit(
|
||||
let rex = RexFlags::from(*src_size);
|
||||
match src_e {
|
||||
RegMem::Reg { reg: reg_e } => {
|
||||
emit_std_reg_reg(sink, prefix, opcode, 2, reg_g.to_reg(), *reg_e, rex);
|
||||
emit_std_reg_reg(
|
||||
sink,
|
||||
prefix,
|
||||
opcode,
|
||||
2,
|
||||
reg_g.to_reg().to_reg(),
|
||||
*reg_e,
|
||||
rex,
|
||||
);
|
||||
}
|
||||
RegMem::Mem { addr } => {
|
||||
let addr = &addr.finalize(state, sink);
|
||||
@@ -1881,7 +1911,7 @@ pub(crate) fn emit(
|
||||
prefix,
|
||||
opcode,
|
||||
2,
|
||||
reg_g.to_reg(),
|
||||
reg_g.to_reg().to_reg(),
|
||||
addr,
|
||||
rex,
|
||||
);
|
||||
@@ -1950,7 +1980,11 @@ pub(crate) fn emit(
|
||||
// If x seen as a signed int64 is not negative, a signed-conversion will do the right
|
||||
// thing.
|
||||
// TODO use tst src, src here.
|
||||
let inst = Inst::cmp_rmi_r(OperandSize::Size64, RegMemImm::imm(0), src.to_reg());
|
||||
let inst = Inst::cmp_rmi_r(
|
||||
OperandSize::Size64,
|
||||
RegMemImm::imm(0),
|
||||
src.to_reg().to_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
one_way_jmp(sink, CC::L, handle_negative);
|
||||
@@ -1961,8 +1995,8 @@ pub(crate) fn emit(
|
||||
sink,
|
||||
info,
|
||||
state,
|
||||
src.to_reg(),
|
||||
*dst,
|
||||
src.to_reg().to_reg(),
|
||||
dst.to_writable_reg(),
|
||||
*dst_size == OperandSize::Size64,
|
||||
);
|
||||
|
||||
@@ -1973,7 +2007,11 @@ pub(crate) fn emit(
|
||||
|
||||
// Divide x by two to get it in range for the signed conversion, keep the LSB, and
|
||||
// scale it back up on the FP side.
|
||||
let inst = Inst::gen_move(*tmp_gpr1, src.to_reg(), types::I64);
|
||||
let inst = Inst::gen_move(
|
||||
tmp_gpr1.to_writable_reg(),
|
||||
src.to_reg().to_reg(),
|
||||
types::I64,
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
// tmp_gpr1 := src >> 1
|
||||
@@ -1981,26 +2019,30 @@ pub(crate) fn emit(
|
||||
OperandSize::Size64,
|
||||
ShiftKind::ShiftRightLogical,
|
||||
Some(1),
|
||||
*tmp_gpr1,
|
||||
tmp_gpr1.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::gen_move(*tmp_gpr2, src.to_reg(), types::I64);
|
||||
let inst = Inst::gen_move(
|
||||
tmp_gpr2.to_writable_reg(),
|
||||
src.to_reg().to_reg(),
|
||||
types::I64,
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::alu_rmi_r(
|
||||
OperandSize::Size64,
|
||||
AluRmiROpcode::And,
|
||||
RegMemImm::imm(1),
|
||||
*tmp_gpr2,
|
||||
tmp_gpr2.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::alu_rmi_r(
|
||||
OperandSize::Size64,
|
||||
AluRmiROpcode::Or,
|
||||
RegMemImm::reg(tmp_gpr1.to_reg()),
|
||||
*tmp_gpr2,
|
||||
RegMemImm::reg(tmp_gpr1.to_reg().to_reg()),
|
||||
tmp_gpr2.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
@@ -2008,8 +2050,8 @@ pub(crate) fn emit(
|
||||
sink,
|
||||
info,
|
||||
state,
|
||||
tmp_gpr2.to_reg(),
|
||||
*dst,
|
||||
tmp_gpr2.to_reg().to_reg(),
|
||||
dst.to_writable_reg(),
|
||||
*dst_size == OperandSize::Size64,
|
||||
);
|
||||
|
||||
@@ -2018,7 +2060,11 @@ pub(crate) fn emit(
|
||||
} else {
|
||||
SseOpcode::Addss
|
||||
};
|
||||
let inst = Inst::xmm_rm_r(add_op, RegMem::reg(dst.to_reg()), *dst);
|
||||
let inst = Inst::xmm_rm_r(
|
||||
add_op,
|
||||
RegMem::reg(dst.to_reg().to_reg()),
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
sink.bind_label(done);
|
||||
@@ -2091,18 +2137,18 @@ pub(crate) fn emit(
|
||||
let not_nan = sink.get_label();
|
||||
|
||||
// The truncation.
|
||||
let inst = Inst::xmm_to_gpr(trunc_op, src, *dst, *dst_size);
|
||||
let inst = Inst::xmm_to_gpr(trunc_op, src.to_reg(), dst.to_writable_reg(), *dst_size);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
// Compare against 1, in case of overflow the dst operand was INT_MIN.
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(1), dst.to_reg());
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(1), dst.to_reg().to_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
one_way_jmp(sink, CC::NO, done); // no overflow => done
|
||||
|
||||
// Check for NaN.
|
||||
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(src), src);
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(src.to_reg()), src.to_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
one_way_jmp(sink, CC::NP, not_nan); // go to not_nan if not a NaN
|
||||
@@ -2112,8 +2158,8 @@ pub(crate) fn emit(
|
||||
let inst = Inst::alu_rmi_r(
|
||||
*dst_size,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(dst.to_reg()),
|
||||
*dst,
|
||||
RegMemImm::reg(dst.to_reg().to_reg()),
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
@@ -2125,11 +2171,18 @@ pub(crate) fn emit(
|
||||
// If the input was positive, saturate to INT_MAX.
|
||||
|
||||
// Zero out tmp_xmm.
|
||||
let inst =
|
||||
Inst::xmm_rm_r(SseOpcode::Xorpd, RegMem::reg(tmp_xmm.to_reg()), *tmp_xmm);
|
||||
let inst = Inst::xmm_rm_r(
|
||||
SseOpcode::Xorpd,
|
||||
RegMem::reg(tmp_xmm.to_reg().to_reg()),
|
||||
tmp_xmm.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(src), tmp_xmm.to_reg());
|
||||
let inst = Inst::xmm_cmp_rm_r(
|
||||
cmp_op,
|
||||
RegMem::reg(src.to_reg()),
|
||||
tmp_xmm.to_reg().to_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
// Jump if >= to done.
|
||||
@@ -2137,10 +2190,14 @@ pub(crate) fn emit(
|
||||
|
||||
// Otherwise, put INT_MAX.
|
||||
if *dst_size == OperandSize::Size64 {
|
||||
let inst = Inst::imm(OperandSize::Size64, 0x7fffffffffffffff, *dst);
|
||||
let inst = Inst::imm(
|
||||
OperandSize::Size64,
|
||||
0x7fffffffffffffff,
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
} else {
|
||||
let inst = Inst::imm(OperandSize::Size32, 0x7fffffff, *dst);
|
||||
let inst = Inst::imm(OperandSize::Size32, 0x7fffffff, dst.to_writable_reg());
|
||||
inst.emit(sink, info, state);
|
||||
}
|
||||
} else {
|
||||
@@ -2162,7 +2219,8 @@ pub(crate) fn emit(
|
||||
match *src_size {
|
||||
OperandSize::Size32 => {
|
||||
let cst = Ieee32::pow2(output_bits - 1).neg().bits();
|
||||
let inst = Inst::imm(OperandSize::Size32, cst as u64, *tmp_gpr);
|
||||
let inst =
|
||||
Inst::imm(OperandSize::Size32, cst as u64, tmp_gpr.to_writable_reg());
|
||||
inst.emit(sink, info, state);
|
||||
}
|
||||
OperandSize::Size64 => {
|
||||
@@ -2174,17 +2232,26 @@ pub(crate) fn emit(
|
||||
} else {
|
||||
Ieee64::pow2(output_bits - 1).neg()
|
||||
};
|
||||
let inst = Inst::imm(OperandSize::Size64, cst.bits(), *tmp_gpr);
|
||||
let inst =
|
||||
Inst::imm(OperandSize::Size64, cst.bits(), tmp_gpr.to_writable_reg());
|
||||
inst.emit(sink, info, state);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let inst =
|
||||
Inst::gpr_to_xmm(cast_op, RegMem::reg(tmp_gpr.to_reg()), *src_size, *tmp_xmm);
|
||||
let inst = Inst::gpr_to_xmm(
|
||||
cast_op,
|
||||
RegMem::reg(tmp_gpr.to_reg().to_reg()),
|
||||
*src_size,
|
||||
tmp_xmm.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(tmp_xmm.to_reg()), src);
|
||||
let inst = Inst::xmm_cmp_rm_r(
|
||||
cmp_op,
|
||||
RegMem::reg(tmp_xmm.to_reg().to_reg()),
|
||||
src.to_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
// jump over trap if src >= or > threshold
|
||||
@@ -2198,11 +2265,18 @@ pub(crate) fn emit(
|
||||
sink.bind_label(check_positive);
|
||||
|
||||
// Zero out the tmp_xmm register.
|
||||
let inst =
|
||||
Inst::xmm_rm_r(SseOpcode::Xorpd, RegMem::reg(tmp_xmm.to_reg()), *tmp_xmm);
|
||||
let inst = Inst::xmm_rm_r(
|
||||
SseOpcode::Xorpd,
|
||||
RegMem::reg(tmp_xmm.to_reg().to_reg()),
|
||||
tmp_xmm.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(src), tmp_xmm.to_reg());
|
||||
let inst = Inst::xmm_cmp_rm_r(
|
||||
cmp_op,
|
||||
RegMem::reg(src.to_reg()),
|
||||
tmp_xmm.to_reg().to_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
one_way_jmp(sink, CC::NB, done); // jump over trap if 0 >= src
|
||||
@@ -2282,14 +2356,22 @@ pub(crate) fn emit(
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let inst = Inst::imm(*src_size, cst, *tmp_gpr);
|
||||
let inst = Inst::imm(*src_size, cst, tmp_gpr.to_writable_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst =
|
||||
Inst::gpr_to_xmm(cast_op, RegMem::reg(tmp_gpr.to_reg()), *src_size, *tmp_xmm);
|
||||
let inst = Inst::gpr_to_xmm(
|
||||
cast_op,
|
||||
RegMem::reg(tmp_gpr.to_reg().to_reg()),
|
||||
*src_size,
|
||||
tmp_xmm.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::xmm_cmp_rm_r(cmp_op, RegMem::reg(tmp_xmm.to_reg()), src.to_reg());
|
||||
let inst = Inst::xmm_cmp_rm_r(
|
||||
cmp_op,
|
||||
RegMem::reg(tmp_xmm.to_reg().to_reg()),
|
||||
src.to_reg().to_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let handle_large = sink.get_label();
|
||||
@@ -2303,8 +2385,8 @@ pub(crate) fn emit(
|
||||
let inst = Inst::alu_rmi_r(
|
||||
*dst_size,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(dst.to_reg()),
|
||||
*dst,
|
||||
RegMemImm::reg(dst.to_reg().to_reg()),
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
@@ -2321,10 +2403,15 @@ pub(crate) fn emit(
|
||||
// Actual truncation for small inputs: if the result is not positive, then we had an
|
||||
// overflow.
|
||||
|
||||
let inst = Inst::xmm_to_gpr(trunc_op, src.to_reg(), *dst, *dst_size);
|
||||
let inst = Inst::xmm_to_gpr(
|
||||
trunc_op,
|
||||
src.to_reg().to_reg(),
|
||||
dst.to_writable_reg(),
|
||||
*dst_size,
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg());
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg().to_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
one_way_jmp(sink, CC::NL, done); // if dst >= 0, jump to done
|
||||
@@ -2335,8 +2422,8 @@ pub(crate) fn emit(
|
||||
let inst = Inst::alu_rmi_r(
|
||||
*dst_size,
|
||||
AluRmiROpcode::Xor,
|
||||
RegMemImm::reg(dst.to_reg()),
|
||||
*dst,
|
||||
RegMemImm::reg(dst.to_reg().to_reg()),
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
@@ -2352,13 +2439,22 @@ pub(crate) fn emit(
|
||||
|
||||
sink.bind_label(handle_large);
|
||||
|
||||
let inst = Inst::xmm_rm_r(sub_op, RegMem::reg(tmp_xmm.to_reg()), *src);
|
||||
let inst = Inst::xmm_rm_r(
|
||||
sub_op,
|
||||
RegMem::reg(tmp_xmm.to_reg().to_reg()),
|
||||
src.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::xmm_to_gpr(trunc_op, src.to_reg(), *dst, *dst_size);
|
||||
let inst = Inst::xmm_to_gpr(
|
||||
trunc_op,
|
||||
src.to_reg().to_reg(),
|
||||
dst.to_writable_reg(),
|
||||
*dst_size,
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg());
|
||||
let inst = Inst::cmp_rmi_r(*dst_size, RegMemImm::imm(0), dst.to_reg().to_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let next_is_large = sink.get_label();
|
||||
@@ -2374,7 +2470,7 @@ pub(crate) fn emit(
|
||||
} else {
|
||||
u32::max_value() as u64
|
||||
},
|
||||
*dst,
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
@@ -2388,14 +2484,14 @@ pub(crate) fn emit(
|
||||
sink.bind_label(next_is_large);
|
||||
|
||||
if *dst_size == OperandSize::Size64 {
|
||||
let inst = Inst::imm(OperandSize::Size64, 1 << 63, *tmp_gpr);
|
||||
let inst = Inst::imm(OperandSize::Size64, 1 << 63, tmp_gpr.to_writable_reg());
|
||||
inst.emit(sink, info, state);
|
||||
|
||||
let inst = Inst::alu_rmi_r(
|
||||
OperandSize::Size64,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::reg(tmp_gpr.to_reg()),
|
||||
*dst,
|
||||
RegMemImm::reg(tmp_gpr.to_reg().to_reg()),
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
} else {
|
||||
@@ -2403,7 +2499,7 @@ pub(crate) fn emit(
|
||||
OperandSize::Size32,
|
||||
AluRmiROpcode::Add,
|
||||
RegMemImm::imm(1 << 31),
|
||||
*dst,
|
||||
dst.to_writable_reg(),
|
||||
);
|
||||
inst.emit(sink, info, state);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
use super::*;
|
||||
use crate::isa::x64;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
impl Inst {
|
||||
@@ -21,8 +22,8 @@ impl Inst {
|
||||
debug_assert_eq!(src.to_reg().get_class(), RegClass::I64);
|
||||
Inst::Neg {
|
||||
size,
|
||||
src: src.to_reg(),
|
||||
dst: src,
|
||||
src: Gpr::new(src.to_reg()).unwrap(),
|
||||
dst: WritableGpr::from_writable_reg(src).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,42 +694,66 @@ fn test_x64_emit() {
|
||||
//
|
||||
// Addr_IRRS, offset max simm8
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, rax, rax, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(rax).unwrap(), Gpr::new(rax).unwrap(), 0),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B5C007F",
|
||||
"movq 127(%rax,%rax,1), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, rdi, rax, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(rdi).unwrap(), Gpr::new(rax).unwrap(), 1),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B5C477F",
|
||||
"movq 127(%rdi,%rax,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, r8, rax, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(r8).unwrap(), Gpr::new(rax).unwrap(), 2),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B5C807F",
|
||||
"movq 127(%r8,%rax,4), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, r15, rax, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(r15).unwrap(), Gpr::new(rax).unwrap(), 3),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B5CC77F",
|
||||
"movq 127(%r15,%rax,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, rax, rdi, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(rax).unwrap(), Gpr::new(rdi).unwrap(), 3),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B5CF87F",
|
||||
"movq 127(%rax,%rdi,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, rdi, rdi, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(rdi).unwrap(), Gpr::new(rdi).unwrap(), 2),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B5CBF7F",
|
||||
"movq 127(%rdi,%rdi,4), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, r8, rdi, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(r8).unwrap(), Gpr::new(rdi).unwrap(), 1),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B5C787F",
|
||||
"movq 127(%r8,%rdi,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(127, r15, rdi, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(127, Gpr::new(r15).unwrap(), Gpr::new(rdi).unwrap(), 0),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B5C3F7F",
|
||||
"movq 127(%r15,%rdi,1), %r11",
|
||||
));
|
||||
@@ -736,42 +761,106 @@ fn test_x64_emit() {
|
||||
// ========================================================
|
||||
// Addr_IRRS, offset min simm8
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, rax, r8, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
2,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B5C8080",
|
||||
"movq -128(%rax,%r8,4), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, rdi, r8, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B5CC780",
|
||||
"movq -128(%rdi,%r8,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, r8, r8, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(r8).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B5C0080",
|
||||
"movq -128(%r8,%r8,1), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, r15, r8, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
1,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B5C4780",
|
||||
"movq -128(%r15,%r8,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, rax, r15, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
1,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B5C7880",
|
||||
"movq -128(%rax,%r15,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, rdi, r15, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B5C3F80",
|
||||
"movq -128(%rdi,%r15,1), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, r8, r15, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(r8).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B5CF880",
|
||||
"movq -128(%r8,%r15,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(-128i32 as u32, r15, r15, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
-128i32 as u32,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
2,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B5CBF80",
|
||||
"movq -128(%r15,%r15,4), %r11",
|
||||
));
|
||||
@@ -779,42 +868,96 @@ fn test_x64_emit() {
|
||||
// ========================================================
|
||||
// Addr_IRRS, offset large positive simm32
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, rax, rax, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(rax).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B9C00BE25664F",
|
||||
"movq 1332094398(%rax,%rax,1), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, rdi, rax, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(rax).unwrap(),
|
||||
1,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B9C47BE25664F",
|
||||
"movq 1332094398(%rdi,%rax,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, r8, rax, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(0x4f6625be, Gpr::new(r8).unwrap(), Gpr::new(rax).unwrap(), 2),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B9C80BE25664F",
|
||||
"movq 1332094398(%r8,%rax,4), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, r15, rax, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(rax).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B9CC7BE25664F",
|
||||
"movq 1332094398(%r15,%rax,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, rax, rdi, 3), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(rdi).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B9CF8BE25664F",
|
||||
"movq 1332094398(%rax,%rdi,8), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, rdi, rdi, 2), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(rdi).unwrap(),
|
||||
2,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4C8B9CBFBE25664F",
|
||||
"movq 1332094398(%rdi,%rdi,4), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, r8, rdi, 1), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(0x4f6625be, Gpr::new(r8).unwrap(), Gpr::new(rdi).unwrap(), 1),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B9C78BE25664F",
|
||||
"movq 1332094398(%r8,%rdi,2), %r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(0x4f6625be, r15, rdi, 0), w_r11),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(
|
||||
0x4f6625be,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(rdi).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4D8B9C3FBE25664F",
|
||||
"movq 1332094398(%r15,%rdi,1), %r11",
|
||||
));
|
||||
@@ -823,7 +966,12 @@ fn test_x64_emit() {
|
||||
// Addr_IRRS, offset large negative simm32
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, rax, r8, 2),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
2,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B9C8070E9B2D9",
|
||||
@@ -831,7 +979,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, rdi, r8, 3),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B9CC770E9B2D9",
|
||||
@@ -839,7 +992,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, r8, r8, 0),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(r8).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B9C0070E9B2D9",
|
||||
@@ -847,7 +1005,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, r15, r8, 1),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(r8).unwrap(),
|
||||
1,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B9C4770E9B2D9",
|
||||
@@ -855,7 +1018,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, rax, r15, 1),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(rax).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
1,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B9C7870E9B2D9",
|
||||
@@ -863,7 +1031,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, rdi, r15, 0),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
0,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4E8B9C3F70E9B2D9",
|
||||
@@ -871,7 +1044,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, r8, r15, 3),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(r8).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
3,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B9CF870E9B2D9",
|
||||
@@ -879,7 +1057,12 @@ fn test_x64_emit() {
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(-0x264d1690i32 as u32, r15, r15, 2),
|
||||
Amode::imm_reg_reg_shift(
|
||||
-0x264d1690i32 as u32,
|
||||
Gpr::new(r15).unwrap(),
|
||||
Gpr::new(r15).unwrap(),
|
||||
2,
|
||||
),
|
||||
w_r11,
|
||||
),
|
||||
"4F8B9CBF70E9B2D9",
|
||||
@@ -1828,42 +2011,66 @@ fn test_x64_emit() {
|
||||
// ========================================================
|
||||
// Mov64_M_R
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, rax, rbx, 0), w_rcx),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(rax).unwrap(), Gpr::new(rbx).unwrap(), 0),
|
||||
w_rcx,
|
||||
),
|
||||
"488B8C18B3000000",
|
||||
"movq 179(%rax,%rbx,1), %rcx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, rax, rbx, 0), w_r8),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(rax).unwrap(), Gpr::new(rbx).unwrap(), 0),
|
||||
w_r8,
|
||||
),
|
||||
"4C8B8418B3000000",
|
||||
"movq 179(%rax,%rbx,1), %r8",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, rax, r9, 0), w_rcx),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(rax).unwrap(), Gpr::new(r9).unwrap(), 0),
|
||||
w_rcx,
|
||||
),
|
||||
"4A8B8C08B3000000",
|
||||
"movq 179(%rax,%r9,1), %rcx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, rax, r9, 0), w_r8),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(rax).unwrap(), Gpr::new(r9).unwrap(), 0),
|
||||
w_r8,
|
||||
),
|
||||
"4E8B8408B3000000",
|
||||
"movq 179(%rax,%r9,1), %r8",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, r10, rbx, 0), w_rcx),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(r10).unwrap(), Gpr::new(rbx).unwrap(), 0),
|
||||
w_rcx,
|
||||
),
|
||||
"498B8C1AB3000000",
|
||||
"movq 179(%r10,%rbx,1), %rcx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, r10, rbx, 0), w_r8),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(r10).unwrap(), Gpr::new(rbx).unwrap(), 0),
|
||||
w_r8,
|
||||
),
|
||||
"4D8B841AB3000000",
|
||||
"movq 179(%r10,%rbx,1), %r8",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, r10, r9, 0), w_rcx),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(r10).unwrap(), Gpr::new(r9).unwrap(), 0),
|
||||
w_rcx,
|
||||
),
|
||||
"4B8B8C0AB3000000",
|
||||
"movq 179(%r10,%r9,1), %rcx",
|
||||
));
|
||||
insns.push((
|
||||
Inst::mov64_m_r(Amode::imm_reg_reg_shift(179, r10, r9, 0), w_r8),
|
||||
Inst::mov64_m_r(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(r10).unwrap(), Gpr::new(r9).unwrap(), 0),
|
||||
w_r8,
|
||||
),
|
||||
"4F8B840AB3000000",
|
||||
"movq 179(%r10,%r9,1), %r8",
|
||||
));
|
||||
@@ -1881,7 +2088,10 @@ fn test_x64_emit() {
|
||||
"lea 42(%r10), %r15",
|
||||
));
|
||||
insns.push((
|
||||
Inst::lea(Amode::imm_reg_reg_shift(179, r10, r9, 0), w_r8),
|
||||
Inst::lea(
|
||||
Amode::imm_reg_reg_shift(179, Gpr::new(r10).unwrap(), Gpr::new(r9).unwrap(), 0),
|
||||
w_r8,
|
||||
),
|
||||
"4F8D840AB3000000",
|
||||
"lea 179(%r10,%r9,1), %r8",
|
||||
));
|
||||
@@ -3115,7 +3325,12 @@ fn test_x64_emit() {
|
||||
Inst::cmove(
|
||||
OperandSize::Size16,
|
||||
CC::NO,
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(37, rdi, rsi, 2)),
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
37,
|
||||
Gpr::new(rdi).unwrap(),
|
||||
Gpr::new(rsi).unwrap(),
|
||||
2,
|
||||
)),
|
||||
w_r15,
|
||||
),
|
||||
"66440F417CB725",
|
||||
@@ -3157,12 +3372,22 @@ fn test_x64_emit() {
|
||||
insns.push((Inst::push64(RegMemImm::reg(rdi)), "57", "pushq %rdi"));
|
||||
insns.push((Inst::push64(RegMemImm::reg(r8)), "4150", "pushq %r8"));
|
||||
insns.push((
|
||||
Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift(321, rsi, rcx, 3))),
|
||||
Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(rsi).unwrap(),
|
||||
Gpr::new(rcx).unwrap(),
|
||||
3,
|
||||
))),
|
||||
"FFB4CE41010000",
|
||||
"pushq 321(%rsi,%rcx,8)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift(321, r9, rbx, 2))),
|
||||
Inst::push64(RegMemImm::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(r9).unwrap(),
|
||||
Gpr::new(rbx).unwrap(),
|
||||
2,
|
||||
))),
|
||||
"41FFB49941010000",
|
||||
"pushq 321(%r9,%rbx,4)",
|
||||
));
|
||||
@@ -3226,12 +3451,22 @@ fn test_x64_emit() {
|
||||
insns.push((call_unknown(RegMem::reg(rbp)), "FFD5", "call *%rbp"));
|
||||
insns.push((call_unknown(RegMem::reg(r11)), "41FFD3", "call *%r11"));
|
||||
insns.push((
|
||||
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(321, rsi, rcx, 3))),
|
||||
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(rsi).unwrap(),
|
||||
Gpr::new(rcx).unwrap(),
|
||||
3,
|
||||
))),
|
||||
"FF94CE41010000",
|
||||
"call *321(%rsi,%rcx,8)",
|
||||
));
|
||||
insns.push((
|
||||
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(321, r10, rdx, 2))),
|
||||
call_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(r10).unwrap(),
|
||||
Gpr::new(rdx).unwrap(),
|
||||
2,
|
||||
))),
|
||||
"41FF949241010000",
|
||||
"call *321(%r10,%rdx,4)",
|
||||
));
|
||||
@@ -3301,12 +3536,22 @@ fn test_x64_emit() {
|
||||
"jmp *%r11",
|
||||
));
|
||||
insns.push((
|
||||
Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift(321, rsi, rcx, 3))),
|
||||
Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(rsi).unwrap(),
|
||||
Gpr::new(rcx).unwrap(),
|
||||
3,
|
||||
))),
|
||||
"FFA4CE41010000",
|
||||
"jmp *321(%rsi,%rcx,8)",
|
||||
));
|
||||
insns.push((
|
||||
Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift(321, r10, rdx, 2))),
|
||||
Inst::jmp_unknown(RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(r10).unwrap(),
|
||||
Gpr::new(rdx).unwrap(),
|
||||
2,
|
||||
))),
|
||||
"41FFA49241010000",
|
||||
"jmp *321(%r10,%rdx,4)",
|
||||
));
|
||||
@@ -3354,7 +3599,12 @@ fn test_x64_emit() {
|
||||
insns.push((
|
||||
Inst::xmm_rm_r(
|
||||
SseOpcode::Addss,
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(123, r10, rdx, 2)),
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
123,
|
||||
Gpr::new(r10).unwrap(),
|
||||
Gpr::new(rdx).unwrap(),
|
||||
2,
|
||||
)),
|
||||
w_xmm0,
|
||||
),
|
||||
"F3410F5844927B",
|
||||
@@ -3379,7 +3629,12 @@ fn test_x64_emit() {
|
||||
insns.push((
|
||||
Inst::xmm_rm_r(
|
||||
SseOpcode::Subss,
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(321, r10, rax, 3)),
|
||||
RegMem::mem(Amode::imm_reg_reg_shift(
|
||||
321,
|
||||
Gpr::new(r10).unwrap(),
|
||||
Gpr::new(rax).unwrap(),
|
||||
3,
|
||||
)),
|
||||
w_xmm10,
|
||||
),
|
||||
"F3450F5C94C241010000",
|
||||
@@ -4200,10 +4455,17 @@ fn test_x64_emit() {
|
||||
|
||||
// ========================================================
|
||||
// Pertaining to atomics.
|
||||
let am1: SyntheticAmode = Amode::imm_reg_reg_shift(321, r10, rdx, 2).into();
|
||||
let am1: SyntheticAmode =
|
||||
Amode::imm_reg_reg_shift(321, Gpr::new(r10).unwrap(), Gpr::new(rdx).unwrap(), 2).into();
|
||||
// `am2` doesn't contribute any 1 bits to the rex prefix, so we must use it when testing
|
||||
// for retention of the apparently-redundant rex prefix in the 8-bit case.
|
||||
let am2: SyntheticAmode = Amode::imm_reg_reg_shift(-12345i32 as u32, rcx, rsi, 3).into();
|
||||
let am2: SyntheticAmode = Amode::imm_reg_reg_shift(
|
||||
-12345i32 as u32,
|
||||
Gpr::new(rcx).unwrap(),
|
||||
Gpr::new(rsi).unwrap(),
|
||||
3,
|
||||
)
|
||||
.into();
|
||||
|
||||
// A general 8-bit case.
|
||||
insns.push((
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user