summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2022-06-13 17:16:33 -0400
committerTakashi Kokubun <takashikkbn@gmail.com>2022-08-29 08:46:55 -0700
commitc10e018e1c2dd3351af1f40f9b20ea23cfeace36 (patch)
treea8b199b04561c3efb516b76ec7c610a1405b26cc
parent1daa5942b83ede3e504f9952a1f705b763e59893 (diff)
LDADDAL, STUR, BL (https://github.com/Shopify/ruby/pull/299)
* LDADDAL instruction * STUR * BL instruction * Remove num_bits from imm and uimm * Tests for imm_fits_bits and uimm_fits_bits * Reorder arguments to LDADDAL
-rw-r--r--yjit/src/asm/arm64/inst/atomic.rs86
-rw-r--r--yjit/src/asm/arm64/inst/call.rs67
-rw-r--r--yjit/src/asm/arm64/inst/mod.rs137
-rw-r--r--yjit/src/asm/arm64/inst/store.rs105
-rw-r--r--yjit/src/asm/arm64/opnd.rs42
5 files changed, 384 insertions, 53 deletions
diff --git a/yjit/src/asm/arm64/inst/atomic.rs b/yjit/src/asm/arm64/inst/atomic.rs
new file mode 100644
index 0000000000..5ce497209c
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/atomic.rs
@@ -0,0 +1,86 @@
+/// The size of the register operands to this instruction.
+enum Size {
+ /// Using 32-bit registers.
+ Size32 = 0b10,
+
+ /// Using 64-bit registers.
+ Size64 = 0b11
+}
+
+/// A convenience function so that we can convert the number of bits of an
+/// register operand directly into a Size enum variant.
+impl From<u8> for Size {
+ fn from(num_bits: u8) -> Self {
+ match num_bits {
+ 64 => Size::Size64,
+ 32 => Size::Size32,
+ _ => panic!("Invalid number of bits: {}", num_bits)
+ }
+ }
+}
+
+/// The struct that represents an A64 atomic instruction that can be encoded.
+///
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
+/// | 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 |
+/// | size rs.............. rn.............. rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Atomic {
+ /// The register holding the value to be loaded.
+ rt: u8,
+
+ /// The base register.
+ rn: u8,
+
+ /// The register holding the data value to be operated on.
+ rs: u8,
+
+ /// The size of the registers used in this instruction.
+ size: Size
+}
+
+impl Atomic {
+ /// LDADDAL
+ /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDADD--LDADDA--LDADDAL--LDADDL--Atomic-add-on-word-or-doubleword-in-memory-?lang=en
+ pub fn ldaddal(rs: u8, rt: u8, rn: u8, num_bits: u8) -> Self {
+ Self { rt, rn, rs, size: num_bits.into() }
+ }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Loads-and-Stores?lang=en
+const FAMILY: u32 = 0b0100;
+
+impl From<Atomic> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: Atomic) -> Self {
+ 0
+ | ((inst.size as u32) << 30)
+ | (0b11 << 28)
+ | (FAMILY << 25)
+ | (0b111 << 21)
+ | ((inst.rs as u32) << 16)
+ | ((inst.rn as u32) << 5)
+ | (inst.rt as u32)
+ }
+}
+
+impl From<Atomic> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: Atomic) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_ldaddal() {
+ let result: u32 = Atomic::ldaddal(20, 21, 22, 64).into();
+ assert_eq!(0xf8f402d5, result);
+ }
+}
diff --git a/yjit/src/asm/arm64/inst/call.rs b/yjit/src/asm/arm64/inst/call.rs
new file mode 100644
index 0000000000..6f23acf9f5
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/call.rs
@@ -0,0 +1,67 @@
+/// The struct that represents an A64 branch with link instruction that can be
+/// encoded.
+///
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
+/// | 1 0 0 1 0 1 |
+/// | imm26.................................................................................... |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Call {
+ /// The PC-relative offset to jump to (which will be multiplied by 4).
+ imm26: i32
+}
+
+impl Call {
+ /// BL
+ /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/BL--Branch-with-Link-?lang=en
+ pub fn bl(imm26: i32) -> Self {
+ Self { imm26 }
+ }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Branches--Exception-Generating-and-System-instructions?lang=en
+const FAMILY: u32 = 0b101;
+
+impl From<Call> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: Call) -> Self {
+ let imm26 = (inst.imm26 as u32) & ((1 << 26) - 1);
+
+ 0
+ | (1 << 31)
+ | (FAMILY << 26)
+ | imm26
+ }
+}
+
+impl From<Call> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: Call) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_bl() {
+ let result: u32 = Call::bl(0).into();
+ assert_eq!(0x94000000, result);
+ }
+
+ #[test]
+ fn test_bl_positive() {
+ let result: u32 = Call::bl(256).into();
+ assert_eq!(0x94000100, result);
+ }
+
+ #[test]
+ fn test_bl_negative() {
+ let result: u32 = Call::bl(-256).into();
+ assert_eq!(0x97ffff00, result);
+ }
+}
diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index eec9d116b2..c96e9328ff 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -1,19 +1,42 @@
+mod atomic;
mod branch;
+mod call;
mod data_imm;
mod data_reg;
mod load;
mod mov;
mod sf;
+mod store;
+use core::num;
+
+use atomic::Atomic;
use branch::Branch;
+use call::Call;
use data_imm::DataImm;
use data_reg::DataReg;
use load::Load;
use mov::Mov;
+use store::Store;
-use crate::asm::{CodeBlock, imm_num_bits};
+use crate::asm::CodeBlock;
use super::opnd::*;
+/// Checks that a signed value fits within the specified number of bits.
+const fn imm_fits_bits(imm: i64, num_bits: u8) -> bool {
+ let minimum = if num_bits == 64 { i64::MIN } else { -2_i64.pow((num_bits as u32) - 1) };
+ let maximum = if num_bits == 64 { i64::MAX } else { 2_i64.pow((num_bits as u32) - 1) - 1 };
+
+ imm >= minimum && imm <= maximum
+}
+
+/// Checks that an unsigned value fits within the specified number of bits.
+const fn uimm_fits_bits(uimm: u64, num_bits: u8) -> bool {
+ let maximum = if num_bits == 64 { u64::MAX } else { 2_u64.pow(num_bits as u32) - 1 };
+
+ uimm <= maximum
+}
+
/// ADD - add rn and rm, put the result in rd, don't update flags
pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
let bytes: [u8; 4] = match (rd, rn, rm) {
@@ -27,9 +50,9 @@ pub fn add(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
},
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
- assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+ assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
- DataImm::add(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+ DataImm::add(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to add instruction."),
};
@@ -50,9 +73,9 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
},
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
- assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+ assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
- DataImm::adds(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+ DataImm::adds(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to adds instruction."),
};
@@ -60,6 +83,20 @@ pub fn adds(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
cb.write_bytes(&bytes);
}
+/// BL - branch with link (offset is number of instructions to jump)
+pub fn bl(cb: &mut CodeBlock, imm26: A64Opnd) {
+ let bytes: [u8; 4] = match imm26 {
+ A64Opnd::Imm(imm26) => {
+ assert!(imm_fits_bits(imm26, 26), "The immediate operand must be 26 bits or less.");
+
+ Call::bl(imm26 as i32).into()
+ },
+ _ => panic!("Invalid operand combination to bl instruction.")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
/// BR - branch to a register
pub fn br(cb: &mut CodeBlock, rn: A64Opnd) {
let bytes: [u8; 4] = match rn {
@@ -70,14 +107,31 @@ pub fn br(cb: &mut CodeBlock, rn: A64Opnd) {
cb.write_bytes(&bytes);
}
+/// LDADDAL - atomic add with acquire and release semantics
+pub fn ldaddal(cb: &mut CodeBlock, rs: A64Opnd, rt: A64Opnd, rn: A64Opnd) {
+ let bytes: [u8; 4] = match (rs, rt, rn) {
+ (A64Opnd::Reg(rs), A64Opnd::Reg(rt), A64Opnd::Reg(rn)) => {
+ assert!(
+ rs.num_bits == rt.num_bits && rt.num_bits == rn.num_bits,
+ "All operands must be of the same size."
+ );
+
+ Atomic::ldaddal(rs.reg_no, rt.reg_no, rn.reg_no, rs.num_bits).into()
+ },
+ _ => panic!("Invalid operand combination to ldaddal instruction."),
+ };
+
+ cb.write_bytes(&bytes);
+}
+
/// LDUR - load a memory address into a register
pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
let bytes: [u8; 4] = match (rt, rn) {
(A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
assert!(rt.num_bits == rn.num_bits, "Expected registers to be the same size");
- assert!(imm_num_bits(rn.disp.into()) <= 9, "Expected displacement to be 9 bits or less");
+ assert!(imm_fits_bits(rn.disp.into(), 9), "Expected displacement to be 9 bits or less");
- Load::ldur(rt.reg_no, rn.base_reg_no, rn.disp.try_into().unwrap(), rt.num_bits).into()
+ Load::ldur(rt.reg_no, rn.base_reg_no, rn.disp as i16, rt.num_bits).into()
},
_ => panic!("Invalid operands for LDUR")
};
@@ -89,9 +143,9 @@ pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
pub fn movk(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
let bytes: [u8; 4] = match (rd, imm16) {
(A64Opnd::Reg(rd), A64Opnd::UImm(imm16)) => {
- assert!(imm16.num_bits <= 16, "The immediate operand must be 16 bits or less.");
+ assert!(uimm_fits_bits(imm16, 16), "The immediate operand must be 16 bits or less.");
- Mov::movk(rd.reg_no, imm16.value as u16, shift, rd.num_bits).into()
+ Mov::movk(rd.reg_no, imm16 as u16, shift, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to movk instruction.")
};
@@ -103,9 +157,9 @@ pub fn movk(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
let bytes: [u8; 4] = match (rd, imm16) {
(A64Opnd::Reg(rd), A64Opnd::UImm(imm16)) => {
- assert!(imm16.num_bits <= 16, "The immediate operand must be 16 bits or less.");
+ assert!(uimm_fits_bits(imm16, 16), "The immediate operand must be 16 bits or less.");
- Mov::movz(rd.reg_no, imm16.value as u16, shift, rd.num_bits).into()
+ Mov::movz(rd.reg_no, imm16 as u16, shift, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to movz instruction.")
};
@@ -113,6 +167,21 @@ pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
cb.write_bytes(&bytes);
}
+/// STUR - store a value in a register at a memory address
+pub fn stur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) {
+ let bytes: [u8; 4] = match (rt, rn) {
+ (A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => {
+ assert!(rt.num_bits == rn.num_bits, "Expected registers to be the same size");
+ assert!(imm_fits_bits(rn.disp.into(), 9), "Expected displacement to be 9 bits or less");
+
+ Store::stur(rt.reg_no, rn.base_reg_no, rn.disp as i16, rt.num_bits).into()
+ },
+ _ => panic!("Invalid operand combination to stur instruction.")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
/// SUB - subtract rm from rn, put the result in rd, don't update flags
pub fn sub(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
let bytes: [u8; 4] = match (rd, rn, rm) {
@@ -126,9 +195,9 @@ pub fn sub(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
},
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
- assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+ assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
- DataImm::sub(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+ DataImm::sub(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to sub instruction."),
};
@@ -149,9 +218,9 @@ pub fn subs(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) {
},
(A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm12)) => {
assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size.");
- assert!(imm12.num_bits <= 12, "The immediate operand must be 12 bits or less.");
+ assert!(uimm_fits_bits(imm12, 12), "The immediate operand must be 12 bits or less.");
- DataImm::subs(rd.reg_no, rn.reg_no, imm12.value as u16, rd.num_bits).into()
+ DataImm::subs(rd.reg_no, rn.reg_no, imm12 as u16, rd.num_bits).into()
},
_ => panic!("Invalid operand combination to subs instruction."),
};
@@ -182,6 +251,29 @@ mod tests {
}
#[test]
+ fn test_imm_fits_bits() {
+ assert!(imm_fits_bits(i8::MAX.into(), 8));
+ assert!(imm_fits_bits(i8::MIN.into(), 8));
+
+ assert!(imm_fits_bits(i16::MAX.into(), 16));
+ assert!(imm_fits_bits(i16::MIN.into(), 16));
+
+ assert!(imm_fits_bits(i32::MAX.into(), 32));
+ assert!(imm_fits_bits(i32::MIN.into(), 32));
+
+ assert!(imm_fits_bits(i64::MAX.into(), 64));
+ assert!(imm_fits_bits(i64::MIN.into(), 64));
+ }
+
+ #[test]
+ fn test_uimm_fits_bits() {
+ assert!(uimm_fits_bits(u8::MAX.into(), 8));
+ assert!(uimm_fits_bits(u16::MAX.into(), 16));
+ assert!(uimm_fits_bits(u32::MAX.into(), 32));
+ assert!(uimm_fits_bits(u64::MAX.into(), 64));
+ }
+
+ #[test]
fn test_add_register() {
check_bytes("2000028b", |cb| add(cb, X0, X1, X2));
}
@@ -202,11 +294,21 @@ mod tests {
}
#[test]
+ fn test_bl() {
+ check_bytes("00040094", |cb| bl(cb, A64Opnd::new_imm(1024)));
+ }
+
+ #[test]
fn test_br() {
check_bytes("80021fd6", |cb| br(cb, X20));
}
#[test]
+ fn test_ldaddal() {
+ check_bytes("8b01eaf8", |cb| ldaddal(cb, X10, X11, X12));
+ }
+
+ #[test]
fn test_ldur() {
check_bytes("20b047f8", |cb| ldur(cb, X0, A64Opnd::new_mem(X1, 123)));
}
@@ -232,6 +334,11 @@ mod tests {
}
#[test]
+ fn test_stur() {
+ check_bytes("6a0108f8", |cb| stur(cb, X10, A64Opnd::new_mem(X11, 128)));
+ }
+
+ #[test]
fn test_sub_register() {
check_bytes("200002cb", |cb| sub(cb, X0, X1, X2));
}
diff --git a/yjit/src/asm/arm64/inst/store.rs b/yjit/src/asm/arm64/inst/store.rs
new file mode 100644
index 0000000000..42b9055ae8
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/store.rs
@@ -0,0 +1,105 @@
+/// The size of the operands being operated on.
+enum Size {
+ Size32 = 0b10,
+ Size64 = 0b11,
+}
+
+/// A convenience function so that we can convert the number of bits of an
+/// register operand directly into an Sf enum variant.
+impl From<u8> for Size {
+ fn from(num_bits: u8) -> Self {
+ match num_bits {
+ 64 => Size::Size64,
+ 32 => Size::Size32,
+ _ => panic!("Invalid number of bits: {}", num_bits)
+ }
+ }
+}
+
+/// The struct that represents an A64 store instruction that can be encoded.
+///
+/// STUR
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 |
+/// | 1 1 1 0 0 0 0 0 0 0 0 |
+/// | size. imm9.......................... rn.............. rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct Store {
+ /// The number of the register to be transferred.
+ rt: u8,
+
+ /// The register holding the memory location.
+ rn: u8,
+
+ /// The optional signed immediate byte offset from the base register.
+ imm9: i16,
+
+ /// The size of the operands being operated on.
+ size: Size
+}
+
+impl Store {
+ /// STUR (store register, unscaled)
+ /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/STUR--Store-Register--unscaled--?lang=en
+ pub fn stur(rt: u8, rn: u8, imm9: i16, num_bits: u8) -> Self {
+ Self {
+ rt,
+ rn,
+ imm9,
+ size: num_bits.into()
+ }
+ }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Loads-and-Stores?lang=en
+const FAMILY: u32 = 0b0100;
+
+impl From<Store> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: Store) -> Self {
+ let imm9 = (inst.imm9 as u32) & ((1 << 9) - 1);
+
+ 0
+ | ((inst.size as u32) << 30)
+ | (0b11 << 28)
+ | (FAMILY << 25)
+ | (imm9 << 12)
+ | ((inst.rn as u32) << 5)
+ | (inst.rt as u32)
+ }
+}
+
+impl From<Store> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: Store) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_stur() {
+ let inst = Store::stur(0, 1, 0, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xf8000020, result);
+ }
+
+ #[test]
+ fn test_stur_negative_offset() {
+ let inst = Store::stur(0, 1, -1, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xf81ff020, result);
+ }
+
+ #[test]
+ fn test_stur_positive_offset() {
+ let inst = Store::stur(0, 1, 255, 64);
+ let result: u32 = inst.into();
+ assert_eq!(0xf80ff020, result);
+ }
+}
diff --git a/yjit/src/asm/arm64/opnd.rs b/yjit/src/asm/arm64/opnd.rs
index ba8ecd166d..aa73d438fe 100644
--- a/yjit/src/asm/arm64/opnd.rs
+++ b/yjit/src/asm/arm64/opnd.rs
@@ -1,39 +1,5 @@
use crate::asm::{imm_num_bits, uimm_num_bits};
-/// This operand represents a signed immediate value.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct A64Imm
-{
- // Size in bits
- pub num_bits: u8,
-
- // The value of the immediate
- pub value: i64
-}
-
-impl A64Imm {
- pub fn new(value: i64) -> Self {
- Self { num_bits: imm_num_bits(value), value }
- }
-}
-
-/// This operand represents an unsigned immediate value.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct A64UImm
-{
- // Size in bits
- pub num_bits: u8,
-
- // The value of the immediate
- pub value: u64
-}
-
-impl A64UImm {
- pub fn new(value: u64) -> Self {
- Self { num_bits: uimm_num_bits(value), value }
- }
-}
-
/// This operand represents a register.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct A64Reg
@@ -80,10 +46,10 @@ pub enum A64Opnd
None,
// Immediate value
- Imm(A64Imm),
+ Imm(i64),
// Unsigned immediate
- UImm(A64UImm),
+ UImm(u64),
// Register
Reg(A64Reg),
@@ -95,12 +61,12 @@ pub enum A64Opnd
impl A64Opnd {
/// Create a new immediate value operand.
pub fn new_imm(value: i64) -> Self {
- A64Opnd::Imm(A64Imm::new(value))
+ A64Opnd::Imm(value)
}
/// Create a new unsigned immediate value operand.
pub fn new_uimm(value: u64) -> Self {
- A64Opnd::UImm(A64UImm::new(value))
+ A64Opnd::UImm(value)
}
/// Creates a new memory operand.