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 = *$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}