From b99806b228944aa452692deb15cb83b2a5243bed Mon Sep 17 00:00:00 2001 From: Ivan Boldyrev Date: Thu, 9 Jul 2026 18:08:52 +0200 Subject: [PATCH 1/3] ADDC/SUBC --- harm/src/instructions/arith.rs | 2 + harm/src/instructions/arith/add.rs | 8 +- harm/src/instructions/arith/adds.rs | 206 ++++++++++++++++++++++++++ harm/src/instructions/arith/macros.rs | 53 +++---- harm/src/instructions/arith/sub.rs | 8 +- harm/src/instructions/arith/subs.rs | 206 ++++++++++++++++++++++++++ 6 files changed, 449 insertions(+), 34 deletions(-) create mode 100644 harm/src/instructions/arith/adds.rs create mode 100644 harm/src/instructions/arith/subs.rs diff --git a/harm/src/instructions/arith.rs b/harm/src/instructions/arith.rs index 3cfc6459..8ce34b5d 100644 --- a/harm/src/instructions/arith.rs +++ b/harm/src/instructions/arith.rs @@ -14,7 +14,9 @@ use crate::{ pub(crate) mod macros; pub mod add; +pub mod adds; pub mod sub; +pub mod subs; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct ShiftedReg { diff --git a/harm/src/instructions/arith/add.rs b/harm/src/instructions/arith/add.rs index e304dc17..53a64076 100644 --- a/harm/src/instructions/arith/add.rs +++ b/harm/src/instructions/arith/add.rs @@ -73,11 +73,11 @@ define_arith_faillible!(Add); define_arith_shift!(Add, 32, addsub, Reg32, RegOrZero32); define_arith_shift!(Add, 64, addsub, Reg64, RegOrZero64); -define_arith_extend!(Add, 32, addsub, Reg32, RegOrSp32, RegOrZero32); -define_arith_extend!(Add, 64, addsub, Reg64, RegOrSp64, RegOrZero64); +define_arith_extend!(Add, 32, addsub, Reg32, RegOrSp32, RegOrSp32, RegOrZero32); +define_arith_extend!(Add, 64, addsub, Reg64, RegOrSp64, RegOrSp64, RegOrZero64); -define_arith_imm12!(Add, 32, addsub, Reg32, RegOrSp32); -define_arith_imm12!(Add, 64, addsub, Reg64, RegOrSp64); +define_arith_imm12!(Add, 32, addsub, Reg32, RegOrSp32, RegOrSp32); +define_arith_imm12!(Add, 64, addsub, Reg64, RegOrSp64, RegOrSp64); #[cfg(test)] mod tests { diff --git a/harm/src/instructions/arith/adds.rs b/harm/src/instructions/arith/adds.rs new file mode 100644 index 00000000..f16bd594 --- /dev/null +++ b/harm/src/instructions/arith/adds.rs @@ -0,0 +1,206 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::{ + dpimm::addsub_imm::{ + ADDS_32S_addsub_imm::ADDS_32S_addsub_imm, ADDS_64S_addsub_imm::ADDS_64S_addsub_imm, + }, + dpreg::{ + addsub_ext::{ + ADDS_32S_addsub_ext::ADDS_32S_addsub_ext, ADDS_64S_addsub_ext::ADDS_64S_addsub_ext, + }, + addsub_shift::{ + ADDS_32_addsub_shift::ADDS_32_addsub_shift, ADDS_64_addsub_shift::ADDS_64_addsub_shift, + }, + }, +}; +use aarchmrs_types::InstructionCode; + +use super::*; +use crate::{ + bits::BitError, + instructions::RawInstruction, + register::{ + IntoReg, Reg32, Reg64, RegOrSp32, RegOrSp64, RegOrZero32, RegOrZero64, Register as _, + }, + sealed::Sealed, +}; + +pub fn adds( + dst: T, + src1: S1, + src2: S2, +) -> as MakeAdds>::Output +where + Adds: MakeAdds, +{ + Adds::::new(dst, src1, src2) +} + +pub trait MakeAdds: Sealed { + type Output; + + fn new(dst: T, src1: S1, src2: S2) -> Self::Output; +} + +pub struct Adds { + pub dst: T, + pub src1: S1, + pub src2: S2, +} + +impl Sealed for Adds {} + +impl MakeAdds for Adds { + type Output = Self; + + #[inline] + fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self { + Self { dst, src1, src2 } + } +} + +impl MakeAdds for Adds { + type Output = Self; + + #[inline] + fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self { + Self { dst, src1, src2 } + } +} + +define_arith_faillible!(Adds); + +define_arith_shift!(Adds, 32, addsub, Reg32, RegOrZero32); +define_arith_shift!(Adds, 64, addsub, Reg64, RegOrZero64); + +define_arith_extend!( + Adds, + 32S, + addsub, + Reg32, + RegOrSp32, + RegOrZero32, + RegOrZero32 +); +define_arith_extend!( + Adds, + 64S, + addsub, + Reg64, + RegOrSp64, + RegOrZero64, + RegOrZero64 +); + +define_arith_imm12!(Adds, 32S, addsub, Reg32, RegOrZero32, RegOrSp32); +define_arith_imm12!(Adds, 64S, addsub, Reg64, RegOrZero64, RegOrSp64); + +#[cfg(test)] +mod tests { + use harm_test_utils::test_cases; + + use super::*; + use crate::instructions::InstructionSeq; + use crate::instructions::arith::AddSubImm12; + use Reg32::*; + use Reg64::*; + use RegOrSp32::Reg as Reg3S; + use RegOrSp64::Reg as RegS; + use RegOrZero32::Reg as Reg3Z; + use RegOrZero32::WZR; + use RegOrZero64::Reg as RegZ; + use RegOrZero64::XZR; + + const ADDS_DB: &str = " +ab3f2c41 adds x1, x2, wzr, uxth #3 +2b0c0041 adds w1, w2, w12 +2b2c6c41 adds w1, w2, w12, uxtx #3 +2b2c4c41 adds w1, w2, w12, uxtw #3 +2b3f6c41 adds w1, w2, wzr, uxtx #3 +2b3f4c41 adds w1, w2, wzr, uxtw #3 +2b4c1041 adds w1, w2, w12, lsr #4 +2b4c13e1 adds w1, wzr, w12, lsr #4 +31048c41 adds w1, w2, #0x123 +31448c41 adds w1, w2, #0x123000 +ab0c0041 adds x1, x2, x12 +ab2c4c41 adds x1, x2, w12, uxtw #3 +ab2c6c41 adds x1, x2, x12, uxtx #3 +ab2c7041 adds x1, x2, x12, uxtx #4 +ab3f4c41 adds x1, x2, wzr, uxtw #3 +ab4c1041 adds x1, x2, x12, lsr #4 +ab4c13e1 adds x1, xzr, x12, lsr #4 +b1000441 adds x1, x2, #1 +b1400441 adds x1, x2, #0x1000 +"; + + test_cases! { + ADDS_DB, untested_adds_db; + test_adds_64, adds(X1, X2, X12), "adds x1, x2, x12"; + test_adds_64_shift, adds(X1, X2, X12).try_shift(ShiftMode::LSR, 4).unwrap(), "adds x1, x2, x12, lsr #4"; + test_adds_64_zero, + adds(X1, XZR, ShiftedReg::from(X12).try_shift(ShiftMode::LSR, 4).unwrap()), + "adds x1, xzr, x12, lsr #4"; + test_adds_64_shift_2, + adds(X1, X2, ShiftedReg::from(X12).try_shift(ShiftMode::LSR, 4)).unwrap(), + "adds x1, x2, x12, lsr #4"; + test_adds_64_shift_3, + adds(X1, X2, (X12, ShiftMode::LSR, 4)).unwrap(), + "adds x1, x2, x12, lsr #4"; + test_adds_64_extend_uxtx, adds(RegZ(X1), RegS(X2), X12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "adds x1, x2, x12, uxtx #3"; + test_adds_64_extend_uxtx_2, adds(RegZ(X1), X2, (X12, ExtendMode::UXTX, 3)).unwrap(), + "adds x1, x2, x12, uxtx #3"; + // KLUDGE: Using Reg64 instead of Reg32 at the last argument. + // To be reimplemented akin `ldr` family. + test_adds_64_extend_uxtw, + adds(X1, X2, X12).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "adds x1, x2, w12, uxtw #3"; + test_adds_64_wzr_extend_uxtw, + adds(RegZ(X1), RegS(X2), XZR).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "adds x1, x2, wzr, uxtw #3"; + test_adds_64_extend_uxtx_4, + adds(X1, X2, X12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(4).unwrap()), + "adds x1, x2, x12, uxtx #4"; + test_adds_64_extend_uxth_xzr, + adds(RegZ(X1), RegS(X2), XZR).extend(ExtendMode::UXTH, ExtendShiftAmount::try_new(3).unwrap()), + "adds x1, x2, wzr, uxth #3"; + test_adds_64_const_1, adds(X1, X2, 1u32).unwrap(), "adds x1, x2, #1"; + test_adds_64_const_1_1, adds(X1, X2, AddSubImm12::try_from(1).unwrap()), "adds x1, x2, #1"; + test_adds_64_const_0x1000, adds(X1, X2, 0x1000).unwrap(), "adds x1, x2, #0x1000"; + test_adds_32, adds(W1, W2, W12), "adds w1, w2, w12"; + test_adds_32_shift, adds(W1, W2, W12).try_shift(ShiftMode::LSR, 4).unwrap(), "adds w1, w2, w12, lsr #4"; + test_adds_32_zero, + adds(W1, WZR, ShiftedReg::from(W12).try_shift(ShiftMode::LSR, 4).unwrap()), + "adds w1, wzr, w12, lsr #4"; + test_adds_32_extend_uxtx, + adds(W1, W2, W12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "adds w1, w2, w12, uxtx #3"; + test_adds_32_extend_uxtw, + adds(W1, W2, W12).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "adds w1, w2, w12, uxtw #3"; + test_adds_32_extend_uxtx_wzr, // that's really strange it works + adds(Reg3Z(W1), Reg3S(W2), WZR).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "adds w1, w2, wzr, uxtx #3"; + test_adds_32_extend_uxtw_wzr, + adds(Reg3Z(W1), Reg3S(W2), WZR).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "adds w1, w2, wzr, uxtw #3"; + test_adds_32_const_0x123, adds(W1, W2, 0x123).unwrap(), "adds w1, w2, #0x123"; + test_adds_32_const_0x123_1, adds(W1, W2, AddSubImm12::try_from(0x123)).unwrap(), "adds w1, w2, #0x123"; + test_adds_32_const_0x123000, adds(W1, W2, 0x123000).unwrap(), "adds w1, w2, #0x123000"; + } + + #[test] + fn test_adds_64_const_0x1001() { + let a = adds(X1, X2, 0x1001); + assert!(a.is_err()); + } + + #[test] + fn test_adds_32_const_0x1001() { + let a = adds(W1, W2, 0x1001); + assert!(a.is_err()); + } +} diff --git a/harm/src/instructions/arith/macros.rs b/harm/src/instructions/arith/macros.rs index 689d75b6..fbcb1d5c 100644 --- a/harm/src/instructions/arith/macros.rs +++ b/harm/src/instructions/arith/macros.rs @@ -175,14 +175,15 @@ macro_rules! define_arith_shift { } } + // TODO instead of u32, use Or, UBitValue<12, 12>>. macro_rules! define_arith_imm12 { - ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $etype:ty) => { + ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $dtype:ty, $etype:ty) => { ::paste::paste! { impl [] - for $name<$etype, $etype, $crate::instructions::arith::AddSubImm12> + for $name<$dtype, $etype, $crate::instructions::arith::AddSubImm12> where - Dst: IntoReg<$etype>, + Dst: IntoReg<$dtype>, Src: IntoReg<$etype>, { type Output = Result; @@ -199,9 +200,9 @@ macro_rules! define_arith_imm12 { } impl [] - for $name<$etype, $etype, $crate::instructions::arith::AddSubImm12> + for $name<$dtype, $etype, $crate::instructions::arith::AddSubImm12> where - Dst: IntoReg<$etype>, + Dst: IntoReg<$dtype>, Src1: IntoReg<$etype>, Src2: Into<$crate::instructions::arith::AddSubImm12>, { @@ -217,7 +218,7 @@ macro_rules! define_arith_imm12 { } } - impl RawInstruction for $name<$etype, $etype, $crate::instructions::arith::AddSubImm12> { + impl RawInstruction for $name<$dtype, $etype, $crate::instructions::arith::AddSubImm12> { #[inline] fn to_code(&self) -> InstructionCode { use $crate::instructions::arith::AddSubImm12::*; @@ -236,7 +237,7 @@ macro_rules! define_arith_imm12 { } macro_rules! define_arith_extend { - ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $stype:ty, $ztype:ty) => { + ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $stype:ty, $dtype:ty, $ztype:ty) => { ::paste::paste! { impl $name<$reg, $reg, $reg> { #[inline] @@ -244,9 +245,9 @@ macro_rules! define_arith_extend { self, mode: ExtendMode, amount: ExtendShiftAmount, - ) -> $name<$stype, $stype, ExtendedReg<$ztype>> { + ) -> $name<$dtype, $stype, ExtendedReg<$ztype>> { $name::new( - <$stype>::Reg(self.dst), + <$dtype>::Reg(self.dst), <$stype>::Reg(self.src1), ExtendedReg::new(<$ztype>::Reg(self.src2)), ) @@ -254,38 +255,38 @@ macro_rules! define_arith_extend { } } - impl []<$stype, Src1, Src2> for $name<$stype, $stype, $ztype> + impl []<$dtype, Src1, Src2> for $name<$dtype, $stype, $ztype> where Src1: IntoReg<$stype>, Src2: IntoReg<$ztype> { type Output = Self; #[inline] - fn new(dst: $stype, src1: Src1, src2: Src2) -> Self { + fn new(dst: $dtype, src1: Src1, src2: Src2) -> Self { Self { dst, src1: src1.into_reg(), src2: src2.into_reg() } } } - impl $name<$stype, $stype, $reg> { + impl $name<$dtype, $stype, $reg> { #[inline] pub fn extend( self, mode: ExtendMode, amount: ExtendShiftAmount, - ) -> $name<$stype, $stype, ExtendedReg<$ztype>> { + ) -> $name<$dtype, $stype, ExtendedReg<$ztype>> { $name::new(self.dst, self.src1, ExtendedReg::new(self.src2.into())) .extend(mode, amount) } } - impl []<$stype, $stype, ExtendedReg<$ztype>> - for $name<$stype, $stype, ExtendedReg<$ztype>> + impl []<$dtype, $stype, ExtendedReg<$ztype>> + for $name<$dtype, $stype, ExtendedReg<$ztype>> { type Output = Self; #[inline] fn new( - dst: $stype, + dst: $dtype, src1: $stype, src2: ExtendedReg<$ztype>, ) -> Self { @@ -293,7 +294,7 @@ macro_rules! define_arith_extend { } } - impl $name<$stype, $stype, ExtendedReg<$ztype>> { + impl $name<$dtype, $stype, ExtendedReg<$ztype>> { #[inline] pub fn extend(mut self, mode: ExtendMode, amount: ExtendShiftAmount) -> Self { self.src2.extend = Extend { mode, amount }; @@ -301,15 +302,15 @@ macro_rules! define_arith_extend { } } - impl $name<$stype, $stype, $ztype> { + impl $name<$dtype, $stype, $ztype> { #[inline] - pub fn extend(self, mode: ExtendMode, amount: ExtendShiftAmount) -> $name<$stype, $stype, ExtendedReg<$ztype>> { + pub fn extend(self, mode: ExtendMode, amount: ExtendShiftAmount) -> $name<$dtype, $stype, ExtendedReg<$ztype>> { $name::new(self.dst, self.src1, ExtendedReg::new(self.src2)) .extend(mode, amount) } } - impl RawInstruction for $name<$stype, $stype, ExtendedReg<$ztype>> { + impl RawInstruction for $name<$dtype, $stype, ExtendedReg<$ztype>> { #[inline] fn to_code(&self) -> InstructionCode { let option = self.src2.extend.mode as u8; @@ -325,9 +326,9 @@ macro_rules! define_arith_extend { } impl [] - for $name<$stype, $stype, ExtendedReg<$ztype>> + for $name<$dtype, $stype, ExtendedReg<$ztype>> where - Dst: IntoReg<$stype>, + Dst: IntoReg<$dtype>, Src1: IntoReg<$stype>, Src2: IntoReg<$ztype>, { @@ -345,9 +346,9 @@ macro_rules! define_arith_extend { } impl [] - for $name<$stype, $stype, ExtendedReg<$ztype>> + for $name<$dtype, $stype, ExtendedReg<$ztype>> where - Dst: IntoReg<$stype>, + Dst: IntoReg<$dtype>, Src1: IntoReg<$stype>, Src2: IntoReg<$ztype>, { @@ -365,9 +366,9 @@ macro_rules! define_arith_extend { } impl [] - for $name<$stype, $stype, ExtendedReg<$ztype>> + for $name<$dtype, $stype, ExtendedReg<$ztype>> where - Dst: IntoReg<$stype>, + Dst: IntoReg<$dtype>, Src1: IntoReg<$stype>, Src2: IntoReg<$ztype>, { diff --git a/harm/src/instructions/arith/sub.rs b/harm/src/instructions/arith/sub.rs index db45def7..3c3f7e32 100644 --- a/harm/src/instructions/arith/sub.rs +++ b/harm/src/instructions/arith/sub.rs @@ -69,11 +69,11 @@ define_arith_faillible!(Sub); define_arith_shift!(Sub, 32, addsub, Reg32, RegOrZero32); define_arith_shift!(Sub, 64, addsub, Reg64, RegOrZero64); -define_arith_extend!(Sub, 32, addsub, Reg32, RegOrSp32, RegOrZero32); -define_arith_extend!(Sub, 64, addsub, Reg64, RegOrSp64, RegOrZero64); +define_arith_extend!(Sub, 32, addsub, Reg32, RegOrSp32, RegOrSp32, RegOrZero32); +define_arith_extend!(Sub, 64, addsub, Reg64, RegOrSp64, RegOrSp64, RegOrZero64); -define_arith_imm12!(Sub, 32, addsub, Reg32, RegOrSp32); -define_arith_imm12!(Sub, 64, addsub, Reg64, RegOrSp64); +define_arith_imm12!(Sub, 32, addsub, Reg32, RegOrSp32, RegOrSp32); +define_arith_imm12!(Sub, 64, addsub, Reg64, RegOrSp64, RegOrSp64); #[cfg(test)] mod tests { diff --git a/harm/src/instructions/arith/subs.rs b/harm/src/instructions/arith/subs.rs new file mode 100644 index 00000000..34e59502 --- /dev/null +++ b/harm/src/instructions/arith/subs.rs @@ -0,0 +1,206 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::{ + dpimm::addsub_imm::{ + SUBS_32S_addsub_imm::SUBS_32S_addsub_imm, SUBS_64S_addsub_imm::SUBS_64S_addsub_imm, + }, + dpreg::{ + addsub_ext::{ + SUBS_32S_addsub_ext::SUBS_32S_addsub_ext, SUBS_64S_addsub_ext::SUBS_64S_addsub_ext, + }, + addsub_shift::{ + SUBS_32_addsub_shift::SUBS_32_addsub_shift, SUBS_64_addsub_shift::SUBS_64_addsub_shift, + }, + }, +}; +use aarchmrs_types::InstructionCode; + +use super::*; +use crate::{ + bits::BitError, + instructions::RawInstruction, + register::{ + IntoReg, Reg32, Reg64, RegOrSp32, RegOrSp64, RegOrZero32, RegOrZero64, Register as _, + }, + sealed::Sealed, +}; + +pub fn subs( + dst: T, + src1: S1, + src2: S2, +) -> as MakeSubs>::Output +where + Subs: MakeSubs, +{ + Subs::::new(dst, src1, src2) +} + +pub trait MakeSubs: Sealed { + type Output; + + fn new(dst: T, src1: S1, src2: S2) -> Self::Output; +} + +pub struct Subs { + pub dst: T, + pub src1: S1, + pub src2: S2, +} + +impl Sealed for Subs {} + +impl MakeSubs for Subs { + type Output = Self; + + #[inline] + fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self { + Self { dst, src1, src2 } + } +} + +impl MakeSubs for Subs { + type Output = Self; + + #[inline] + fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self { + Self { dst, src1, src2 } + } +} + +define_arith_faillible!(Subs); + +define_arith_shift!(Subs, 32, addsub, Reg32, RegOrZero32); +define_arith_shift!(Subs, 64, addsub, Reg64, RegOrZero64); + +define_arith_extend!( + Subs, + 32S, + addsub, + Reg32, + RegOrSp32, + RegOrZero32, + RegOrZero32 +); +define_arith_extend!( + Subs, + 64S, + addsub, + Reg64, + RegOrSp64, + RegOrZero64, + RegOrZero64 +); + +define_arith_imm12!(Subs, 32S, addsub, Reg32, RegOrZero32, RegOrSp32); +define_arith_imm12!(Subs, 64S, addsub, Reg64, RegOrZero64, RegOrSp64); + +#[cfg(test)] +mod tests { + use harm_test_utils::test_cases; + + use super::*; + use crate::instructions::InstructionSeq; + use crate::instructions::arith::AddSubImm12; + use Reg32::*; + use Reg64::*; + use RegOrSp32::Reg as Reg3S; + use RegOrSp64::Reg as RegS; + use RegOrZero32::Reg as Reg3Z; + use RegOrZero32::WZR; + use RegOrZero64::Reg as RegZ; + use RegOrZero64::XZR; + + const SUBS_DB: &str = " +eb3f2c41 subs x1, x2, wzr, uxth #3 +6b0c0041 subs w1, w2, w12 +6b2c6c41 subs w1, w2, w12, uxtx #3 +6b2c4c41 subs w1, w2, w12, uxtw #3 +6b3f6c41 subs w1, w2, wzr, uxtx #3 +6b3f4c41 subs w1, w2, wzr, uxtw #3 +6b4c1041 subs w1, w2, w12, lsr #4 +6b4c13e1 subs w1, wzr, w12, lsr #4 +71048c41 subs w1, w2, #0x123 +71448c41 subs w1, w2, #0x123000 +eb0c0041 subs x1, x2, x12 +eb2c4c41 subs x1, x2, w12, uxtw #3 +eb2c6c41 subs x1, x2, x12, uxtx #3 +eb2c7041 subs x1, x2, x12, uxtx #4 +eb3f4c41 subs x1, x2, wzr, uxtw #3 +eb4c1041 subs x1, x2, x12, lsr #4 +eb4c13e1 subs x1, xzr, x12, lsr #4 +f1000441 subs x1, x2, #1 +f1400441 subs x1, x2, #0x1000 +"; + + test_cases! { + SUBS_DB, untested_adds_db; + test_subs_64, subs(X1, X2, X12), "subs x1, x2, x12"; + test_subs_64_shift, subs(X1, X2, X12).try_shift(ShiftMode::LSR, 4).unwrap(), "subs x1, x2, x12, lsr #4"; + test_subs_64_zero, + subs(X1, XZR, ShiftedReg::from(X12).try_shift(ShiftMode::LSR, 4).unwrap()), + "subs x1, xzr, x12, lsr #4"; + test_subs_64_shift_2, + subs(X1, X2, ShiftedReg::from(X12).try_shift(ShiftMode::LSR, 4)).unwrap(), + "subs x1, x2, x12, lsr #4"; + test_subs_64_shift_3, + subs(X1, X2, (X12, ShiftMode::LSR, 4)).unwrap(), + "subs x1, x2, x12, lsr #4"; + test_subs_64_extend_uxtx, subs(RegZ(X1), RegS(X2), X12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "subs x1, x2, x12, uxtx #3"; + test_subs_64_extend_uxtx_2, subs(RegZ(X1), X2, (X12, ExtendMode::UXTX, 3)).unwrap(), + "subs x1, x2, x12, uxtx #3"; + // KLUDGE: Using Reg64 instead of Reg32 at the last argument. + // To be reimplemented akin `ldr` family. + test_subs_64_extend_uxtw, + subs(X1, X2, X12).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "subs x1, x2, w12, uxtw #3"; + test_subs_64_wzr_extend_uxtw, + subs(RegZ(X1), RegS(X2), XZR).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "subs x1, x2, wzr, uxtw #3"; + test_subs_64_extend_uxtx_4, + subs(X1, X2, X12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(4).unwrap()), + "subs x1, x2, x12, uxtx #4"; + test_subs_64_extend_uxth_xzr, + subs(RegZ(X1), RegS(X2), XZR).extend(ExtendMode::UXTH, ExtendShiftAmount::try_new(3).unwrap()), + "subs x1, x2, wzr, uxth #3"; + test_subs_64_const_1, subs(X1, X2, 1u32).unwrap(), "subs x1, x2, #1"; + test_subs_64_const_1_1, subs(X1, X2, AddSubImm12::try_from(1).unwrap()), "subs x1, x2, #1"; + test_subs_64_const_0x1000, subs(X1, X2, 0x1000).unwrap(), "subs x1, x2, #0x1000"; + test_subs_32, subs(W1, W2, W12), "subs w1, w2, w12"; + test_subs_32_shift, subs(W1, W2, W12).try_shift(ShiftMode::LSR, 4).unwrap(), "subs w1, w2, w12, lsr #4"; + test_subs_32_zero, + subs(W1, WZR, ShiftedReg::from(W12).try_shift(ShiftMode::LSR, 4).unwrap()), + "subs w1, wzr, w12, lsr #4"; + test_subs_32_extend_uxtx, + subs(W1, W2, W12).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "subs w1, w2, w12, uxtx #3"; + test_subs_32_extend_uxtw, + subs(W1, W2, W12).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "subs w1, w2, w12, uxtw #3"; + test_subs_32_extend_uxtx_wzr, // that's really strange it works + subs(Reg3Z(W1), Reg3S(W2), WZR).extend(ExtendMode::UXTX, ExtendShiftAmount::try_new(3).unwrap()), + "subs w1, w2, wzr, uxtx #3"; + test_subs_32_extend_uxtw_wzr, + subs(Reg3Z(W1), Reg3S(W2), WZR).extend(ExtendMode::UXTW, ExtendShiftAmount::try_new(3).unwrap()), + "subs w1, w2, wzr, uxtw #3"; + test_subs_32_const_0x123, subs(W1, W2, 0x123).unwrap(), "subs w1, w2, #0x123"; + test_subs_32_const_0x123_1, subs(W1, W2, AddSubImm12::try_from(0x123)).unwrap(), "subs w1, w2, #0x123"; + test_subs_32_const_0x123000, subs(W1, W2, 0x123000).unwrap(), "subs w1, w2, #0x123000"; + } + + #[test] + fn test_subs_64_const_0x1001() { + let a = subs(X1, X2, 0x1001); + assert!(a.is_err()); + } + + #[test] + fn test_subs_32_const_0x1001() { + let a = subs(W1, W2, 0x1001); + assert!(a.is_err()); + } +} From eccc9970bc508df6562aecc678485776112de165 Mon Sep 17 00:00:00 2001 From: Ivan Boldyrev Date: Fri, 10 Jul 2026 09:49:48 +0200 Subject: [PATCH 2/3] Make arith macros consistent Change arg order, remove unused args. --- harm/src/instructions/arith/add.rs | 12 ++++++------ harm/src/instructions/arith/adds.rs | 18 ++++++++++-------- harm/src/instructions/arith/macros.rs | 7 +++---- harm/src/instructions/arith/sub.rs | 12 ++++++------ harm/src/instructions/arith/subs.rs | 18 ++++++++++-------- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/harm/src/instructions/arith/add.rs b/harm/src/instructions/arith/add.rs index 53a64076..71d633cd 100644 --- a/harm/src/instructions/arith/add.rs +++ b/harm/src/instructions/arith/add.rs @@ -70,14 +70,14 @@ impl MakeAdd for Add { define_arith_faillible!(Add); -define_arith_shift!(Add, 32, addsub, Reg32, RegOrZero32); -define_arith_shift!(Add, 64, addsub, Reg64, RegOrZero64); +define_arith_shift!(Add, 32, addsub, RegOrZero32, Reg32); +define_arith_shift!(Add, 64, addsub, RegOrZero64, Reg64); -define_arith_extend!(Add, 32, addsub, Reg32, RegOrSp32, RegOrSp32, RegOrZero32); -define_arith_extend!(Add, 64, addsub, Reg64, RegOrSp64, RegOrSp64, RegOrZero64); +define_arith_extend!(Add, 32, addsub, RegOrSp32, RegOrSp32, RegOrZero32, Reg32); +define_arith_extend!(Add, 64, addsub, RegOrSp64, RegOrSp64, RegOrZero64, Reg64); -define_arith_imm12!(Add, 32, addsub, Reg32, RegOrSp32, RegOrSp32); -define_arith_imm12!(Add, 64, addsub, Reg64, RegOrSp64, RegOrSp64); +define_arith_imm12!(Add, 32, addsub, RegOrSp32, RegOrSp32); +define_arith_imm12!(Add, 64, addsub, RegOrSp64, RegOrSp64); #[cfg(test)] mod tests { diff --git a/harm/src/instructions/arith/adds.rs b/harm/src/instructions/arith/adds.rs index f16bd594..45834bc0 100644 --- a/harm/src/instructions/arith/adds.rs +++ b/harm/src/instructions/arith/adds.rs @@ -73,30 +73,32 @@ impl MakeAdds for Adds { define_arith_faillible!(Adds); -define_arith_shift!(Adds, 32, addsub, Reg32, RegOrZero32); -define_arith_shift!(Adds, 64, addsub, Reg64, RegOrZero64); +define_arith_shift!(Adds, 32, addsub, RegOrZero32, Reg32); +define_arith_shift!(Adds, 64, addsub, RegOrZero64, Reg64); +// N.B.: `add`/`sub` use `RegOrSp{N}, RegOrSp{N}, RegOrZero{N}` define_arith_extend!( Adds, 32S, addsub, - Reg32, + RegOrZero32, RegOrSp32, RegOrZero32, - RegOrZero32 + Reg32 ); define_arith_extend!( Adds, 64S, addsub, - Reg64, + RegOrZero64, RegOrSp64, RegOrZero64, - RegOrZero64 + Reg64 ); -define_arith_imm12!(Adds, 32S, addsub, Reg32, RegOrZero32, RegOrSp32); -define_arith_imm12!(Adds, 64S, addsub, Reg64, RegOrZero64, RegOrSp64); +// N.B.: `add`/`sub` use `RegOrSp{N}, RegOrSp{N}` +define_arith_imm12!(Adds, 32S, addsub, RegOrZero32, RegOrSp32); +define_arith_imm12!(Adds, 64S, addsub, RegOrZero64, RegOrSp64); #[cfg(test)] mod tests { diff --git a/harm/src/instructions/arith/macros.rs b/harm/src/instructions/arith/macros.rs index fbcb1d5c..411b7fc3 100644 --- a/harm/src/instructions/arith/macros.rs +++ b/harm/src/instructions/arith/macros.rs @@ -21,7 +21,7 @@ macro_rules! define_arith_faillible { } macro_rules! define_arith_shift { - ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $ztype:ty) => { + ($name:ident, $bits:expr, $cmd:ident, $ztype:ty, $reg:ty) => { ::paste::paste! { impl $name<$reg, $reg, $reg> { #[inline] @@ -175,10 +175,9 @@ macro_rules! define_arith_shift { } } - // TODO instead of u32, use Or, UBitValue<12, 12>>. macro_rules! define_arith_imm12 { - ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $dtype:ty, $etype:ty) => { + ($name:ident, $bits:expr, $cmd:ident, $dtype:ty, $etype:ty) => { ::paste::paste! { impl [] for $name<$dtype, $etype, $crate::instructions::arith::AddSubImm12> @@ -237,7 +236,7 @@ macro_rules! define_arith_imm12 { } macro_rules! define_arith_extend { - ($name:ident, $bits:expr, $cmd:ident, $reg:ty, $stype:ty, $dtype:ty, $ztype:ty) => { + ($name:ident, $bits:expr, $cmd:ident, $dtype:ty, $stype:ty, $ztype:ty, $reg:ty) => { ::paste::paste! { impl $name<$reg, $reg, $reg> { #[inline] diff --git a/harm/src/instructions/arith/sub.rs b/harm/src/instructions/arith/sub.rs index 3c3f7e32..b2e52705 100644 --- a/harm/src/instructions/arith/sub.rs +++ b/harm/src/instructions/arith/sub.rs @@ -66,14 +66,14 @@ impl MakeSub for Sub { define_arith_faillible!(Sub); -define_arith_shift!(Sub, 32, addsub, Reg32, RegOrZero32); -define_arith_shift!(Sub, 64, addsub, Reg64, RegOrZero64); +define_arith_shift!(Sub, 32, addsub, RegOrZero32, Reg32); +define_arith_shift!(Sub, 64, addsub, RegOrZero64, Reg64); -define_arith_extend!(Sub, 32, addsub, Reg32, RegOrSp32, RegOrSp32, RegOrZero32); -define_arith_extend!(Sub, 64, addsub, Reg64, RegOrSp64, RegOrSp64, RegOrZero64); +define_arith_extend!(Sub, 32, addsub, RegOrSp32, RegOrSp32, RegOrZero32, Reg32); +define_arith_extend!(Sub, 64, addsub, RegOrSp64, RegOrSp64, RegOrZero64, Reg64); -define_arith_imm12!(Sub, 32, addsub, Reg32, RegOrSp32, RegOrSp32); -define_arith_imm12!(Sub, 64, addsub, Reg64, RegOrSp64, RegOrSp64); +define_arith_imm12!(Sub, 32, addsub, RegOrSp32, RegOrSp32); +define_arith_imm12!(Sub, 64, addsub, RegOrSp64, RegOrSp64); #[cfg(test)] mod tests { diff --git a/harm/src/instructions/arith/subs.rs b/harm/src/instructions/arith/subs.rs index 34e59502..57bb3431 100644 --- a/harm/src/instructions/arith/subs.rs +++ b/harm/src/instructions/arith/subs.rs @@ -73,30 +73,32 @@ impl MakeSubs for Subs { define_arith_faillible!(Subs); -define_arith_shift!(Subs, 32, addsub, Reg32, RegOrZero32); -define_arith_shift!(Subs, 64, addsub, Reg64, RegOrZero64); +define_arith_shift!(Subs, 32, addsub, RegOrZero32, Reg32); +define_arith_shift!(Subs, 64, addsub, RegOrZero64, Reg64); +// N.B.: `add`/`sub` use `RegOrSp{N}, RegOrSp{N}, RegOrZero{N}` define_arith_extend!( Subs, 32S, addsub, - Reg32, + RegOrZero32, RegOrSp32, RegOrZero32, - RegOrZero32 + Reg32 ); define_arith_extend!( Subs, 64S, addsub, - Reg64, + RegOrZero64, RegOrSp64, RegOrZero64, - RegOrZero64 + Reg64 ); -define_arith_imm12!(Subs, 32S, addsub, Reg32, RegOrZero32, RegOrSp32); -define_arith_imm12!(Subs, 64S, addsub, Reg64, RegOrZero64, RegOrSp64); +// N.B.: `add`/`sub` use `RegOrSp{N}, RegOrSp{N}` +define_arith_imm12!(Subs, 32S, addsub, RegOrZero32, RegOrSp32); +define_arith_imm12!(Subs, 64S, addsub, RegOrZero64, RegOrSp64); #[cfg(test)] mod tests { From c05c8b796adc19ded722ce19f96f8f5c834e0b66 Mon Sep 17 00:00:00 2001 From: Ivan Boldyrev Date: Fri, 10 Jul 2026 17:31:46 +0200 Subject: [PATCH 3/3] Review fixes --- harm/src/instructions/arith/subs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/harm/src/instructions/arith/subs.rs b/harm/src/instructions/arith/subs.rs index 57bb3431..8da01881 100644 --- a/harm/src/instructions/arith/subs.rs +++ b/harm/src/instructions/arith/subs.rs @@ -139,7 +139,7 @@ f1400441 subs x1, x2, #0x1000 "; test_cases! { - SUBS_DB, untested_adds_db; + SUBS_DB, untested_subs_db; test_subs_64, subs(X1, X2, X12), "subs x1, x2, x12"; test_subs_64_shift, subs(X1, X2, X12).try_shift(ShiftMode::LSR, 4).unwrap(), "subs x1, x2, x12, lsr #4"; test_subs_64_zero,