asmkit/x86/features/BMI2.rs
1use crate::x86::assembler::*;
2use crate::x86::operands::*;
3use super::super::opcodes::*;
4use crate::core::emitter::*;
5use crate::core::operand::*;
6
7/// A dummy operand that represents no register. Here just for simplicity.
8const NOREG: Operand = Operand::new();
9
10/// `BZHI` (BZHI).
11/// BZHI copies the bits of the first source operand (the second operand) into the destination operand (the first operand) and clears the higher bits in the destination according to the INDEX value specified by the second source operand (the third operand). The INDEX is specified by bits 7:0 of the second source operand. The INDEX value is saturated at the value of OperandSize -1. CF is set, if the number contained in the 8 low bits of the third operand is greater than OperandSize -1.
12///
13///
14/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/BZHI.html).
15///
16/// Supported operand variants:
17///
18/// ```text
19/// +---+---------------+
20/// | # | Operands |
21/// +---+---------------+
22/// | 1 | Gpd, Gpd, Gpd |
23/// | 2 | Gpd, Mem, Gpd |
24/// | 3 | Gpq, Gpq, Gpq |
25/// | 4 | Gpq, Mem, Gpq |
26/// +---+---------------+
27/// ```
28pub trait BzhiEmitter<A, B, C> {
29 fn bzhi(&mut self, op0: A, op1: B, op2: C);
30}
31
32impl<'a> BzhiEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
33 fn bzhi(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
34 self.emit(BZHI32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
35 }
36}
37
38impl<'a> BzhiEmitter<Gpd, Mem, Gpd> for Assembler<'a> {
39 fn bzhi(&mut self, op0: Gpd, op1: Mem, op2: Gpd) {
40 self.emit(BZHI32RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
41 }
42}
43
44impl<'a> BzhiEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
45 fn bzhi(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
46 self.emit(BZHI64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
47 }
48}
49
50impl<'a> BzhiEmitter<Gpq, Mem, Gpq> for Assembler<'a> {
51 fn bzhi(&mut self, op0: Gpq, op1: Mem, op2: Gpq) {
52 self.emit(BZHI64RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
53 }
54}
55
56/// `MULX` (MULX).
57/// Performs an unsigned multiplication of the implicit source operand (EDX/RDX) and the specified source operand (the third operand) and stores the low half of the result in the second destination (second operand), the high half of the result in the first destination operand (first operand), without reading or writing the arithmetic flags. This enables efficient programming where the software can interleave add with carry operations and multiplications.
58///
59///
60/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/MULX.html).
61///
62/// Supported operand variants:
63///
64/// ```text
65/// +---+---------------+
66/// | # | Operands |
67/// +---+---------------+
68/// | 1 | Gpd, Gpd, Gpd |
69/// | 2 | Gpd, Gpd, Mem |
70/// | 3 | Gpq, Gpq, Gpq |
71/// | 4 | Gpq, Gpq, Mem |
72/// +---+---------------+
73/// ```
74pub trait MulxEmitter<A, B, C> {
75 fn mulx(&mut self, op0: A, op1: B, op2: C);
76}
77
78impl<'a> MulxEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
79 fn mulx(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
80 self.emit(MULX32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
81 }
82}
83
84impl<'a> MulxEmitter<Gpd, Gpd, Mem> for Assembler<'a> {
85 fn mulx(&mut self, op0: Gpd, op1: Gpd, op2: Mem) {
86 self.emit(MULX32RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
87 }
88}
89
90impl<'a> MulxEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
91 fn mulx(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
92 self.emit(MULX64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
93 }
94}
95
96impl<'a> MulxEmitter<Gpq, Gpq, Mem> for Assembler<'a> {
97 fn mulx(&mut self, op0: Gpq, op1: Gpq, op2: Mem) {
98 self.emit(MULX64RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
99 }
100}
101
102/// `PDEP` (PDEP).
103/// PDEP uses a mask in the second source operand (the third operand) to transfer/scatter contiguous low order bits in the first source operand (the second operand) into the destination (the first operand). PDEP takes the low bits from the first source operand and deposit them in the destination operand at the corresponding bit locations that are set in the second source operand (mask). All other bits (bits not set in mask) in destination are set to zero.
104///
105///
106/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/PDEP.html).
107///
108/// Supported operand variants:
109///
110/// ```text
111/// +---+---------------+
112/// | # | Operands |
113/// +---+---------------+
114/// | 1 | Gpd, Gpd, Gpd |
115/// | 2 | Gpd, Gpd, Mem |
116/// | 3 | Gpq, Gpq, Gpq |
117/// | 4 | Gpq, Gpq, Mem |
118/// +---+---------------+
119/// ```
120pub trait PdepEmitter<A, B, C> {
121 fn pdep(&mut self, op0: A, op1: B, op2: C);
122}
123
124impl<'a> PdepEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
125 fn pdep(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
126 self.emit(PDEP32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
127 }
128}
129
130impl<'a> PdepEmitter<Gpd, Gpd, Mem> for Assembler<'a> {
131 fn pdep(&mut self, op0: Gpd, op1: Gpd, op2: Mem) {
132 self.emit(PDEP32RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
133 }
134}
135
136impl<'a> PdepEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
137 fn pdep(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
138 self.emit(PDEP64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
139 }
140}
141
142impl<'a> PdepEmitter<Gpq, Gpq, Mem> for Assembler<'a> {
143 fn pdep(&mut self, op0: Gpq, op1: Gpq, op2: Mem) {
144 self.emit(PDEP64RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
145 }
146}
147
148/// `PEXT` (PEXT).
149/// PEXT uses a mask in the second source operand (the third operand) to transfer either contiguous or non-contiguous bits in the first source operand (the second operand) to contiguous low order bit positions in the destination (the first operand). For each bit set in the MASK, PEXT extracts the corresponding bits from the first source operand and writes them into contiguous lower bits of destination operand. The remaining upper bits of destination are zeroed.
150///
151///
152/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/PEXT.html).
153///
154/// Supported operand variants:
155///
156/// ```text
157/// +---+---------------+
158/// | # | Operands |
159/// +---+---------------+
160/// | 1 | Gpd, Gpd, Gpd |
161/// | 2 | Gpd, Gpd, Mem |
162/// | 3 | Gpq, Gpq, Gpq |
163/// | 4 | Gpq, Gpq, Mem |
164/// +---+---------------+
165/// ```
166pub trait PextEmitter<A, B, C> {
167 fn pext(&mut self, op0: A, op1: B, op2: C);
168}
169
170impl<'a> PextEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
171 fn pext(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
172 self.emit(PEXT32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
173 }
174}
175
176impl<'a> PextEmitter<Gpd, Gpd, Mem> for Assembler<'a> {
177 fn pext(&mut self, op0: Gpd, op1: Gpd, op2: Mem) {
178 self.emit(PEXT32RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
179 }
180}
181
182impl<'a> PextEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
183 fn pext(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
184 self.emit(PEXT64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
185 }
186}
187
188impl<'a> PextEmitter<Gpq, Gpq, Mem> for Assembler<'a> {
189 fn pext(&mut self, op0: Gpq, op1: Gpq, op2: Mem) {
190 self.emit(PEXT64RRM, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
191 }
192}
193
194/// `RORX` (RORX).
195/// Rotates the bits of second operand right by the count value specified in imm8 without affecting arithmetic flags. The RORX instruction does not read or write the arithmetic flags.
196///
197///
198/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/RORX.html).
199///
200/// Supported operand variants:
201///
202/// ```text
203/// +---+---------------+
204/// | # | Operands |
205/// +---+---------------+
206/// | 1 | Gpd, Gpd, Imm |
207/// | 2 | Gpd, Mem, Imm |
208/// | 3 | Gpq, Gpq, Imm |
209/// | 4 | Gpq, Mem, Imm |
210/// +---+---------------+
211/// ```
212pub trait RorxEmitter<A, B, C> {
213 fn rorx(&mut self, op0: A, op1: B, op2: C);
214}
215
216impl<'a> RorxEmitter<Gpd, Gpd, Imm> for Assembler<'a> {
217 fn rorx(&mut self, op0: Gpd, op1: Gpd, op2: Imm) {
218 self.emit(RORX32RRI, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
219 }
220}
221
222impl<'a> RorxEmitter<Gpd, Mem, Imm> for Assembler<'a> {
223 fn rorx(&mut self, op0: Gpd, op1: Mem, op2: Imm) {
224 self.emit(RORX32RMI, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
225 }
226}
227
228impl<'a> RorxEmitter<Gpq, Gpq, Imm> for Assembler<'a> {
229 fn rorx(&mut self, op0: Gpq, op1: Gpq, op2: Imm) {
230 self.emit(RORX64RRI, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
231 }
232}
233
234impl<'a> RorxEmitter<Gpq, Mem, Imm> for Assembler<'a> {
235 fn rorx(&mut self, op0: Gpq, op1: Mem, op2: Imm) {
236 self.emit(RORX64RMI, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
237 }
238}
239
240/// `SARX` (SARX).
241/// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
242///
243///
244/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
245///
246/// Supported operand variants:
247///
248/// ```text
249/// +---+---------------+
250/// | # | Operands |
251/// +---+---------------+
252/// | 1 | Gpd, Gpd, Gpd |
253/// | 2 | Gpd, Mem, Gpd |
254/// | 3 | Gpq, Gpq, Gpq |
255/// | 4 | Gpq, Mem, Gpq |
256/// +---+---------------+
257/// ```
258pub trait SarxEmitter<A, B, C> {
259 fn sarx(&mut self, op0: A, op1: B, op2: C);
260}
261
262impl<'a> SarxEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
263 fn sarx(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
264 self.emit(SARX32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
265 }
266}
267
268impl<'a> SarxEmitter<Gpd, Mem, Gpd> for Assembler<'a> {
269 fn sarx(&mut self, op0: Gpd, op1: Mem, op2: Gpd) {
270 self.emit(SARX32RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
271 }
272}
273
274impl<'a> SarxEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
275 fn sarx(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
276 self.emit(SARX64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
277 }
278}
279
280impl<'a> SarxEmitter<Gpq, Mem, Gpq> for Assembler<'a> {
281 fn sarx(&mut self, op0: Gpq, op1: Mem, op2: Gpq) {
282 self.emit(SARX64RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
283 }
284}
285
286/// `SHLX` (SHLX).
287/// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
288///
289///
290/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
291///
292/// Supported operand variants:
293///
294/// ```text
295/// +---+---------------+
296/// | # | Operands |
297/// +---+---------------+
298/// | 1 | Gpd, Gpd, Gpd |
299/// | 2 | Gpd, Mem, Gpd |
300/// | 3 | Gpq, Gpq, Gpq |
301/// | 4 | Gpq, Mem, Gpq |
302/// +---+---------------+
303/// ```
304pub trait ShlxEmitter<A, B, C> {
305 fn shlx(&mut self, op0: A, op1: B, op2: C);
306}
307
308impl<'a> ShlxEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
309 fn shlx(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
310 self.emit(SHLX32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
311 }
312}
313
314impl<'a> ShlxEmitter<Gpd, Mem, Gpd> for Assembler<'a> {
315 fn shlx(&mut self, op0: Gpd, op1: Mem, op2: Gpd) {
316 self.emit(SHLX32RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
317 }
318}
319
320impl<'a> ShlxEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
321 fn shlx(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
322 self.emit(SHLX64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
323 }
324}
325
326impl<'a> ShlxEmitter<Gpq, Mem, Gpq> for Assembler<'a> {
327 fn shlx(&mut self, op0: Gpq, op1: Mem, op2: Gpq) {
328 self.emit(SHLX64RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
329 }
330}
331
332/// `SHRX` (SHRX).
333/// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
334///
335///
336/// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
337///
338/// Supported operand variants:
339///
340/// ```text
341/// +---+---------------+
342/// | # | Operands |
343/// +---+---------------+
344/// | 1 | Gpd, Gpd, Gpd |
345/// | 2 | Gpd, Mem, Gpd |
346/// | 3 | Gpq, Gpq, Gpq |
347/// | 4 | Gpq, Mem, Gpq |
348/// +---+---------------+
349/// ```
350pub trait ShrxEmitter<A, B, C> {
351 fn shrx(&mut self, op0: A, op1: B, op2: C);
352}
353
354impl<'a> ShrxEmitter<Gpd, Gpd, Gpd> for Assembler<'a> {
355 fn shrx(&mut self, op0: Gpd, op1: Gpd, op2: Gpd) {
356 self.emit(SHRX32RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
357 }
358}
359
360impl<'a> ShrxEmitter<Gpd, Mem, Gpd> for Assembler<'a> {
361 fn shrx(&mut self, op0: Gpd, op1: Mem, op2: Gpd) {
362 self.emit(SHRX32RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
363 }
364}
365
366impl<'a> ShrxEmitter<Gpq, Gpq, Gpq> for Assembler<'a> {
367 fn shrx(&mut self, op0: Gpq, op1: Gpq, op2: Gpq) {
368 self.emit(SHRX64RRR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
369 }
370}
371
372impl<'a> ShrxEmitter<Gpq, Mem, Gpq> for Assembler<'a> {
373 fn shrx(&mut self, op0: Gpq, op1: Mem, op2: Gpq) {
374 self.emit(SHRX64RMR, op0.as_operand(), op1.as_operand(), op2.as_operand(), &NOREG);
375 }
376}
377
378
379impl<'a> Assembler<'a> {
380 /// `BZHI` (BZHI).
381 /// BZHI copies the bits of the first source operand (the second operand) into the destination operand (the first operand) and clears the higher bits in the destination according to the INDEX value specified by the second source operand (the third operand). The INDEX is specified by bits 7:0 of the second source operand. The INDEX value is saturated at the value of OperandSize -1. CF is set, if the number contained in the 8 low bits of the third operand is greater than OperandSize -1.
382 ///
383 ///
384 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/BZHI.html).
385 ///
386 /// Supported operand variants:
387 ///
388 /// ```text
389 /// +---+---------------+
390 /// | # | Operands |
391 /// +---+---------------+
392 /// | 1 | Gpd, Gpd, Gpd |
393 /// | 2 | Gpd, Mem, Gpd |
394 /// | 3 | Gpq, Gpq, Gpq |
395 /// | 4 | Gpq, Mem, Gpq |
396 /// +---+---------------+
397 /// ```
398 #[inline]
399 pub fn bzhi<A, B, C>(&mut self, op0: A, op1: B, op2: C)
400 where Assembler<'a>: BzhiEmitter<A, B, C> {
401 <Self as BzhiEmitter<A, B, C>>::bzhi(self, op0, op1, op2);
402 }
403 /// `MULX` (MULX).
404 /// Performs an unsigned multiplication of the implicit source operand (EDX/RDX) and the specified source operand (the third operand) and stores the low half of the result in the second destination (second operand), the high half of the result in the first destination operand (first operand), without reading or writing the arithmetic flags. This enables efficient programming where the software can interleave add with carry operations and multiplications.
405 ///
406 ///
407 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/MULX.html).
408 ///
409 /// Supported operand variants:
410 ///
411 /// ```text
412 /// +---+---------------+
413 /// | # | Operands |
414 /// +---+---------------+
415 /// | 1 | Gpd, Gpd, Gpd |
416 /// | 2 | Gpd, Gpd, Mem |
417 /// | 3 | Gpq, Gpq, Gpq |
418 /// | 4 | Gpq, Gpq, Mem |
419 /// +---+---------------+
420 /// ```
421 #[inline]
422 pub fn mulx<A, B, C>(&mut self, op0: A, op1: B, op2: C)
423 where Assembler<'a>: MulxEmitter<A, B, C> {
424 <Self as MulxEmitter<A, B, C>>::mulx(self, op0, op1, op2);
425 }
426 /// `PDEP` (PDEP).
427 /// PDEP uses a mask in the second source operand (the third operand) to transfer/scatter contiguous low order bits in the first source operand (the second operand) into the destination (the first operand). PDEP takes the low bits from the first source operand and deposit them in the destination operand at the corresponding bit locations that are set in the second source operand (mask). All other bits (bits not set in mask) in destination are set to zero.
428 ///
429 ///
430 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/PDEP.html).
431 ///
432 /// Supported operand variants:
433 ///
434 /// ```text
435 /// +---+---------------+
436 /// | # | Operands |
437 /// +---+---------------+
438 /// | 1 | Gpd, Gpd, Gpd |
439 /// | 2 | Gpd, Gpd, Mem |
440 /// | 3 | Gpq, Gpq, Gpq |
441 /// | 4 | Gpq, Gpq, Mem |
442 /// +---+---------------+
443 /// ```
444 #[inline]
445 pub fn pdep<A, B, C>(&mut self, op0: A, op1: B, op2: C)
446 where Assembler<'a>: PdepEmitter<A, B, C> {
447 <Self as PdepEmitter<A, B, C>>::pdep(self, op0, op1, op2);
448 }
449 /// `PEXT` (PEXT).
450 /// PEXT uses a mask in the second source operand (the third operand) to transfer either contiguous or non-contiguous bits in the first source operand (the second operand) to contiguous low order bit positions in the destination (the first operand). For each bit set in the MASK, PEXT extracts the corresponding bits from the first source operand and writes them into contiguous lower bits of destination operand. The remaining upper bits of destination are zeroed.
451 ///
452 ///
453 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/PEXT.html).
454 ///
455 /// Supported operand variants:
456 ///
457 /// ```text
458 /// +---+---------------+
459 /// | # | Operands |
460 /// +---+---------------+
461 /// | 1 | Gpd, Gpd, Gpd |
462 /// | 2 | Gpd, Gpd, Mem |
463 /// | 3 | Gpq, Gpq, Gpq |
464 /// | 4 | Gpq, Gpq, Mem |
465 /// +---+---------------+
466 /// ```
467 #[inline]
468 pub fn pext<A, B, C>(&mut self, op0: A, op1: B, op2: C)
469 where Assembler<'a>: PextEmitter<A, B, C> {
470 <Self as PextEmitter<A, B, C>>::pext(self, op0, op1, op2);
471 }
472 /// `RORX` (RORX).
473 /// Rotates the bits of second operand right by the count value specified in imm8 without affecting arithmetic flags. The RORX instruction does not read or write the arithmetic flags.
474 ///
475 ///
476 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/RORX.html).
477 ///
478 /// Supported operand variants:
479 ///
480 /// ```text
481 /// +---+---------------+
482 /// | # | Operands |
483 /// +---+---------------+
484 /// | 1 | Gpd, Gpd, Imm |
485 /// | 2 | Gpd, Mem, Imm |
486 /// | 3 | Gpq, Gpq, Imm |
487 /// | 4 | Gpq, Mem, Imm |
488 /// +---+---------------+
489 /// ```
490 #[inline]
491 pub fn rorx<A, B, C>(&mut self, op0: A, op1: B, op2: C)
492 where Assembler<'a>: RorxEmitter<A, B, C> {
493 <Self as RorxEmitter<A, B, C>>::rorx(self, op0, op1, op2);
494 }
495 /// `SARX` (SARX).
496 /// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
497 ///
498 ///
499 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
500 ///
501 /// Supported operand variants:
502 ///
503 /// ```text
504 /// +---+---------------+
505 /// | # | Operands |
506 /// +---+---------------+
507 /// | 1 | Gpd, Gpd, Gpd |
508 /// | 2 | Gpd, Mem, Gpd |
509 /// | 3 | Gpq, Gpq, Gpq |
510 /// | 4 | Gpq, Mem, Gpq |
511 /// +---+---------------+
512 /// ```
513 #[inline]
514 pub fn sarx<A, B, C>(&mut self, op0: A, op1: B, op2: C)
515 where Assembler<'a>: SarxEmitter<A, B, C> {
516 <Self as SarxEmitter<A, B, C>>::sarx(self, op0, op1, op2);
517 }
518 /// `SHLX` (SHLX).
519 /// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
520 ///
521 ///
522 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
523 ///
524 /// Supported operand variants:
525 ///
526 /// ```text
527 /// +---+---------------+
528 /// | # | Operands |
529 /// +---+---------------+
530 /// | 1 | Gpd, Gpd, Gpd |
531 /// | 2 | Gpd, Mem, Gpd |
532 /// | 3 | Gpq, Gpq, Gpq |
533 /// | 4 | Gpq, Mem, Gpq |
534 /// +---+---------------+
535 /// ```
536 #[inline]
537 pub fn shlx<A, B, C>(&mut self, op0: A, op1: B, op2: C)
538 where Assembler<'a>: ShlxEmitter<A, B, C> {
539 <Self as ShlxEmitter<A, B, C>>::shlx(self, op0, op1, op2);
540 }
541 /// `SHRX` (SHRX).
542 /// Shifts the bits of the first source operand (the second operand) to the left or right by a COUNT value specified in the second source operand (the third operand). The result is written to the destination operand (the first operand).
543 ///
544 ///
545 /// For more details, see the [Intel manual](https://www.felixcloutier.com/x86/SARX%3ASHLX%3ASHRX.html).
546 ///
547 /// Supported operand variants:
548 ///
549 /// ```text
550 /// +---+---------------+
551 /// | # | Operands |
552 /// +---+---------------+
553 /// | 1 | Gpd, Gpd, Gpd |
554 /// | 2 | Gpd, Mem, Gpd |
555 /// | 3 | Gpq, Gpq, Gpq |
556 /// | 4 | Gpq, Mem, Gpq |
557 /// +---+---------------+
558 /// ```
559 #[inline]
560 pub fn shrx<A, B, C>(&mut self, op0: A, op1: B, op2: C)
561 where Assembler<'a>: ShrxEmitter<A, B, C> {
562 <Self as ShrxEmitter<A, B, C>>::shrx(self, op0, op1, op2);
563 }
564}