Skip to main content

cmov/backends/
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 = u16::from(*$dst);
31        let condition = u16::from($condition);
32        unsafe {
33            asm! {
34                $xor,
35                $instruction,
36                inout(reg) *$lhs => _,
37                in(reg) *$rhs,
38                inlateout(reg) tmp,
39                in(reg) condition,
40                options(pure, nomem, nostack),
41            };
42        }
43
44        *$dst = (tmp & 0xFF) as u8;
45    };
46}
47
48#[cfg_attr(docsrs, doc(cfg(true)))]
49impl Cmov for u16 {
50    #[inline]
51    fn cmovnz(&mut self, value: &Self, condition: Condition) {
52        cmov!("cmovnz {1:e}, {2:e}", self, value, condition);
53    }
54
55    #[inline]
56    fn cmovz(&mut self, value: &Self, condition: Condition) {
57        cmov!("cmovz {1:e}, {2:e}", self, value, condition);
58    }
59}
60
61#[cfg_attr(docsrs, doc(cfg(true)))]
62impl Cmov for u32 {
63    #[inline]
64    fn cmovnz(&mut self, value: &Self, condition: Condition) {
65        cmov!("cmovnz {1:e}, {2:e}", self, value, condition);
66    }
67
68    #[inline]
69    fn cmovz(&mut self, value: &Self, condition: Condition) {
70        cmov!("cmovz {1:e}, {2:e}", self, value, condition);
71    }
72}
73
74#[cfg(target_arch = "x86")]
75#[cfg_attr(docsrs, doc(cfg(true)))]
76impl Cmov for u64 {
77    #[inline]
78    fn cmovnz(&mut self, value: &Self, condition: Condition) {
79        let mut lo = (*self & u32::MAX as u64) as u32;
80        let mut hi = (*self >> 32) as u32;
81
82        lo.cmovnz(&((*value & u32::MAX as u64) as u32), condition);
83        hi.cmovnz(&((*value >> 32) as u32), condition);
84
85        *self = (lo as u64) | (hi as u64) << 32;
86    }
87
88    #[inline]
89    fn cmovz(&mut self, value: &Self, condition: Condition) {
90        let mut lo = (*self & u32::MAX as u64) as u32;
91        let mut hi = (*self >> 32) as u32;
92
93        lo.cmovz(&((*value & u32::MAX as u64) as u32), condition);
94        hi.cmovz(&((*value >> 32) as u32), condition);
95
96        *self = (lo as u64) | (hi as u64) << 32;
97    }
98}
99
100#[cfg(target_arch = "x86_64")]
101#[cfg_attr(docsrs, doc(cfg(true)))]
102impl Cmov for u64 {
103    #[inline]
104    fn cmovnz(&mut self, value: &Self, condition: Condition) {
105        cmov!("cmovnz {1:r}, {2:r}", self, value, condition);
106    }
107
108    #[inline]
109    fn cmovz(&mut self, value: &Self, condition: Condition) {
110        cmov!("cmovz {1:r}, {2:r}", self, value, condition);
111    }
112}
113
114#[cfg_attr(docsrs, doc(cfg(true)))]
115impl CmovEq for u16 {
116    #[inline]
117    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
118        cmov_eq!(
119            "xor {0:x}, {1:x}",
120            "cmovz {2:e}, {3:e}",
121            self,
122            rhs,
123            input,
124            output
125        );
126    }
127
128    #[inline]
129    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
130        cmov_eq!(
131            "xor {0:x}, {1:x}",
132            "cmovnz {2:e}, {3:e}",
133            self,
134            rhs,
135            input,
136            output
137        );
138    }
139}
140
141#[cfg_attr(docsrs, doc(cfg(true)))]
142impl CmovEq for u32 {
143    #[inline]
144    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
145        cmov_eq!(
146            "xor {0:e}, {1:e}",
147            "cmovz {2:e}, {3:e}",
148            self,
149            rhs,
150            input,
151            output
152        );
153    }
154
155    #[inline]
156    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
157        cmov_eq!(
158            "xor {0:e}, {1:e}",
159            "cmovnz {2:e}, {3:e}",
160            self,
161            rhs,
162            input,
163            output
164        );
165    }
166}
167
168#[cfg(target_arch = "x86")]
169#[cfg_attr(docsrs, doc(cfg(true)))]
170impl CmovEq for u64 {
171    #[inline]
172    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
173        let lo = (*self & u32::MAX as u64) as u32;
174        let hi = (*self >> 32) as u32;
175
176        let mut tmp = 1u8;
177        lo.cmovne(&((*rhs & u32::MAX as u64) as u32), 0, &mut tmp);
178        hi.cmovne(&((*rhs >> 32) as u32), 0, &mut tmp);
179        tmp.cmoveq(&0, input, output);
180    }
181
182    #[inline]
183    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
184        let lo = (*self & u32::MAX as u64) as u32;
185        let hi = (*self >> 32) as u32;
186
187        let mut tmp = 1u8;
188        lo.cmovne(&((*rhs & u32::MAX as u64) as u32), 0, &mut tmp);
189        hi.cmovne(&((*rhs >> 32) as u32), 0, &mut tmp);
190        tmp.cmoveq(&1, input, output);
191    }
192}
193
194#[cfg(target_arch = "x86_64")]
195#[cfg_attr(docsrs, doc(cfg(true)))]
196impl CmovEq for u64 {
197    #[inline]
198    fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
199        cmov_eq!(
200            "xor {0:r}, {1:r}",
201            "cmovz {2:r}, {3:r}",
202            self,
203            rhs,
204            input,
205            output
206        );
207    }
208
209    #[inline]
210    fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
211        cmov_eq!(
212            "xor {0:r}, {1:r}",
213            "cmovnz {2:r}, {3:r}",
214            self,
215            rhs,
216            input,
217            output
218        );
219    }
220}