summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yjit/src/asm/arm64/arg/mod.rs2
-rw-r--r--yjit/src/asm/arm64/arg/sys_reg.rs6
-rw-r--r--yjit/src/asm/arm64/inst/mod.rs2
-rw-r--r--yjit/src/asm/arm64/inst/sys_reg.rs86
-rw-r--r--yjit/src/asm/arm64/mod.rs34
5 files changed, 130 insertions, 0 deletions
diff --git a/yjit/src/asm/arm64/arg/mod.rs b/yjit/src/asm/arm64/arg/mod.rs
index 0d2f1ac28a..bb779ab6df 100644
--- a/yjit/src/asm/arm64/arg/mod.rs
+++ b/yjit/src/asm/arm64/arg/mod.rs
@@ -4,7 +4,9 @@
mod bitmask_imm;
mod condition;
mod sf;
+mod sys_reg;
pub use bitmask_imm::BitmaskImmediate;
pub use condition::Condition;
pub use sf::Sf;
+pub use sys_reg::SystemRegister;
diff --git a/yjit/src/asm/arm64/arg/sys_reg.rs b/yjit/src/asm/arm64/arg/sys_reg.rs
new file mode 100644
index 0000000000..41d71920cb
--- /dev/null
+++ b/yjit/src/asm/arm64/arg/sys_reg.rs
@@ -0,0 +1,6 @@
+/// The encoded representation of an A64 system register.
+/// https://developer.arm.com/documentation/ddi0601/2022-06/AArch64-Registers/
+pub enum SystemRegister {
+ /// https://developer.arm.com/documentation/ddi0601/2022-06/AArch64-Registers/NZCV--Condition-Flags?lang=en
+ NZCV = 0b1_011_0100_0010_000
+}
diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs
index f402f6765a..9dfc923f53 100644
--- a/yjit/src/asm/arm64/inst/mod.rs
+++ b/yjit/src/asm/arm64/inst/mod.rs
@@ -16,6 +16,7 @@ mod mov;
mod nop;
mod shift_imm;
mod store;
+mod sys_reg;
pub use atomic::Atomic;
pub use branch::Branch;
@@ -32,3 +33,4 @@ pub use mov::Mov;
pub use nop::Nop;
pub use shift_imm::ShiftImm;
pub use store::Store;
+pub use sys_reg::SysReg;
diff --git a/yjit/src/asm/arm64/inst/sys_reg.rs b/yjit/src/asm/arm64/inst/sys_reg.rs
new file mode 100644
index 0000000000..108737a870
--- /dev/null
+++ b/yjit/src/asm/arm64/inst/sys_reg.rs
@@ -0,0 +1,86 @@
+use super::super::arg::SystemRegister;
+
+/// Which operation to perform (loading or storing the system register value).
+enum L {
+ /// Store the value of a general-purpose register in a system register.
+ MSR = 0,
+
+ /// Store the value of a system register in a general-purpose register.
+ MRS = 1
+}
+
+/// The struct that represents an A64 system register instruction that can be
+/// encoded.
+///
+/// MSR/MRS (register)
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+/// | 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 0 1 0 1 0 1 0 0 1 |
+/// | L o0 op1..... CRn........ CRm........ op2..... rt.............. |
+/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
+///
+pub struct SysReg {
+ /// The register to load the system register value into.
+ rt: u8,
+
+ /// Which system register to load or store.
+ systemreg: SystemRegister,
+
+ /// Which operation to perform (loading or storing the system register value).
+ l: L
+}
+
+impl SysReg {
+ /// MRS (register)
+ /// https://developer.arm.com/documentation/ddi0602/2022-03/Base-Instructions/MRS--Move-System-Register-?lang=en
+ pub fn mrs(rt: u8, systemreg: SystemRegister) -> Self {
+ SysReg { rt, systemreg, l: L::MRS }
+ }
+
+ /// MSR (register)
+ /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/MSR--register---Move-general-purpose-register-to-System-Register-?lang=en
+ pub fn msr(systemreg: SystemRegister, rt: u8) -> Self {
+ SysReg { rt, systemreg, l: L::MSR }
+ }
+}
+
+/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Branches--Exception-Generating-and-System-instructions?lang=en#systemmove
+const FAMILY: u32 = 0b110101010001;
+
+impl From<SysReg> for u32 {
+ /// Convert an instruction into a 32-bit value.
+ fn from(inst: SysReg) -> Self {
+ 0
+ | (FAMILY << 20)
+ | ((inst.l as u32) << 21)
+ | ((inst.systemreg as u32) << 5)
+ | inst.rt as u32
+ }
+}
+
+impl From<SysReg> for [u8; 4] {
+ /// Convert an instruction into a 4 byte array.
+ fn from(inst: SysReg) -> [u8; 4] {
+ let result: u32 = inst.into();
+ result.to_le_bytes()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_mrs() {
+ let inst = SysReg::mrs(0, SystemRegister::NZCV);
+ let result: u32 = inst.into();
+ assert_eq!(0xd53b4200, result);
+ }
+
+ #[test]
+ fn test_msr() {
+ let inst = SysReg::msr(SystemRegister::NZCV, 0);
+ let result: u32 = inst.into();
+ assert_eq!(0xd51b4200, result);
+ }
+}
diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs
index 3b5f1ff022..7adc1a2745 100644
--- a/yjit/src/asm/arm64/mod.rs
+++ b/yjit/src/asm/arm64/mod.rs
@@ -364,6 +364,30 @@ pub fn movz(cb: &mut CodeBlock, rd: A64Opnd, imm16: A64Opnd, shift: u8) {
cb.write_bytes(&bytes);
}
+/// MRS - move a system register into a general-purpose register
+pub fn mrs(cb: &mut CodeBlock, rt: A64Opnd, systemregister: SystemRegister) {
+ let bytes: [u8; 4] = match rt {
+ A64Opnd::Reg(rt) => {
+ SysReg::mrs(rt.reg_no, systemregister).into()
+ },
+ _ => panic!("Invalid operand combination to mrs instruction")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
+/// MSR - move a general-purpose register into a system register
+pub fn msr(cb: &mut CodeBlock, systemregister: SystemRegister, rt: A64Opnd) {
+ let bytes: [u8; 4] = match rt {
+ A64Opnd::Reg(rt) => {
+ SysReg::msr(systemregister, rt.reg_no).into()
+ },
+ _ => panic!("Invalid operand combination to msr instruction")
+ };
+
+ cb.write_bytes(&bytes);
+}
+
/// MVN - move a value in a register to another register, negating it
pub fn mvn(cb: &mut CodeBlock, rd: A64Opnd, rm: A64Opnd) {
let bytes: [u8; 4] = match (rd, rm) {
@@ -715,6 +739,16 @@ mod tests {
}
#[test]
+ fn test_mrs() {
+ check_bytes("0a423bd5", |cb| mrs(cb, X10, SystemRegister::NZCV));
+ }
+
+ #[test]
+ fn test_msr() {
+ check_bytes("0a421bd5", |cb| msr(cb, SystemRegister::NZCV, X10));
+ }
+
+ #[test]
fn test_mvn() {
check_bytes("ea032baa", |cb| mvn(cb, X10, X11));
}