1use 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}