1 #![allow(non_snake_case)]
2 
3 use crate::cdsl::instructions::{
4     AllInstructions, InstructionBuilder as Inst, InstructionGroup, InstructionGroupBuilder,
5 };
6 use crate::cdsl::operands::Operand;
7 use crate::cdsl::types::ValueType;
8 use crate::cdsl::typevar::{Interval, TypeSetBuilder, TypeVar};
9 use crate::shared::entities::EntityRefs;
10 use crate::shared::formats::Formats;
11 use crate::shared::immediates::Immediates;
12 use crate::shared::types;
13 
14 #[allow(clippy::many_single_char_names)]
define( mut all_instructions: &mut AllInstructions, formats: &Formats, immediates: &Immediates, entities: &EntityRefs, ) -> InstructionGroup15 pub(crate) fn define(
16     mut all_instructions: &mut AllInstructions,
17     formats: &Formats,
18     immediates: &Immediates,
19     entities: &EntityRefs,
20 ) -> InstructionGroup {
21     let mut ig = InstructionGroupBuilder::new(&mut all_instructions);
22 
23     let iflags: &TypeVar = &ValueType::Special(types::Flag::IFlags.into()).into();
24 
25     let iWord = &TypeVar::new(
26         "iWord",
27         "A scalar integer machine word",
28         TypeSetBuilder::new().ints(32..64).build(),
29     );
30     let nlo = &Operand::new("nlo", iWord).with_doc("Low part of numerator");
31     let nhi = &Operand::new("nhi", iWord).with_doc("High part of numerator");
32     let d = &Operand::new("d", iWord).with_doc("Denominator");
33     let q = &Operand::new("q", iWord).with_doc("Quotient");
34     let r = &Operand::new("r", iWord).with_doc("Remainder");
35 
36     ig.push(
37         Inst::new(
38             "x86_udivmodx",
39             r#"
40         Extended unsigned division.
41 
42         Concatenate the bits in `nhi` and `nlo` to form the numerator.
43         Interpret the bits as an unsigned number and divide by the unsigned
44         denominator `d`. Trap when `d` is zero or if the quotient is larger
45         than the range of the output.
46 
47         Return both quotient and remainder.
48         "#,
49             &formats.ternary,
50         )
51         .operands_in(vec![nlo, nhi, d])
52         .operands_out(vec![q, r])
53         .can_trap(true),
54     );
55 
56     ig.push(
57         Inst::new(
58             "x86_sdivmodx",
59             r#"
60         Extended signed division.
61 
62         Concatenate the bits in `nhi` and `nlo` to form the numerator.
63         Interpret the bits as a signed number and divide by the signed
64         denominator `d`. Trap when `d` is zero or if the quotient is outside
65         the range of the output.
66 
67         Return both quotient and remainder.
68         "#,
69             &formats.ternary,
70         )
71         .operands_in(vec![nlo, nhi, d])
72         .operands_out(vec![q, r])
73         .can_trap(true),
74     );
75 
76     let argL = &Operand::new("argL", iWord);
77     let argR = &Operand::new("argR", iWord);
78     let resLo = &Operand::new("resLo", iWord);
79     let resHi = &Operand::new("resHi", iWord);
80 
81     ig.push(
82         Inst::new(
83             "x86_umulx",
84             r#"
85         Unsigned integer multiplication, producing a double-length result.
86 
87         Polymorphic over all scalar integer types, but does not support vector
88         types.
89         "#,
90             &formats.binary,
91         )
92         .operands_in(vec![argL, argR])
93         .operands_out(vec![resLo, resHi]),
94     );
95 
96     ig.push(
97         Inst::new(
98             "x86_smulx",
99             r#"
100         Signed integer multiplication, producing a double-length result.
101 
102         Polymorphic over all scalar integer types, but does not support vector
103         types.
104         "#,
105             &formats.binary,
106         )
107         .operands_in(vec![argL, argR])
108         .operands_out(vec![resLo, resHi]),
109     );
110 
111     let Float = &TypeVar::new(
112         "Float",
113         "A scalar or vector floating point number",
114         TypeSetBuilder::new()
115             .floats(Interval::All)
116             .simd_lanes(Interval::All)
117             .build(),
118     );
119     let IntTo = &TypeVar::new(
120         "IntTo",
121         "An integer type with the same number of lanes",
122         TypeSetBuilder::new()
123             .ints(32..64)
124             .simd_lanes(Interval::All)
125             .build(),
126     );
127     let x = &Operand::new("x", Float);
128     let a = &Operand::new("a", IntTo);
129 
130     ig.push(
131         Inst::new(
132             "x86_cvtt2si",
133             r#"
134         Convert with truncation floating point to signed integer.
135 
136         The source floating point operand is converted to a signed integer by
137         rounding towards zero. If the result can't be represented in the output
138         type, returns the smallest signed value the output type can represent.
139 
140         This instruction does not trap.
141         "#,
142             &formats.unary,
143         )
144         .operands_in(vec![x])
145         .operands_out(vec![a]),
146     );
147 
148     let x = &Operand::new("x", Float);
149     let a = &Operand::new("a", Float);
150     let y = &Operand::new("y", Float);
151 
152     ig.push(
153         Inst::new(
154             "x86_fmin",
155             r#"
156         Floating point minimum with x86 semantics.
157 
158         This is equivalent to the C ternary operator `x < y ? x : y` which
159         differs from `fmin` when either operand is NaN or when comparing
160         +0.0 to -0.0.
161 
162         When the two operands don't compare as LT, `y` is returned unchanged,
163         even if it is a signalling NaN.
164         "#,
165             &formats.binary,
166         )
167         .operands_in(vec![x, y])
168         .operands_out(vec![a]),
169     );
170 
171     ig.push(
172         Inst::new(
173             "x86_fmax",
174             r#"
175         Floating point maximum with x86 semantics.
176 
177         This is equivalent to the C ternary operator `x > y ? x : y` which
178         differs from `fmax` when either operand is NaN or when comparing
179         +0.0 to -0.0.
180 
181         When the two operands don't compare as GT, `y` is returned unchanged,
182         even if it is a signalling NaN.
183         "#,
184             &formats.binary,
185         )
186         .operands_in(vec![x, y])
187         .operands_out(vec![a]),
188     );
189 
190     let x = &Operand::new("x", iWord);
191 
192     ig.push(
193         Inst::new(
194             "x86_push",
195             r#"
196     Pushes a value onto the stack.
197 
198     Decrements the stack pointer and stores the specified value on to the top.
199 
200     This is polymorphic in i32 and i64. However, it is only implemented for i64
201     in 64-bit mode, and only for i32 in 32-bit mode.
202     "#,
203             &formats.unary,
204         )
205         .operands_in(vec![x])
206         .other_side_effects(true)
207         .can_store(true),
208     );
209 
210     ig.push(
211         Inst::new(
212             "x86_pop",
213             r#"
214     Pops a value from the stack.
215 
216     Loads a value from the top of the stack and then increments the stack
217     pointer.
218 
219     This is polymorphic in i32 and i64. However, it is only implemented for i64
220     in 64-bit mode, and only for i32 in 32-bit mode.
221     "#,
222             &formats.nullary,
223         )
224         .operands_out(vec![x])
225         .other_side_effects(true)
226         .can_load(true),
227     );
228 
229     let y = &Operand::new("y", iWord);
230     let rflags = &Operand::new("rflags", iflags);
231 
232     ig.push(
233         Inst::new(
234             "x86_bsr",
235             r#"
236     Bit Scan Reverse -- returns the bit-index of the most significant 1
237     in the word. Result is undefined if the argument is zero. However, it
238     sets the Z flag depending on the argument, so it is at least easy to
239     detect and handle that case.
240 
241     This is polymorphic in i32 and i64. It is implemented for both i64 and
242     i32 in 64-bit mode, and only for i32 in 32-bit mode.
243     "#,
244             &formats.unary,
245         )
246         .operands_in(vec![x])
247         .operands_out(vec![y, rflags]),
248     );
249 
250     ig.push(
251         Inst::new(
252             "x86_bsf",
253             r#"
254     Bit Scan Forwards -- returns the bit-index of the least significant 1
255     in the word. Is otherwise identical to 'bsr', just above.
256     "#,
257             &formats.unary,
258         )
259         .operands_in(vec![x])
260         .operands_out(vec![y, rflags]),
261     );
262 
263     let uimm8 = &immediates.uimm8;
264     let TxN = &TypeVar::new(
265         "TxN",
266         "A SIMD vector type",
267         TypeSetBuilder::new()
268             .ints(Interval::All)
269             .floats(Interval::All)
270             .bools(Interval::All)
271             .simd_lanes(Interval::All)
272             .includes_scalars(false)
273             .build(),
274     );
275     let a = &Operand::new("a", TxN).with_doc("A vector value (i.e. held in an XMM register)");
276     let b = &Operand::new("b", TxN).with_doc("A vector value (i.e. held in an XMM register)");
277     let i = &Operand::new("i", uimm8).with_doc("An ordering operand controlling the copying of data from the source to the destination; see PSHUFD in Intel manual for details");
278 
279     ig.push(
280         Inst::new(
281             "x86_pshufd",
282             r#"
283     Packed Shuffle Doublewords -- copies data from either memory or lanes in an extended
284     register and re-orders the data according to the passed immediate byte.
285     "#,
286             &formats.binary_imm8,
287         )
288         .operands_in(vec![a, i]) // TODO allow copying from memory here (need more permissive type than TxN)
289         .operands_out(vec![a]),
290     );
291 
292     ig.push(
293         Inst::new(
294             "x86_pshufb",
295             r#"
296     Packed Shuffle Bytes -- re-orders data in an extended register using a shuffle
297     mask from either memory or another extended register
298     "#,
299             &formats.binary,
300         )
301         .operands_in(vec![a, b]) // TODO allow re-ordering from memory here (need more permissive type than TxN)
302         .operands_out(vec![a]),
303     );
304 
305     let Idx = &Operand::new("Idx", uimm8).with_doc("Lane index");
306     let x = &Operand::new("x", TxN);
307     let a = &Operand::new("a", &TxN.lane_of());
308 
309     ig.push(
310         Inst::new(
311             "x86_pextr",
312             r#"
313         Extract lane ``Idx`` from ``x``.
314         The lane index, ``Idx``, is an immediate value, not an SSA value. It
315         must indicate a valid lane index for the type of ``x``.
316         "#,
317             &formats.binary_imm8,
318         )
319         .operands_in(vec![x, Idx])
320         .operands_out(vec![a]),
321     );
322 
323     let IBxN = &TypeVar::new(
324         "IBxN",
325         "A SIMD vector type containing only booleans and integers",
326         TypeSetBuilder::new()
327             .ints(Interval::All)
328             .bools(Interval::All)
329             .simd_lanes(Interval::All)
330             .includes_scalars(false)
331             .build(),
332     );
333     let x = &Operand::new("x", IBxN);
334     let y = &Operand::new("y", &IBxN.lane_of()).with_doc("New lane value");
335     let a = &Operand::new("a", IBxN);
336 
337     ig.push(
338         Inst::new(
339             "x86_pinsr",
340             r#"
341         Insert ``y`` into ``x`` at lane ``Idx``.
342         The lane index, ``Idx``, is an immediate value, not an SSA value. It
343         must indicate a valid lane index for the type of ``x``.
344         "#,
345             &formats.ternary_imm8,
346         )
347         .operands_in(vec![x, y, Idx])
348         .operands_out(vec![a]),
349     );
350 
351     let FxN = &TypeVar::new(
352         "FxN",
353         "A SIMD vector type containing floats",
354         TypeSetBuilder::new()
355             .floats(Interval::All)
356             .simd_lanes(Interval::All)
357             .includes_scalars(false)
358             .build(),
359     );
360     let x = &Operand::new("x", FxN);
361     let y = &Operand::new("y", &FxN.lane_of()).with_doc("New lane value");
362     let a = &Operand::new("a", FxN);
363 
364     ig.push(
365         Inst::new(
366             "x86_insertps",
367             r#"
368         Insert a lane of ``y`` into ``x`` at using ``Idx`` to encode both which lane the value is
369         extracted from and which it is inserted to. This is similar to x86_pinsr but inserts
370         floats, which are already stored in an XMM register.
371         "#,
372             &formats.ternary_imm8,
373         )
374         .operands_in(vec![x, y, Idx])
375         .operands_out(vec![a]),
376     );
377 
378     let x = &Operand::new("x", TxN);
379     let y = &Operand::new("y", TxN);
380     let a = &Operand::new("a", TxN);
381 
382     ig.push(
383         Inst::new(
384             "x86_punpckh",
385             r#"
386         Unpack the high-order lanes of ``x`` and ``y`` and interleave into ``a``. With notional
387         i8x4 vectors, where ``x = [x3, x2, x1, x0]`` and ``y = [y3, y2, y1, y0]``, this operation
388         would result in ``a = [y3, x3, y2, x2]`` (using the Intel manual's right-to-left lane
389         ordering).
390         "#,
391             &formats.binary,
392         )
393         .operands_in(vec![x, y])
394         .operands_out(vec![a]),
395     );
396 
397     ig.push(
398         Inst::new(
399             "x86_punpckl",
400             r#"
401         Unpack the low-order lanes of ``x`` and ``y`` and interleave into ``a``. With notional
402         i8x4 vectors, where ``x = [x3, x2, x1, x0]`` and ``y = [y3, y2, y1, y0]``, this operation
403         would result in ``a = [y1, x1, y0, x0]`` (using the Intel manual's right-to-left lane
404         ordering).
405         "#,
406             &formats.binary,
407         )
408         .operands_in(vec![x, y])
409         .operands_out(vec![a]),
410     );
411 
412     let I16xN = &TypeVar::new(
413         "I16xN",
414         "A SIMD vector type containing integers 16-bits wide and up",
415         TypeSetBuilder::new()
416             .ints(16..32)
417             .simd_lanes(4..8)
418             .includes_scalars(false)
419             .build(),
420     );
421 
422     let x = &Operand::new("x", I16xN);
423     let y = &Operand::new("y", I16xN);
424     let a = &Operand::new("a", &I16xN.split_lanes());
425 
426     ig.push(
427         Inst::new(
428             "x86_packss",
429             r#"
430         Convert packed signed integers the lanes of ``x`` and ``y`` into half-width integers, using
431         signed saturation to handle overflows. For example, with notional i16x2 vectors, where
432         ``x = [x1, x0]`` and ``y = [y1, y0]``, this operation would result in
433         ``a = [y1', y0', x1', x0']`` (using the Intel manual's right-to-left lane ordering).
434         "#,
435             &formats.binary,
436         )
437         .operands_in(vec![x, y])
438         .operands_out(vec![a]),
439     );
440 
441     let x = &Operand::new("x", FxN);
442     let y = &Operand::new("y", FxN);
443     let a = &Operand::new("a", FxN);
444 
445     ig.push(
446         Inst::new(
447             "x86_movsd",
448             r#"
449         Move the low 64 bits of the float vector ``y`` to the low 64 bits of float vector ``x``
450         "#,
451             &formats.binary,
452         )
453         .operands_in(vec![x, y])
454         .operands_out(vec![a]),
455     );
456 
457     ig.push(
458         Inst::new(
459             "x86_movlhps",
460             r#"
461         Move the low 64 bits of the float vector ``y`` to the high 64 bits of float vector ``x``
462         "#,
463             &formats.binary,
464         )
465         .operands_in(vec![x, y])
466         .operands_out(vec![a]),
467     );
468 
469     let IxN = &TypeVar::new(
470         "IxN",
471         "A SIMD vector type containing integers",
472         TypeSetBuilder::new()
473             .ints(Interval::All)
474             .simd_lanes(Interval::All)
475             .includes_scalars(false)
476             .build(),
477     );
478     let I128 = &TypeVar::new(
479         "I128",
480         "A SIMD vector type containing one large integer (due to Cranelift type constraints, \
481         this uses the Cranelift I64X2 type but should be understood as one large value, i.e., the \
482         upper lane is concatenated with the lower lane to form the integer)",
483         TypeSetBuilder::new()
484             .ints(64..64)
485             .simd_lanes(2..2)
486             .includes_scalars(false)
487             .build(),
488     );
489 
490     let x = &Operand::new("x", IxN).with_doc("Vector value to shift");
491     let y = &Operand::new("y", I128).with_doc("Number of bits to shift");
492     let a = &Operand::new("a", IxN);
493 
494     ig.push(
495         Inst::new(
496             "x86_psll",
497             r#"
498         Shift Packed Data Left Logical -- This implements the behavior of the shared instruction
499         ``ishl`` but alters the shift operand to live in an XMM register as expected by the PSLL*
500         family of instructions.
501         "#,
502             &formats.binary,
503         )
504         .operands_in(vec![x, y])
505         .operands_out(vec![a]),
506     );
507 
508     ig.push(
509         Inst::new(
510             "x86_psrl",
511             r#"
512         Shift Packed Data Right Logical -- This implements the behavior of the shared instruction
513         ``ushr`` but alters the shift operand to live in an XMM register as expected by the PSRL*
514         family of instructions.
515         "#,
516             &formats.binary,
517         )
518         .operands_in(vec![x, y])
519         .operands_out(vec![a]),
520     );
521 
522     ig.push(
523         Inst::new(
524             "x86_psra",
525             r#"
526         Shift Packed Data Right Arithmetic -- This implements the behavior of the shared
527         instruction ``sshr`` but alters the shift operand to live in an XMM register as expected by
528         the PSRA* family of instructions.
529         "#,
530             &formats.binary,
531         )
532         .operands_in(vec![x, y])
533         .operands_out(vec![a]),
534     );
535 
536     let I64x2 = &TypeVar::new(
537         "I64x2",
538         "A SIMD vector type containing two 64-bit integers",
539         TypeSetBuilder::new()
540             .ints(64..64)
541             .simd_lanes(2..2)
542             .includes_scalars(false)
543             .build(),
544     );
545 
546     let x = &Operand::new("x", I64x2);
547     let y = &Operand::new("y", I64x2);
548     let a = &Operand::new("a", I64x2);
549     ig.push(
550         Inst::new(
551             "x86_pmullq",
552             r#"
553         Multiply Packed Integers -- Multiply two 64x2 integers and receive a 64x2 result with
554         lane-wise wrapping if the result overflows. This instruction is necessary to add distinct
555         encodings for CPUs with newer vector features.
556         "#,
557             &formats.binary,
558         )
559         .operands_in(vec![x, y])
560         .operands_out(vec![a]),
561     );
562 
563     ig.push(
564         Inst::new(
565             "x86_pmuludq",
566             r#"
567         Multiply Packed Integers -- Using only the bottom 32 bits in each lane, multiply two 64x2
568         unsigned integers and receive a 64x2 result. This instruction avoids the need for handling
569         overflow as in `x86_pmullq`.
570         "#,
571             &formats.binary,
572         )
573         .operands_in(vec![x, y])
574         .operands_out(vec![a]),
575     );
576 
577     let x = &Operand::new("x", TxN);
578     let y = &Operand::new("y", TxN);
579     let f = &Operand::new("f", iflags);
580     ig.push(
581         Inst::new(
582             "x86_ptest",
583             r#"
584         Logical Compare -- PTEST will set the ZF flag if all bits in the result are 0 of the
585         bitwise AND of the first source operand (first operand) and the second source operand
586         (second operand). PTEST sets the CF flag if all bits in the result are 0 of the bitwise
587         AND of the second source operand (second operand) and the logical NOT of the destination
588         operand (first operand).
589         "#,
590             &formats.binary,
591         )
592         .operands_in(vec![x, y])
593         .operands_out(vec![f]),
594     );
595 
596     let x = &Operand::new("x", IxN);
597     let y = &Operand::new("y", IxN);
598     let a = &Operand::new("a", IxN);
599     ig.push(
600         Inst::new(
601             "x86_pmaxs",
602             r#"
603         Maximum of Packed Signed Integers -- Compare signed integers in the first and second
604         operand and return the maximum values.
605         "#,
606             &formats.binary,
607         )
608         .operands_in(vec![x, y])
609         .operands_out(vec![a]),
610     );
611 
612     ig.push(
613         Inst::new(
614             "x86_pmaxu",
615             r#"
616         Maximum of Packed Unsigned Integers -- Compare unsigned integers in the first and second
617         operand and return the maximum values.
618         "#,
619             &formats.binary,
620         )
621         .operands_in(vec![x, y])
622         .operands_out(vec![a]),
623     );
624 
625     ig.push(
626         Inst::new(
627             "x86_pmins",
628             r#"
629         Minimum of Packed Signed Integers -- Compare signed integers in the first and second
630         operand and return the minimum values.
631         "#,
632             &formats.binary,
633         )
634         .operands_in(vec![x, y])
635         .operands_out(vec![a]),
636     );
637 
638     ig.push(
639         Inst::new(
640             "x86_pminu",
641             r#"
642         Minimum of Packed Unsigned Integers -- Compare unsigned integers in the first and second
643         operand and return the minimum values.
644         "#,
645             &formats.binary,
646         )
647         .operands_in(vec![x, y])
648         .operands_out(vec![a]),
649     );
650 
651     let i64_t = &TypeVar::new(
652         "i64_t",
653         "A scalar 64bit integer",
654         TypeSetBuilder::new().ints(64..64).build(),
655     );
656 
657     let GV = &Operand::new("GV", &entities.global_value);
658     let addr = &Operand::new("addr", i64_t);
659 
660     ig.push(
661         Inst::new(
662             "x86_elf_tls_get_addr",
663             r#"
664         Elf tls get addr -- This implements the GD TLS model for ELF. The clobber output should
665         not be used.
666             "#,
667             &formats.unary_global_value,
668         )
669         // This is a bit overly broad to mark as clobbering *all* the registers, because it should
670         // only preserve caller-saved registers. There's no way to indicate this to register
671         // allocation yet, though, so mark as clobbering all registers instead.
672         .clobbers_all_regs(true)
673         .operands_in(vec![GV])
674         .operands_out(vec![addr]),
675     );
676     ig.push(
677         Inst::new(
678             "x86_macho_tls_get_addr",
679             r#"
680         Mach-O tls get addr -- This implements TLS access for Mach-O. The clobber output should
681         not be used.
682             "#,
683             &formats.unary_global_value,
684         )
685         // See above comment for x86_elf_tls_get_addr.
686         .clobbers_all_regs(true)
687         .operands_in(vec![GV])
688         .operands_out(vec![addr]),
689     );
690 
691     ig.build()
692 }
693