cmov/
x86.rs

1//! From "AMD64 Architecture Programmer’s Manual, Volume 1: Application Programming"
2//! (Rev. 3.23 - October 2020) page 46:
3//!
4//! <https://www.amd.com/system/files/TechDocs/24592.pdf>
5//!
6//! > The CMOVcc instructions conditionally copy a word, doubleword, or
7//! > quadword from a register or memory location to a register location.
8//! > The source and destination must be of the same size.
9
10use crate::{Cmov, CmovEq, Condition};
11use core::arch::asm;
12
13macro_rules! cmov {
14    ($instruction:expr, $dst:expr, $src:expr, $condition:expr) => {
15        unsafe {
16            asm! {
17                "test {0}, {0}",
18                $instruction,
19                in(reg_byte) $condition,
20                inlateout(reg) *$dst,
21                in(reg) *$src,
22                options(pure, nomem, nostack),
23            };
24        }
25    };
26}
27
28macro_rules! cmov_eq {
29    ($xor:expr, $instruction:expr, $lhs:expr, $rhs:expr, $condition:expr, $dst:expr) => {
30        let mut tmp = *$dst as u16;
31        unsafe {
32            asm! {
33                $xor,
34                $instruction,
35                inout(reg) *$lhs => _,
36                in(reg) *$rhs,
37                inlateout(reg) tmp,
38                in(reg) $condition as u16,
39                options(pure, nomem, nostack),
40            };
41        }
42        *$dst = tmp as u8;
43    };
44}
45
46impl Cmov for u16 {
47    #[inline]
48    fn cmovnz(&mut self, value: &Self, condition: Condition) {
49        cmov!("cmovnz {1:e}, {2:e}", self, value, condition);
50    }
51
52    #[inline]
53    fn cmovz(&mut self, value: &Self, condition: Condition) {
54        cmov!("cmovz {1:e}, {2:e}", self, value, condition);
55    }
56}
57
58impl CmovEq for u16 {
59    #[inline]
60    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
61        cmov_eq!(
62            "xor {0:x}, {1:x}",
63            "cmovz {2:e}, {3:e}",
64            self,
65            rhs,
66            input,
67            output
68        );
69    }
70
71    #[inline]
72    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
73        cmov_eq!(
74            "xor {0:x}, {1:x}",
75            "cmovnz {2:e}, {3:e}",
76            self,
77            rhs,
78            input,
79            output
80        );
81    }
82}
83
84impl Cmov for u32 {
85    #[inline]
86    fn cmovnz(&mut self, value: &Self, condition: Condition) {
87        cmov!("cmovnz {1:e}, {2:e}", self, value, condition);
88    }
89
90    #[inline]
91    fn cmovz(&mut self, value: &Self, condition: Condition) {
92        cmov!("cmovz {1:e}, {2:e}", self, value, condition);
93    }
94}
95
96impl CmovEq for u32 {
97    #[inline]
98    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
99        cmov_eq!(
100            "xor {0:e}, {1:e}",
101            "cmovz {2:e}, {3:e}",
102            self,
103            rhs,
104            input,
105            output
106        );
107    }
108
109    #[inline]
110    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
111        cmov_eq!(
112            "xor {0:e}, {1:e}",
113            "cmovnz {2:e}, {3:e}",
114            self,
115            rhs,
116            input,
117            output
118        );
119    }
120}
121
122#[cfg(target_arch = "x86")]
123impl Cmov for u64 {
124    #[inline]
125    fn cmovnz(&mut self, value: &Self, condition: Condition) {
126        let mut lo = (*self & u32::MAX as u64) as u32;
127        let mut hi = (*self >> 32) as u32;
128
129        lo.cmovnz(&((*value & u32::MAX as u64) as u32), condition);
130        hi.cmovnz(&((*value >> 32) as u32), condition);
131
132        *self = (lo as u64) | (hi as u64) << 32;
133    }
134
135    #[inline]
136    fn cmovz(&mut self, value: &Self, condition: Condition) {
137        let mut lo = (*self & u32::MAX as u64) as u32;
138        let mut hi = (*self >> 32) as u32;
139
140        lo.cmovz(&((*value & u32::MAX as u64) as u32), condition);
141        hi.cmovz(&((*value >> 32) as u32), condition);
142
143        *self = (lo as u64) | (hi as u64) << 32;
144    }
145}
146
147#[cfg(target_arch = "x86")]
148impl CmovEq for u64 {
149    #[inline]
150    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
151        let lo = (*self & u32::MAX as u64) as u32;
152        let hi = (*self >> 32) as u32;
153
154        let mut tmp = 1u8;
155        lo.cmovne(&((*rhs & u32::MAX as u64) as u32), 0, &mut tmp);
156        hi.cmovne(&((*rhs >> 32) as u32), 0, &mut tmp);
157        tmp.cmoveq(&0, input, output);
158    }
159
160    #[inline]
161    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
162        let lo = (*self & u32::MAX as u64) as u32;
163        let hi = (*self >> 32) as u32;
164
165        let mut tmp = 1u8;
166        lo.cmovne(&((*rhs & u32::MAX as u64) as u32), 0, &mut tmp);
167        hi.cmovne(&((*rhs >> 32) as u32), 0, &mut tmp);
168        tmp.cmoveq(&1, input, output);
169    }
170}
171
172#[cfg(target_arch = "x86_64")]
173impl Cmov for u64 {
174    #[inline]
175    fn cmovnz(&mut self, value: &Self, condition: Condition) {
176        cmov!("cmovnz {1:r}, {2:r}", self, value, condition);
177    }
178
179    #[inline]
180    fn cmovz(&mut self, value: &Self, condition: Condition) {
181        cmov!("cmovz {1:r}, {2:r}", self, value, condition);
182    }
183}
184
185#[cfg(target_arch = "x86_64")]
186impl CmovEq for u64 {
187    #[inline]
188    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
189        cmov_eq!(
190            "xor {0:r}, {1:r}",
191            "cmovz {2:r}, {3:r}",
192            self,
193            rhs,
194            input,
195            output
196        );
197    }
198
199    #[inline]
200    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
201        cmov_eq!(
202            "xor {0:r}, {1:r}",
203            "cmovnz {2:r}, {3:r}",
204            self,
205            rhs,
206            input,
207            output
208        );
209    }
210}