1;; s390x instruction selection and CLIF-to-MachInst lowering.
2
3;; The main lowering constructor term: takes a clif `Inst` and returns the
4;; register(s) within which the lowered instruction's result values live.
5(decl partial lower (Inst) InstOutput)
6
7;; A variant of the main lowering constructor term, used for branches.
8;; The only difference is that it gets an extra argument holding a vector
9;; of branch targets to be used.
10(decl partial lower_branch (Inst MachLabelSlice) Unit)
11
12
13;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
15(rule (lower (has_type ty (iconst _ (u64_from_imm64 n))))
16      (imm ty n))
17
18
19;;;; Rules for `f16const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
21(rule (lower (f16const _ (u16_from_ieee16 x)))
22      (imm $F16 x))
23
24
25;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26
27(rule (lower (f32const _ (u32_from_ieee32 x)))
28      (imm $F32 x))
29
30
31;;;; Rules for `f64const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32
33(rule (lower (f64const _ (u64_from_ieee64 x)))
34      (imm $F64 x))
35
36
37;;;; Rules for `f128const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
39(rule (lower (f128const _ (u128_from_constant x)))
40      (vec_imm $F128 (be_vec_const $F128 x)))
41
42
43;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44
45(rule (lower (has_type ty (vconst _ (u128_from_constant x))))
46      (vec_imm ty (be_vec_const ty x)))
47
48
49;;;; Rules for `nop` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50
51(rule (lower (nop))
52      (invalid_reg))
53
54
55;;;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56
57(rule (lower (has_type (vr128_ty ty) (iconcat _ x y)))
58      (mov_to_vec128 ty y x))
59
60
61;;;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
62
63(rule (lower (isplit _ x @ (value_type $I128)))
64      (let ((x_reg Reg x)
65            (x_hi Reg (vec_extract_lane $I64X2 x_reg 0 (zero_reg)))
66            (x_lo Reg (vec_extract_lane $I64X2 x_reg 1 (zero_reg))))
67        (output_pair x_lo x_hi)))
68
69
70;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
71
72;; Add two registers.
73(rule 0 (lower (has_type (fits_in_64 ty) (iadd _ x y)))
74      (add_reg ty x y))
75
76;; Add a register and a sign-extended register.
77(rule 8 (lower (has_type (fits_in_64 ty) (iadd _ x (sext32_value y))))
78      (add_reg_sext32 ty x y))
79(rule 15 (lower (has_type (fits_in_64 ty) (iadd _ (sext32_value x) y)))
80      (add_reg_sext32 ty y x))
81
82;; Add a register and an immediate.
83(rule 7 (lower (has_type (fits_in_64 ty) (iadd _ x (i16_from_value y))))
84      (add_simm16 ty x y))
85(rule 14 (lower (has_type (fits_in_64 ty) (iadd _ (i16_from_value x) y)))
86      (add_simm16 ty y x))
87(rule 6 (lower (has_type (fits_in_64 ty) (iadd _ x (i32_from_value y))))
88      (add_simm32 ty x y))
89(rule 13 (lower (has_type (fits_in_64 ty) (iadd _ (i32_from_value x) y)))
90      (add_simm32 ty y x))
91
92;; Add a register and memory (32/64-bit types).
93(rule 5 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_load_32_64 y))))
94      (add_mem ty x (sink_load y)))
95(rule 12 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_load_32_64 x) y)))
96      (add_mem ty y (sink_load x)))
97
98;; Add a register and memory (16-bit types).
99(rule 4 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_load_16 y))))
100      (add_mem_sext16 ty x (sink_load y)))
101(rule 11 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_load_16 x) y)))
102      (add_mem_sext16 ty y (sink_load x)))
103
104;; Add a register and sign-extended memory.
105(rule 3 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_sload16 y))))
106      (add_mem_sext16 ty x (sink_sload16 y)))
107(rule 10 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_sload16 x) y)))
108      (add_mem_sext16 ty y (sink_sload16 x)))
109(rule 2 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_sload32 y))))
110      (add_mem_sext32 ty x (sink_sload32 y)))
111(rule 9 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_sload32 x) y)))
112      (add_mem_sext32 ty y (sink_sload32 x)))
113
114;; Add two vector registers.
115(rule 1 (lower (has_type (vr128_ty ty) (iadd _ x y)))
116      (vec_add ty x y))
117
118
119;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
120
121;; Add (saturate unsigned) two vector registers.
122(rule (lower (has_type (ty_vec128 ty) (uadd_sat _ x y)))
123      (let ((sum Reg (vec_add ty x y)))
124        (vec_or ty sum (vec_cmphl ty x sum))))
125
126
127;;;; Rules for `sadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
128
129;; Add (saturate signed) two vector registers.  $I64X2 not supported.
130(rule (lower (has_type (ty_vec128 ty) (sadd_sat _ x y)))
131      (vec_pack_ssat (vec_widen_type ty)
132                     (vec_add (vec_widen_type ty) (vec_unpacks_high ty x)
133                                                  (vec_unpacks_high ty y))
134                     (vec_add (vec_widen_type ty) (vec_unpacks_low ty x)
135                                                  (vec_unpacks_low ty y))))
136
137
138;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139
140;; Lane-wise integer pairwise addition for 8-/16/32-bit vector registers.
141(rule (lower (has_type ty @ (multi_lane bits _) (iadd_pairwise _ x y)))
142      (let ((size Reg (vec_imm_splat $I8X16 bits)))
143        (vec_pack_lane_order (vec_widen_type ty)
144                             (vec_add ty x (vec_lshr_by_byte x size))
145                             (vec_add ty y (vec_lshr_by_byte y size)))))
146
147;; special case for the `i32x4.dot_i16x8_s` wasm instruction
148(rule 1 (lower
149        (has_type dst_ty (iadd_pairwise _
150                           (imul _ (swiden_low _ x @ (value_type src_ty)) (swiden_low _ y))
151                           (imul _ (swiden_high _ x) (swiden_high _ y)))))
152      (vec_add dst_ty (vec_smul_even src_ty x y)
153                      (vec_smul_odd src_ty x y)))
154
155
156;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
157
158;; Sub two registers.
159(rule 0 (lower (has_type (fits_in_64 ty) (isub _ x y)))
160      (sub_reg ty x y))
161
162;; Sub a register and a sign-extended register.
163(rule 8 (lower (has_type (fits_in_64 ty) (isub _ x (sext32_value y))))
164      (sub_reg_sext32 ty x y))
165
166;; Sub a register and an immediate (using add of the negated value).
167(rule 7 (lower (has_type (fits_in_64 ty) (isub _ x (i16_from_negated_value y))))
168      (add_simm16 ty x y))
169(rule 6 (lower (has_type (fits_in_64 ty) (isub _ x (i32_from_negated_value y))))
170      (add_simm32 ty x y))
171
172;; Sub a register and memory (32/64-bit types).
173(rule 5 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_load_32_64 y))))
174      (sub_mem ty x (sink_load y)))
175
176;; Sub a register and memory (16-bit types).
177(rule 4 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_load_16 y))))
178      (sub_mem_sext16 ty x (sink_load y)))
179
180;; Sub a register and sign-extended memory.
181(rule 3 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_sload16 y))))
182      (sub_mem_sext16 ty x (sink_sload16 y)))
183(rule 2 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_sload32 y))))
184      (sub_mem_sext32 ty x (sink_sload32 y)))
185
186;; Sub two vector registers.
187(rule 1 (lower (has_type (vr128_ty ty) (isub _ x y)))
188      (vec_sub ty x y))
189
190
191;;;; Rules for `usub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
192
193;; Add (saturate unsigned) two vector registers.
194(rule (lower (has_type (ty_vec128 ty) (usub_sat _ x y)))
195      (vec_and ty (vec_sub ty x y) (vec_cmphl ty x y)))
196
197
198;;;; Rules for `ssub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199
200;; Add (saturate signed) two vector registers.  $I64X2 not supported.
201(rule (lower (has_type (ty_vec128 ty) (ssub_sat _ x y)))
202      (vec_pack_ssat (vec_widen_type ty)
203                     (vec_sub (vec_widen_type ty) (vec_unpacks_high ty x)
204                                                  (vec_unpacks_high ty y))
205                     (vec_sub (vec_widen_type ty) (vec_unpacks_low ty x)
206                                                  (vec_unpacks_low ty y))))
207
208
209;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
210
211;; Absolute value of a register.
212;; For types smaller than 32-bit, the input value must be sign-extended.
213(rule 2 (lower (has_type (fits_in_64 ty) (iabs _ x)))
214      (abs_reg (ty_ext32 ty) (put_in_reg_sext32 x)))
215
216;; Absolute value of a sign-extended register.
217(rule 3 (lower (has_type (fits_in_64 ty) (iabs _ (sext32_value x))))
218      (abs_reg_sext32 ty x))
219
220;; Absolute value of a vector register.
221(rule 1 (lower (has_type (ty_vec128 ty) (iabs _ x)))
222      (vec_abs ty x))
223
224;; Absolute value of a 128-bit integer on z17.
225(rule 4 (lower (has_type (and (vxrs_ext3_enabled) $I128) (iabs _ x)))
226      (vec_abs $I128 x))
227
228;; Absolute value of a 128-bit integer pre-z17.
229(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (iabs _ x)))
230      (let ((zero Reg (vec_imm $I128 0))
231            (pos Reg x)
232            (neg Reg (vec_sub $I128 zero pos))
233            (rep Reg (vec_replicate_lane $I64X2 pos 0))
234            (mask Reg (vec_cmph $I64X2 zero rep)))
235        (vec_select $I128 neg pos mask)))
236
237
238;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
239
240;; Negate a register.
241(rule 2 (lower (has_type (fits_in_64 ty) (ineg _ x)))
242      (neg_reg ty x))
243
244;; Negate a sign-extended register.
245(rule 3 (lower (has_type (fits_in_64 ty) (ineg _ (sext32_value x))))
246      (neg_reg_sext32 ty x))
247
248;; Negate a vector register.
249(rule 1 (lower (has_type (ty_vec128 ty) (ineg _ x)))
250      (vec_neg ty x))
251
252;; Negate a 128-bit integer on z17.
253(rule 4 (lower (has_type (and (vxrs_ext3_enabled) $I128) (ineg _ x)))
254      (vec_neg $I128 x))
255
256;; Negate a 128-bit integer pre-z17.
257(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (ineg _ x)))
258      (vec_sub $I128 (vec_imm $I128 0) x))
259
260
261;;;; Rules for `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262
263;; Unsigned maximum of two scalar integers - expand to icmp + select.
264(rule 2 (lower (has_type (fits_in_64 ty) (umax _ x y)))
265      (let ((x_ext Reg (put_in_reg_zext32 x))
266            (y_ext Reg (put_in_reg_zext32 y))
267            (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext)
268                                     (intcc_as_cond (IntCC.UnsignedLessThan)))))
269        (select_bool_reg ty cond y_ext x_ext)))
270
271;; Unsigned maximum of two 128-bit integers pre-z17 - expand to icmp + select.
272(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (umax _ x y)))
273      (let ((x_reg Reg (put_in_reg x))
274            (y_reg Reg (put_in_reg y))
275            (cond ProducesBool (vec_int128_ucmphi y_reg x_reg)))
276        (select_bool_reg $I128 cond y_reg x_reg)))
277
278;; Unsigned maximum of two 128-bit integers on z17.
279(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (umax _ x y)))
280      (vec_umax $I128 x y))
281
282;; Unsigned maximum of two vector registers.
283(rule 0 (lower (has_type (ty_vec128 ty) (umax _ x y)))
284      (vec_umax ty x y))
285
286
287;;;; Rules for `umin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
288
289;; Unsigned minimum of two scalar integers - expand to icmp + select.
290(rule 2 (lower (has_type (fits_in_64 ty) (umin _ x y)))
291      (let ((x_ext Reg (put_in_reg_zext32 x))
292            (y_ext Reg (put_in_reg_zext32 y))
293            (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext)
294                                     (intcc_as_cond (IntCC.UnsignedGreaterThan)))))
295        (select_bool_reg ty cond y_ext x_ext)))
296
297;; Unsigned maximum of two 128-bit integers pre-z17 - expand to icmp + select.
298(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (umin _ x y)))
299      (let ((x_reg Reg (put_in_reg x))
300            (y_reg Reg (put_in_reg y))
301            (cond ProducesBool (vec_int128_ucmphi x_reg y_reg)))
302        (select_bool_reg $I128 cond y_reg x_reg)))
303
304;; Unsigned minimum of two 128-bit integers on z17.
305(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (umin _ x y)))
306      (vec_umin $I128 x y))
307
308;; Unsigned minimum of two vector registers.
309(rule 0 (lower (has_type (ty_vec128 ty) (umin _ x y)))
310      (vec_umin ty x y))
311
312
313;;;; Rules for `smax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314
315;; Signed maximum of two scalar integers - expand to icmp + select.
316(rule 2 (lower (has_type (fits_in_64 ty) (smax _ x y)))
317      (let ((x_ext Reg (put_in_reg_sext32 x))
318            (y_ext Reg (put_in_reg_sext32 y))
319            (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext)
320                                     (intcc_as_cond (IntCC.SignedLessThan)))))
321        (select_bool_reg ty cond y_ext x_ext)))
322
323;; Signed maximum of two 128-bit integers pre-z17 - expand to icmp + select.
324(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (smax _ x y)))
325      (let ((x_reg Reg (put_in_reg x))
326            (y_reg Reg (put_in_reg y))
327            (cond ProducesBool (vec_int128_scmphi y_reg x_reg)))
328        (select_bool_reg $I128 cond y_reg x_reg)))
329
330;; Signed maximum of two 128-bit integers on z17.
331(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (smax _ x y)))
332      (vec_smax $I128 x y))
333
334;; Signed maximum of two vector registers.
335(rule (lower (has_type (ty_vec128 ty) (smax _ x y)))
336      (vec_smax ty x y))
337
338
339;;;; Rules for `smin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
340
341;; Signed minimum of two scalar integers - expand to icmp + select.
342(rule 2 (lower (has_type (fits_in_64 ty) (smin _ x y)))
343      (let ((x_ext Reg (put_in_reg_sext32 x))
344            (y_ext Reg (put_in_reg_sext32 y))
345            (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext)
346                                     (intcc_as_cond (IntCC.SignedGreaterThan)))))
347        (select_bool_reg ty cond y_ext x_ext)))
348
349;; Signed maximum of two 128-bit integers pre-z17 - expand to icmp + select.
350(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (smin _ x y)))
351      (let ((x_reg Reg (put_in_reg x))
352            (y_reg Reg (put_in_reg y))
353            (cond ProducesBool (vec_int128_scmphi x_reg y_reg)))
354        (select_bool_reg $I128 cond y_reg x_reg)))
355
356;; Signed minimum of two 128-bit integers on z17.
357(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (smin _ x y)))
358      (vec_smin $I128 x y))
359
360;; Signed minimum of two vector registers.
361(rule (lower (has_type (ty_vec128 ty) (smin _ x y)))
362      (vec_smin ty x y))
363
364
365;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
366
367;; Unsigned average of two vector registers.
368(rule (lower (has_type (ty_vec128 ty) (avg_round _ x y)))
369      (vec_uavg ty x y))
370
371
372;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
373
374;; Multiply two registers.
375(rule 0 (lower (has_type (fits_in_64 ty) (imul _ x y)))
376      (mul_reg ty x y))
377
378;; Multiply a register and a sign-extended register.
379(rule 8 (lower (has_type (fits_in_64 ty) (imul _ x (sext32_value y))))
380      (mul_reg_sext32 ty x y))
381(rule 15 (lower (has_type (fits_in_64 ty) (imul _ (sext32_value x) y)))
382      (mul_reg_sext32 ty y x))
383
384;; Multiply a register and an immediate.
385(rule 7 (lower (has_type (fits_in_64 ty) (imul _ x (i16_from_value y))))
386      (mul_simm16 ty x y))
387(rule 14 (lower (has_type (fits_in_64 ty) (imul _ (i16_from_value x) y)))
388      (mul_simm16 ty y x))
389(rule 6 (lower (has_type (fits_in_64 ty) (imul _ x (i32_from_value y))))
390      (mul_simm32 ty x y))
391(rule 13 (lower (has_type (fits_in_64 ty) (imul _ (i32_from_value x) y)))
392      (mul_simm32 ty y x))
393
394;; Multiply a register and memory (32/64-bit types).
395(rule 5 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_load_32_64 y))))
396      (mul_mem ty x (sink_load y)))
397(rule 12 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_load_32_64 x) y)))
398      (mul_mem ty y (sink_load x)))
399
400;; Multiply a register and memory (16-bit types).
401(rule 4 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_load_16 y))))
402      (mul_mem_sext16 ty x (sink_load y)))
403(rule 11 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_load_16 x) y)))
404      (mul_mem_sext16 ty y (sink_load x)))
405
406;; Multiply a register and sign-extended memory.
407(rule 3 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_sload16 y))))
408      (mul_mem_sext16 ty x (sink_sload16 y)))
409(rule 10 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_sload16 x) y)))
410      (mul_mem_sext16 ty y (sink_sload16 x)))
411(rule 2 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_sload32 y))))
412      (mul_mem_sext32 ty x (sink_sload32 y)))
413(rule 9 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_sload32 x) y)))
414      (mul_mem_sext32 ty y (sink_sload32 x)))
415
416;; Multiply two vector registers, using a helper.
417(decl vec_mul_impl (Type Reg Reg) Reg)
418(rule 1 (lower (has_type (vr128_ty ty) (imul _ x y)))
419      (vec_mul_impl ty x y))
420
421;; Multiply two vector registers - byte, halfword, and word.
422(rule (vec_mul_impl $I8X16 x y) (vec_mul $I8X16 x y))
423(rule (vec_mul_impl $I16X8 x y) (vec_mul $I16X8 x y))
424(rule (vec_mul_impl $I32X4 x y) (vec_mul $I32X4 x y))
425
426;; Multiply two vector registers - doubleword on z17.
427(rule 1 (vec_mul_impl (and (vxrs_ext3_enabled) $I64X2) x y) (vec_mul $I64X2 x y))
428
429;; Multiply two vector registers - doubleword pre-z17.  Has to be scalarized.
430(rule (vec_mul_impl (and (vxrs_ext3_disabled) $I64X2) x y)
431      (mov_to_vec128 $I64X2
432                     (mul_reg $I64 (vec_extract_lane $I64X2 x 0 (zero_reg))
433                                   (vec_extract_lane $I64X2 y 0 (zero_reg)))
434                     (mul_reg $I64 (vec_extract_lane $I64X2 x 1 (zero_reg))
435                                   (vec_extract_lane $I64X2 y 1 (zero_reg)))))
436
437;; Multiply two vector registers - quadword on z17.
438(rule 1 (vec_mul_impl (and (vxrs_ext3_enabled) $I128) x y) (vec_mul $I128 x y))
439
440;; Multiply two vector registers - quadword pre-z17.
441(rule (vec_mul_impl (and (vxrs_ext3_disabled) $I128) x y)
442      (let ((x_hi Reg (vec_extract_lane $I64X2 x 0 (zero_reg)))
443            (x_lo Reg (vec_extract_lane $I64X2 x 1 (zero_reg)))
444            (y_hi Reg (vec_extract_lane $I64X2 y 0 (zero_reg)))
445            (y_lo Reg (vec_extract_lane $I64X2 y 1 (zero_reg)))
446            (lo_pair RegPair (umul_wide x_lo y_lo))
447            (res_lo Reg (regpair_lo lo_pair))
448            (res_hi_1 Reg (regpair_hi lo_pair))
449            (res_hi_2 Reg (mul_reg $I64 x_lo y_hi))
450            (res_hi_3 Reg (mul_reg $I64 x_hi y_lo))
451            (res_hi Reg (add_reg $I64 res_hi_3 (add_reg $I64 res_hi_2 res_hi_1))))
452        (mov_to_vec128 $I64X2 res_hi res_lo)))
453
454;; Special-case the lowering of a 128-bit multiply where the operands are sign
455;; or zero extended. This maps directly to `umul_wide` and `smul_wide`.
456(rule 16 (lower (has_type $I128 (imul _ (uextend _ x) (uextend _ y))))
457  (let ((pair RegPair (umul_wide (put_in_reg_zext64 x) (put_in_reg_zext64 y))))
458    (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair))))
459
460(rule 16 (lower (has_type $I128 (imul _ (sextend _ x) (sextend _ y))))
461  (let ((pair RegPair (smul_wide (put_in_reg_sext64 x) (put_in_reg_sext64 y))))
462    (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair))))
463
464;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
465
466;; Multiply high part unsigned, 8-bit or 16-bit types.  (Uses 32-bit multiply.)
467(rule -1 (lower (has_type (ty_8_or_16 ty) (umulhi _ x y)))
468      (let ((ext_reg_x Reg (put_in_reg_zext32 x))
469            (ext_reg_y Reg (put_in_reg_zext32 y))
470            (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y)))
471        (lshr_imm $I32 ext_mul (ty_bits ty))))
472
473;; Multiply high part unsigned, 32-bit types.  (Uses 64-bit multiply.)
474(rule (lower (has_type $I32 (umulhi _ x y)))
475      (let ((ext_reg_x Reg (put_in_reg_zext64 x))
476            (ext_reg_y Reg (put_in_reg_zext64 y))
477            (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y)))
478        (lshr_imm $I64 ext_mul 32)))
479
480;; Multiply high part unsigned, 64-bit types.  (Uses umul_wide.)
481(rule (lower (has_type $I64 (umulhi _ x y)))
482      (let ((pair RegPair (umul_wide x y)))
483        (regpair_hi pair)))
484
485;; Multiply high part unsigned, vector types with 8-, 16-, or 32-bit elements.
486(rule (lower (has_type $I8X16 (umulhi _ x y))) (vec_umulhi $I8X16 x y))
487(rule (lower (has_type $I16X8 (umulhi _ x y))) (vec_umulhi $I16X8 x y))
488(rule (lower (has_type $I32X4 (umulhi _ x y))) (vec_umulhi $I32X4 x y))
489
490;; Multiply high part unsigned, vector types with 64-bit elements on z17.
491(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I64X2) (umulhi _ x y))) (vec_umulhi $I64X2 x y))
492
493;; Multiply high part unsigned, vector types with 64-bit elements pre-z17.
494;; Has to be scalarized.
495(rule (lower (has_type (and (vxrs_ext3_disabled) $I64X2) (umulhi _ x y)))
496      (let ((pair_0 RegPair (umul_wide (vec_extract_lane $I64X2 x 0 (zero_reg))
497                                       (vec_extract_lane $I64X2 y 0 (zero_reg))))
498            (res_0 Reg (regpair_hi pair_0))
499            (pair_1 RegPair (umul_wide (vec_extract_lane $I64X2 x 1 (zero_reg))
500                                       (vec_extract_lane $I64X2 y 1 (zero_reg))))
501            (res_1 Reg (regpair_hi pair_1)))
502        (mov_to_vec128 $I64X2 res_0 res_1)))
503
504
505;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
506
507;; Multiply high part signed, 8-bit or 16-bit types.  (Uses 32-bit multiply.)
508(rule -1 (lower (has_type (ty_8_or_16 ty) (smulhi _ x y)))
509      (let ((ext_reg_x Reg (put_in_reg_sext32 x))
510            (ext_reg_y Reg (put_in_reg_sext32 y))
511            (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y)))
512        (ashr_imm $I32 ext_mul (ty_bits ty))))
513
514;; Multiply high part signed, 32-bit types.  (Uses 64-bit multiply.)
515(rule (lower (has_type $I32 (smulhi _ x y)))
516      (let ((ext_reg_x Reg (put_in_reg_sext64 x))
517            (ext_reg_y Reg (put_in_reg_sext64 y))
518            (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y)))
519        (ashr_imm $I64 ext_mul 32)))
520
521;; Multiply high part signed, 64-bit types.  (Uses smul_wide.)
522(rule (lower (has_type $I64 (smulhi _ x y)))
523      (let ((pair RegPair (smul_wide x y)))
524        (regpair_hi pair)))
525
526;; Multiply high part signed, vector types with 8-, 16-, or 32-bit elements.
527(rule (lower (has_type $I8X16 (smulhi _ x y))) (vec_smulhi $I8X16 x y))
528(rule (lower (has_type $I16X8 (smulhi _ x y))) (vec_smulhi $I16X8 x y))
529(rule (lower (has_type $I32X4 (smulhi _ x y))) (vec_smulhi $I32X4 x y))
530
531;; Multiply high part signed, vector types with 64-bit elements on z17.
532(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I64X2) (smulhi _ x y))) (vec_smulhi $I64X2 x y))
533
534;; Multiply high part signed, vector types with 64-bit elements pre-z17.
535;; Has to be scalarized.
536(rule (lower (has_type (and (vxrs_ext3_disabled) $I64X2) (smulhi _ x y)))
537      (let ((pair_0 RegPair (smul_wide (vec_extract_lane $I64X2 x 0 (zero_reg))
538                                       (vec_extract_lane $I64X2 y 0 (zero_reg))))
539            (res_0 Reg (copy_reg $I64 (regpair_hi pair_0)))
540            (pair_1 RegPair (smul_wide (vec_extract_lane $I64X2 x 1 (zero_reg))
541                                       (vec_extract_lane $I64X2 y 1 (zero_reg))))
542            (res_1 Reg (regpair_hi pair_1)))
543        (mov_to_vec128 $I64X2 res_0 res_1)))
544
545
546;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
547
548;; Fixed-point multiplication of two vector registers.
549(rule (lower (has_type (ty_vec128 ty) (sqmul_round_sat _ x y)))
550      (vec_pack_ssat (vec_widen_type ty)
551                     (sqmul_impl (vec_widen_type ty)
552                                 (vec_unpacks_high ty x)
553                                 (vec_unpacks_high ty y))
554                     (sqmul_impl (vec_widen_type ty)
555                                 (vec_unpacks_low ty x)
556                                 (vec_unpacks_low ty y))))
557
558;; Helper to perform the rounded multiply in the wider type.
559(decl sqmul_impl (Type Reg Reg) Reg)
560(rule (sqmul_impl $I32X4 x y)
561      (vec_ashr_imm $I32X4 (vec_add $I32X4 (vec_mul_impl $I32X4 x y)
562                                           (vec_imm_bit_mask $I32X4 17 17))
563                           15))
564(rule (sqmul_impl $I64X2 x y)
565      (vec_ashr_imm $I64X2 (vec_add $I64X2 (vec_mul_impl $I64X2 x y)
566                                           (vec_imm_bit_mask $I64X2 33 33))
567                           31))
568
569
570;;;; Rules for `udiv` and `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
571
572;; Divide two registers.  The architecture provides combined udiv / urem
573;; instructions with the following combination of data types:
574;;
575;;  - 64-bit dividend (split across a 2x32-bit register pair),
576;;    32-bit divisor (in a single input register)
577;;    32-bit quotient & remainder (in a 2x32-bit register pair)
578;;
579;;  - 128-bit dividend (split across a 2x64-bit register pair),
580;;    64-bit divisor (in a single input register)
581;;    64-bit quotient & remainder (in a 2x64-bit register pair)
582;;
583;; We use the first variant for 32-bit and smaller input types,
584;; and the second variant for 64-bit input types.
585
586;; Implement `udiv`.
587(rule (lower (has_type (fits_in_64 ty) (udiv _ x y)))
588      (let (
589            ;; Look at the divisor to determine whether we need to generate
590            ;; an explicit division-by zero check.
591            ;; Load up the dividend, by loading the input (possibly zero-
592            ;; extended) input into the low half of the register pair,
593            ;; and setting the high half to zero.
594            (ext_x RegPair (regpair (imm (ty_ext32 ty) 0)
595                                    (put_in_reg_zext32 x)))
596            ;; Load up the divisor, zero-extended if necessary.
597            (ext_y Reg (put_in_reg_zext32 y))
598            (ext_ty Type (ty_ext32 ty))
599            ;; Emit the actual divide instruction.
600            (pair RegPair (udivmod ext_ty ext_x ext_y)))
601        ;; The quotient can be found in the low half of the result.
602        (regpair_lo pair)))
603
604;; Implement `urem`.  Same as `udiv`, but finds the remainder in
605;; the high half of the result register pair instead.
606(rule (lower (has_type (fits_in_64 ty) (urem _ x y)))
607      (let ((ext_x RegPair (regpair (imm (ty_ext32 ty) 0)
608                                    (put_in_reg_zext32 x)))
609            (ext_y Reg (put_in_reg_zext32 y))
610            (ext_ty Type (ty_ext32 ty))
611            (pair RegPair (udivmod ext_ty ext_x ext_y)))
612        (regpair_hi pair)))
613
614;; Implement `udiv` for 128-bit integers on z17 (only).
615(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (udiv _ x y)))
616        (vec_udiv $I128 x y))
617
618;; Implement `urem` for 128-bit integers on z17 (only).
619(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (urem _ x y)))
620        (vec_urem $I128 x y))
621
622
623;;;; Rules for `sdiv` and `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
624
625;; Divide two registers.  The architecture provides combined sdiv / srem
626;; instructions with the following combination of data types:
627;;
628;;  - 64-bit dividend (in the low half of a 2x64-bit register pair),
629;;    32-bit divisor (in a single input register)
630;;    64-bit quotient & remainder (in a 2x64-bit register pair)
631;;
632;;  - 64-bit dividend (in the low half of a 2x64-bit register pair),
633;;    64-bit divisor (in a single input register)
634;;    64-bit quotient & remainder (in a 2x64-bit register pair)
635;;
636;; We use the first variant for 32-bit and smaller input types,
637;; and the second variant for 64-bit input types.
638
639;; Implement `sdiv`.
640(rule (lower (has_type (fits_in_64 ty) (sdiv _ x y)))
641      (let (
642            ;; Look at the divisor to determine whether we need to generate
643            ;; explicit division-by-zero and/or integer-overflow checks.
644            (OFcheck bool (div_overflow_check_needed y))
645            ;; Load up the dividend (sign-extended to 64-bit)
646            (ext_x Reg (put_in_reg_sext64 x))
647            ;; Load up the divisor (sign-extended if necessary).
648            (ext_y Reg (put_in_reg_sext32 y))
649            (ext_ty Type (ty_ext32 ty))
650            ;; Perform integer-overflow check if necessary.
651            (_ Reg (maybe_trap_if_sdiv_overflow OFcheck ext_ty ty ext_x ext_y))
652            ;; Emit the actual divide instruction.
653            (pair RegPair (sdivmod ext_ty ext_x ext_y)))
654        ;; The quotient can be found in the low half of the result.
655        (regpair_lo pair)))
656
657;; Implement `srem`.  Same as `sdiv`, but finds the remainder in
658;; the high half of the result register pair instead.  Also, handle
659;; the integer overflow case differently, see below.
660(rule (lower (has_type (fits_in_64 ty) (srem _ x y)))
661      (let ((OFcheck bool (div_overflow_check_needed y))
662            (ext_x Reg (put_in_reg_sext64 x))
663            (ext_y Reg (put_in_reg_sext32 y))
664            (ext_ty Type (ty_ext32 ty))
665            (checked_x Reg (maybe_avoid_srem_overflow OFcheck ext_ty ext_x ext_y))
666            (pair RegPair (sdivmod ext_ty checked_x ext_y)))
667        (regpair_hi pair)))
668
669;; Determine whether we need to perform an integer-overflow check.
670;;
671;; We never rely on the divide instruction itself to trap; while that trap
672;; would indeed happen, we have no way of signalling two different trap
673;; conditions from the same instruction.  By explicitly checking for the
674;; integer-overflow case ahead of time, any hardware trap in the divide
675;; instruction is guaranteed to indicate division-by-zero.
676;;
677;; In addition, for types smaller than 64 bits we would have to perform
678;; the check explicitly anyway, since the instruction provides a 64-bit
679;; quotient and only traps if *that* overflows.
680;;
681;; However, the only case where integer overflow can occur is if the
682;; minimum (signed) integer value is divided by -1, so if the divisor
683;; is any immediate different from -1, the check can be omitted.
684(decl div_overflow_check_needed (Value) bool)
685(rule 1 (div_overflow_check_needed (i64_from_value x))
686      (if (i64_not_neg1 x))
687      false)
688(rule (div_overflow_check_needed _) true)
689
690;; Perform the integer-overflow check if necessary.   This implements:
691;;
692;;    if divisor == INT_MIN && dividend == -1 { trap }
693;;
694;; but to avoid introducing control flow, it is actually done as:
695;;
696;;    if ((divisor ^ INT_MAX) & dividend) == -1 { trap }
697;;
698;; instead, using a single conditional trap instruction.
699(decl maybe_trap_if_sdiv_overflow (bool Type Type Reg Reg) Reg)
700(rule (maybe_trap_if_sdiv_overflow false ext_ty _ _ _) (invalid_reg))
701(rule (maybe_trap_if_sdiv_overflow true ext_ty ty x y)
702      (let ((int_max Reg (imm ext_ty (int_max ty)))
703            (reg Reg (and_reg ext_ty (xor_reg ext_ty int_max x) y)))
704        (icmps_simm16_and_trap ext_ty reg -1
705                               (intcc_as_cond (IntCC.Equal))
706                               (trap_code_integer_overflow))))
707(rule 1 (maybe_trap_if_sdiv_overflow true $I128 $I128 x y)
708      (let (
709            ;; We need to trap when y == INT_MIN && x == -1
710            ;; y == INT_MIN is implemented as y == -y, as -INT_MIN == INT_MIN.
711            ;; This checks that y == -y, by using Not-Xor for bitwise
712            ;; equality, producing all 0b1's (-1u128) when y == -y.
713            ;; Then it uses band to include the x == -1 check as well.
714            ;; using (band x (bnot (bxor y neg_division))) variant of vec eval
715            (neg_divisor Reg (vec_neg $I128 y))
716            (reg Reg (vec_eval $I128 0b00001001 x y neg_divisor))
717            ;; finally, we check that the combination of x & y == -y is -1
718            (flags ProducesFlags (vec_elt_icmps reg (vec_imm $I128 -1))))
719        (trap_if flags
720           (intcc_as_cond (IntCC.Equal))
721           (trap_code_integer_overflow))))
722
723(decl int_max (Type) u64)
724(rule (int_max $I8) 0x7f)
725(rule (int_max $I16) 0x7fff)
726(rule (int_max $I32) 0x7fffffff)
727(rule (int_max $I64) 0x7fffffffffffffff)
728
729;; When performing `srem`, we do not want to trap in the
730;; integer-overflow scenario, because it is only the quotient
731;; that overflows, not the remainder.
732;;
733;; For types smaller than 64 bits, we can simply let the
734;; instruction execute, since (as above) it will never trap.
735;;
736;; For 64-bit inputs, we check whether the divisor is -1, and
737;; if so simply replace the dividend by zero, which will give
738;; the correct result, since any value modulo -1 is zero.
739;;
740;; (We could in fact avoid executing the divide instruction
741;; at all in this case, but that would require introducing
742;; control flow.)
743(decl maybe_avoid_srem_overflow (bool Type Reg Reg) Reg)
744(rule (maybe_avoid_srem_overflow false _ x _) x)
745(rule (maybe_avoid_srem_overflow true $I32 x _) x)
746(rule (maybe_avoid_srem_overflow true $I64 x y)
747      (with_flags_reg (icmps_simm16 $I64 y -1)
748                      (cmov_imm $I64 (intcc_as_cond (IntCC.Equal)) 0 x)))
749(rule (maybe_avoid_srem_overflow true $I128 x y)
750      (with_flags_reg
751        (vec_elt_icmps y (vec_imm $I128 -1))
752        (cmov_reg_reg $I128
753          (intcc_as_cond(IntCC.Equal))
754          (vec_imm $I128 0)
755          x)))
756
757
758;; Implement `sdiv` for 128-bit integers on z17 (only).
759(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (sdiv _ x y)))
760        (let ((OFcheck bool (div_overflow_check_needed y))
761              (_ Reg (maybe_trap_if_sdiv_overflow OFcheck $I128 $I128 x y)))
762        (vec_sdiv $I128 x y)))
763
764;; Implement `srem` for 128-bit integers on z17 (only).
765(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (srem _ x y)))
766        (let ((OFcheck bool (div_overflow_check_needed y))
767              (top Reg (maybe_avoid_srem_overflow OFcheck $I128 x y)))
768        (vec_srem $I128 top y)))
769
770
771;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
772
773;; Shift left, shift amount in register.
774(rule 0 (lower (has_type (fits_in_64 ty) (ishl _ x y)))
775      (let ((masked_amt Reg (mask_amt_reg ty (amt_reg y))))
776        (lshl_reg ty x masked_amt)))
777
778;; Shift left, immediate shift amount.
779(rule 1 (lower (has_type (fits_in_64 ty) (ishl _ x (i64_from_value y))))
780      (let ((masked_amt u8 (mask_amt_imm ty y)))
781        (lshl_imm ty x masked_amt)))
782
783;; Vector shift left, shift amount in register.
784(rule 2 (lower (has_type (ty_vec128 ty) (ishl _ x y)))
785      (vec_lshl_reg ty x (amt_reg y)))
786
787;; Vector shift left, immediate shift amount.
788(rule 3 (lower (has_type (ty_vec128 ty) (ishl _ x (i64_from_value y))))
789      (let ((masked_amt u8 (mask_amt_imm ty y)))
790        (vec_lshl_imm ty x masked_amt)))
791
792;; 128-bit vector shift left.
793(rule 4 (lower (has_type $I128 (ishl _ x y)))
794      (let ((amt Reg (amt_vr y)))
795        (vec_lshl_by_bit (vec_lshl_by_byte x amt) amt)))
796
797
798;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
799
800;; Shift right logical, shift amount in register.
801;; For types smaller than 32-bit, the input value must be zero-extended.
802(rule 0 (lower (has_type (fits_in_64 ty) (ushr _ x y)))
803      (let ((ext_reg Reg (put_in_reg_zext32 x))
804            (masked_amt Reg (mask_amt_reg ty (amt_reg y))))
805        (lshr_reg (ty_ext32 ty) ext_reg masked_amt)))
806
807;; Shift right logical, immediate shift amount.
808;; For types smaller than 32-bit, the input value must be zero-extended.
809(rule 1 (lower (has_type (fits_in_64 ty) (ushr _ x (i64_from_value y))))
810      (let ((ext_reg Reg (put_in_reg_zext32 x))
811            (masked_amt u8 (mask_amt_imm ty y)))
812        (lshr_imm (ty_ext32 ty) ext_reg masked_amt)))
813
814;; Vector shift right logical, shift amount in register.
815(rule 2 (lower (has_type (ty_vec128 ty) (ushr _ x y)))
816      (vec_lshr_reg ty x (amt_reg y)))
817
818;; Vector shift right logical, immediate shift amount.
819(rule 3 (lower (has_type (ty_vec128 ty) (ushr _ x (i64_from_value y))))
820      (let ((masked_amt u8 (mask_amt_imm ty y)))
821        (vec_lshr_imm ty x masked_amt)))
822
823;; 128-bit vector shift right logical.
824(rule 4 (lower (has_type $I128 (ushr _ x y)))
825      (let ((amt Reg (amt_vr y)))
826        (vec_lshr_by_bit (vec_lshr_by_byte x amt) amt)))
827
828
829;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
830
831;; Shift right arithmetic, shift amount in register.
832;; For types smaller than 32-bit, the input value must be sign-extended.
833(rule 0 (lower (has_type (fits_in_64 ty) (sshr _ x y)))
834      (let ((ext_reg Reg (put_in_reg_sext32 x))
835            (masked_amt Reg (mask_amt_reg ty (amt_reg y))))
836        (ashr_reg (ty_ext32 ty) ext_reg masked_amt)))
837
838;; Shift right arithmetic, immediate shift amount.
839;; For types smaller than 32-bit, the input value must be sign-extended.
840(rule 1 (lower (has_type (fits_in_64 ty) (sshr _ x (i64_from_value y))))
841      (let ((ext_reg Reg (put_in_reg_sext32 x))
842            (masked_amt u8 (mask_amt_imm ty y)))
843        (ashr_imm (ty_ext32 ty) ext_reg masked_amt)))
844
845;; Vector shift right arithmetic, shift amount in register.
846(rule 2 (lower (has_type (ty_vec128 ty) (sshr _ x y)))
847      (vec_ashr_reg ty x (amt_reg y)))
848
849;; Vector shift right arithmetic, immediate shift amount.
850(rule 3 (lower (has_type (ty_vec128 ty) (sshr _ x (i64_from_value y))))
851      (let ((masked_amt u8 (mask_amt_imm ty y)))
852        (vec_ashr_imm ty x masked_amt)))
853
854;; 128-bit vector shift right arithmetic.
855(rule 4 (lower (has_type $I128 (sshr _ x y)))
856      (let ((amt Reg (amt_vr y)))
857        (vec_ashr_by_bit (vec_ashr_by_byte x amt) amt)))
858
859
860;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
861
862;; Rotate left, shift amount in register.  32-bit or 64-bit types.
863(rule 0 (lower (has_type (ty_32_or_64 ty) (rotl _ x y)))
864      (rot_reg ty x (amt_reg y)))
865
866;; Rotate left arithmetic, immediate shift amount.  32-bit or 64-bit types.
867(rule 1 (lower (has_type (ty_32_or_64 ty) (rotl _ x (i64_from_value y))))
868      (let ((masked_amt u8 (mask_amt_imm ty y)))
869        (rot_imm ty x masked_amt)))
870
871;; Rotate left, shift amount in register.  8-bit or 16-bit types.
872;; Implemented via a pair of 32-bit shifts on the zero-extended input.
873(rule 2 (lower (has_type (ty_8_or_16 ty) (rotl _ x y)))
874      (let ((ext_reg Reg (put_in_reg_zext32 x))
875            (ext_ty Type (ty_ext32 ty))
876            (pos_amt Reg (amt_reg y))
877            (neg_amt Reg (neg_reg $I32 pos_amt))
878            (masked_pos_amt Reg (mask_amt_reg ty pos_amt))
879            (masked_neg_amt Reg (mask_amt_reg ty neg_amt)))
880        (or_reg ty (lshl_reg ext_ty ext_reg masked_pos_amt)
881                (lshr_reg ext_ty ext_reg masked_neg_amt))))
882
883;; Rotate left, immediate shift amount.  8-bit or 16-bit types.
884;; Implemented via a pair of 32-bit shifts on the zero-extended input.
885(rule 3 (lower (has_type (ty_8_or_16 ty) (rotl _ x (and (i64_from_value pos_amt)
886                                                    (i64_from_negated_value neg_amt)))))
887      (let ((ext_reg Reg (put_in_reg_zext32 x))
888            (ext_ty Type (ty_ext32 ty))
889            (masked_pos_amt u8 (mask_amt_imm ty pos_amt))
890            (masked_neg_amt u8 (mask_amt_imm ty neg_amt)))
891        (or_reg ty (lshl_imm ext_ty ext_reg masked_pos_amt)
892                (lshr_imm ext_ty ext_reg masked_neg_amt))))
893
894;; Vector rotate left, shift amount in register.
895(rule 4 (lower (has_type (ty_vec128 ty) (rotl _ x y)))
896      (vec_rot_reg ty x (amt_reg y)))
897
898;; Vector rotate left, immediate shift amount.
899(rule 5 (lower (has_type (ty_vec128 ty) (rotl _ x (i64_from_value y))))
900      (let ((masked_amt u8 (mask_amt_imm ty y)))
901        (vec_rot_imm ty x masked_amt)))
902
903;; 128-bit full vector rotate left.
904;; Implemented via a pair of 128-bit full vector shifts.
905(rule 6 (lower (has_type $I128 (rotl _ x y)))
906      (let ((x_reg Reg x)
907            (pos_amt Reg (amt_vr y))
908            (neg_amt Reg (vec_neg $I8X16 pos_amt)))
909        (vec_or $I128
910          (vec_lshl_by_bit (vec_lshl_by_byte x_reg pos_amt) pos_amt)
911          (vec_lshr_by_bit (vec_lshr_by_byte x_reg neg_amt) neg_amt))))
912
913
914;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
915
916;; Rotate right, shift amount in register.  32-bit or 64-bit types.
917;; Implemented as rotate left with negated rotate amount.
918(rule 0 (lower (has_type (ty_32_or_64 ty) (rotr _ x y)))
919      (let ((negated_amt Reg (neg_reg $I32 (amt_reg y))))
920        (rot_reg ty x negated_amt)))
921
922;; Rotate right arithmetic, immediate shift amount.  32-bit or 64-bit types.
923;; Implemented as rotate left with negated rotate amount.
924(rule 1 (lower (has_type (ty_32_or_64 ty) (rotr _ x (i64_from_negated_value y))))
925      (let ((negated_amt u8 (mask_amt_imm ty y)))
926        (rot_imm ty x negated_amt)))
927
928;; Rotate right, shift amount in register.  8-bit or 16-bit types.
929;; Implemented as rotate left with negated rotate amount.
930(rule 2 (lower (has_type (ty_8_or_16 ty) (rotr _ x y)))
931      (let ((ext_reg Reg (put_in_reg_zext32 x))
932            (ext_ty Type (ty_ext32 ty))
933            (pos_amt Reg (amt_reg y))
934            (neg_amt Reg (neg_reg $I32 pos_amt))
935            (masked_pos_amt Reg (mask_amt_reg ty pos_amt))
936            (masked_neg_amt Reg (mask_amt_reg ty neg_amt)))
937        (or_reg ty (lshl_reg ext_ty ext_reg masked_neg_amt)
938                (lshr_reg ext_ty ext_reg masked_pos_amt))))
939
940;; Rotate right, immediate shift amount.  8-bit or 16-bit types.
941;; Implemented as rotate left with negated rotate amount.
942(rule 3 (lower (has_type (ty_8_or_16 ty) (rotr _ x (and (i64_from_value pos_amt)
943                                                    (i64_from_negated_value neg_amt)))))
944      (let ((ext_reg Reg (put_in_reg_zext32 x))
945            (ext_ty Type (ty_ext32 ty))
946            (masked_pos_amt u8 (mask_amt_imm ty pos_amt))
947            (masked_neg_amt u8 (mask_amt_imm ty neg_amt)))
948        (or_reg ty (lshl_imm ext_ty ext_reg masked_neg_amt)
949                (lshr_imm ext_ty ext_reg masked_pos_amt))))
950
951;; Vector rotate right, shift amount in register.
952;; Implemented as rotate left with negated rotate amount.
953(rule 4 (lower (has_type (ty_vec128 ty) (rotr _ x y)))
954      (let ((negated_amt Reg (neg_reg $I32 (amt_reg y))))
955        (vec_rot_reg ty x negated_amt)))
956
957;; Vector rotate right, immediate shift amount.
958;; Implemented as rotate left with negated rotate amount.
959(rule 5 (lower (has_type (ty_vec128 ty) (rotr _ x (i64_from_negated_value y))))
960      (let ((negated_amt u8 (mask_amt_imm ty y)))
961        (vec_rot_imm ty x negated_amt)))
962
963;; 128-bit full vector rotate right.
964;; Implemented via a pair of 128-bit full vector shifts.
965(rule 6 (lower (has_type $I128 (rotr _ x y)))
966      (let ((x_reg Reg x)
967            (pos_amt Reg (amt_vr y))
968            (neg_amt Reg (vec_neg $I8X16 pos_amt)))
969        (vec_or $I128
970          (vec_lshl_by_bit (vec_lshl_by_byte x_reg neg_amt) neg_amt)
971          (vec_lshr_by_bit (vec_lshr_by_byte x_reg pos_amt) pos_amt))))
972
973
974;;;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
975
976;; Up to 64-bit source type: Always a no-op.
977(rule 1 (lower (ireduce _ x @ (value_type (fits_in_64 _ty))))
978      x)
979
980;; 128-bit source type: Extract the low half.
981(rule (lower (ireduce _ x @ (value_type (vr128_ty _ty))))
982      (vec_extract_lane $I64X2 x 1 (zero_reg)))
983
984
985;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
986
987;; 16- or 32-bit target types.
988(rule 1 (lower (has_type (gpr32_ty _ty) (uextend _ x)))
989      (put_in_reg_zext32 x))
990
991;; 64-bit target types.
992(rule 2 (lower (has_type (gpr64_ty _ty) (uextend _ x)))
993      (put_in_reg_zext64 x))
994
995;; 128-bit target types.
996(rule (lower (has_type $I128 (uextend _ x @ (value_type $I8))))
997      (vec_insert_lane $I8X16 (vec_imm $I128 0) x 15 (zero_reg)))
998(rule (lower (has_type $I128 (uextend _ x @ (value_type $I16))))
999      (vec_insert_lane $I16X8 (vec_imm $I128 0) x 7 (zero_reg)))
1000(rule (lower (has_type $I128 (uextend _ x @ (value_type $I32))))
1001      (vec_insert_lane $I32X4 (vec_imm $I128 0) x 3 (zero_reg)))
1002(rule (lower (has_type $I128 (uextend _ x @ (value_type $I64))))
1003      (vec_insert_lane $I64X2 (vec_imm $I128 0) x 1 (zero_reg)))
1004
1005
1006;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1007
1008;; 16- or 32-bit target types.
1009(rule 1 (lower (has_type (gpr32_ty _ty) (sextend _ x)))
1010      (put_in_reg_sext32 x))
1011
1012;; 64-bit target types.
1013(rule 2 (lower (has_type (gpr64_ty _ty) (sextend _ x)))
1014      (put_in_reg_sext64 x))
1015
1016;; 128-bit target types.
1017(rule (lower (has_type $I128 (sextend _ x)))
1018      (let ((x_ext Reg (put_in_reg_sext64 x)))
1019        (mov_to_vec128 $I128 (ashr_imm $I64 x_ext 63) x_ext)))
1020
1021
1022;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1023
1024(rule (lower (snarrow _ x @ (value_type (ty_vec128 ty)) y))
1025      (vec_pack_ssat_lane_order ty x y))
1026
1027
1028;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1029
1030(rule (lower (uunarrow _ x @ (value_type (ty_vec128 ty)) y))
1031      (vec_pack_usat_lane_order ty x y))
1032
1033
1034;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1035
1036(rule (lower (unarrow _ x @ (value_type (ty_vec128 ty)) y))
1037      (let ((zero Reg (vec_imm ty 0)))
1038        (vec_pack_usat_lane_order ty (vec_smax ty x zero) (vec_smax ty y zero))))
1039
1040
1041;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1042
1043(rule (lower (swiden_low _ x @ (value_type (ty_vec128 ty))))
1044      (vec_unpacks_low_lane_order ty x))
1045
1046
1047;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1048
1049(rule (lower (swiden_high _ x @ (value_type (ty_vec128 ty))))
1050      (vec_unpacks_high_lane_order ty x))
1051
1052
1053;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1054
1055(rule (lower (uwiden_low _ x @ (value_type (ty_vec128 ty))))
1056      (vec_unpacku_low_lane_order ty x))
1057
1058
1059;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1060
1061(rule (lower (uwiden_high _ x @ (value_type (ty_vec128 ty))))
1062      (vec_unpacku_high_lane_order ty x))
1063
1064
1065;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1066
1067;; z15 version using a single instruction (NOR).
1068(rule 2 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bnot _ x)))
1069      (let ((rx Reg x))
1070        (not_or_reg ty rx rx)))
1071
1072;; z14 version using XOR with -1.
1073(rule 1 (lower (has_type (and (mie3_disabled) (fits_in_64 ty)) (bnot _ x)))
1074      (not_reg ty x))
1075
1076;; Vector version using vector NOR.
1077(rule (lower (has_type (vr128_ty ty) (bnot _ x)))
1078      (vec_not ty x))
1079
1080;; Float version using vector NOR.
1081(rule 5 (lower (has_type (ty_scalar_float _) (bnot _ x)))
1082      (vec_not $F64X2 x))
1083
1084;; With z15 (bnot (bxor ...)) can be a single instruction, similar to the
1085;; (bxor _ (bnot _)) lowering.
1086(rule 3 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bnot _ (bxor _ x y))))
1087      (not_xor_reg ty x y))
1088
1089;; Combine a not/xor operation of vector types into one.
1090(rule 4 (lower (has_type (vr128_ty ty) (bnot _ (bxor _ x y))))
1091      (vec_not_xor ty x y))
1092
1093
1094;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1095
1096;; And two registers.
1097(rule -1 (lower (has_type (fits_in_64 ty) (band _ x y)))
1098      (and_reg ty x y))
1099
1100;; And a register and an immediate.
1101(rule 5 (lower (has_type (fits_in_64 ty) (band _ x (uimm16shifted_from_inverted_value y))))
1102      (and_uimm16shifted ty x y))
1103(rule 6 (lower (has_type (fits_in_64 ty) (band _ (uimm16shifted_from_inverted_value x) y)))
1104      (and_uimm16shifted ty y x))
1105(rule 3 (lower (has_type (fits_in_64 ty) (band _ x (uimm32shifted_from_inverted_value y))))
1106      (and_uimm32shifted ty x y))
1107(rule 4 (lower (has_type (fits_in_64 ty) (band _ (uimm32shifted_from_inverted_value x) y)))
1108      (and_uimm32shifted ty y x))
1109
1110;; And a register and memory (32/64-bit types).
1111(rule 1 (lower (has_type (fits_in_64 ty) (band _ x (sinkable_load_32_64 y))))
1112      (and_mem ty x (sink_load y)))
1113(rule 2 (lower (has_type (fits_in_64 ty) (band _ (sinkable_load_32_64 x) y)))
1114      (and_mem ty y (sink_load x)))
1115
1116;; And two vector registers.
1117(rule 0 (lower (has_type (vr128_ty ty) (band _ x y)))
1118      (vec_and ty x y))
1119
1120;; And two float registers, using vector overlay.
1121(rule 11 (lower (has_type (ty_scalar_float _) (band _ x y)))
1122      (vec_and $F64X2 x y))
1123
1124(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x y) z)))
1125      (vec_eval ty 0b00000001 x y z))
1126(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ y z))))
1127      (vec_eval ty 0b00000001 x y z))
1128
1129;; Specialized lowerings for `(band x (bnot y))` which is additionally produced
1130;; by Cranelift's `band_not` instruction that is legalized into the simpler
1131;; forms early on.
1132
1133;; z15 version using a single instruction.
1134(rule 7 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (band _ x (bnot _ y))))
1135      (and_not_reg ty x y))
1136(rule 8 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (band _ (bnot _ y) x)))
1137      (and_not_reg ty x y))
1138
1139;; And-not two vector registers.
1140(rule 9 (lower (has_type (vr128_ty ty) (band _ x (bnot _ y))))
1141      (vec_and_not ty x y))
1142(rule 10 (lower (has_type (vr128_ty ty) (band _ (bnot _ y) x)))
1143      (vec_and_not ty x y))
1144
1145;; And-not three vector registers.
1146(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ (bnot _ x) y) z)))
1147      (vec_eval ty 0b00010000 x y z))
1148(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ x) (band _ y z))))
1149      (vec_eval ty 0b00010000 x y z))
1150(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x y) (bnot _ z))))
1151      (vec_eval ty 0b00000010 x y z))
1152(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ y (bnot _ z)))))
1153      (vec_eval ty 0b00000010 x y z))
1154(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x (bnot _ y)) z)))
1155      (vec_eval ty 0b00000100 y x z))
1156(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ (bnot _ y) z))))
1157      (vec_eval ty 0b00000100 z x y))
1158
1159;; Not-and three vector registers
1160(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (band _ (band _ x y) z))))
1161      (vec_eval ty 0b11111110 x y z))
1162(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (band _ x (band _ y z)))))
1163      (vec_eval ty 0b11111110 x y z))
1164
1165;; And-Nand three vector registers
1166(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (band _ x y)) z)))
1167      (vec_eval ty 0b01010100 x y z))
1168(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (band _ y z)))))
1169      (vec_eval ty 0b00001110 x y z))
1170
1171;; And-Or 3 vector registers
1172(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bor _ y z))))
1173      (vec_eval ty 0b00000111 x y z))
1174(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bor _ x y) z)))
1175      (vec_eval ty 0b00010101 x y z))
1176
1177;; And-Nor 3 vector registers
1178(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (bor _ y z)))))
1179      (vec_eval ty 0b00001000 x y z))
1180(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (bor _ x y)) z)))
1181      (vec_eval ty 0b01000000 x y z))
1182
1183;; And-Xor 3 vector registers
1184(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bxor _ y z))))
1185      (vec_eval ty 0b00000110 x y z))
1186(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bxor _ x y) z)))
1187      (vec_eval ty 0b00010100 x y z))
1188
1189;; And-Nxor 3 vector registers
1190(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (bxor _ y z)))))
1191      (vec_eval ty 0b00001001 x y z))
1192(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (bxor _ x y)) z)))
1193      (vec_eval ty 0b01000001 x y z))
1194
1195;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1196
1197;; Or two registers.
1198(rule -1 (lower (has_type (fits_in_64 ty) (bor _ x y)))
1199      (or_reg ty x y))
1200
1201;; Or a register and an immediate.
1202(rule 5 (lower (has_type (fits_in_64 ty) (bor _ x (uimm16shifted_from_value y))))
1203      (or_uimm16shifted ty x y))
1204(rule 6 (lower (has_type (fits_in_64 ty) (bor _ (uimm16shifted_from_value x) y)))
1205      (or_uimm16shifted ty y x))
1206(rule 3 (lower (has_type (fits_in_64 ty) (bor _ x (uimm32shifted_from_value y))))
1207      (or_uimm32shifted ty x y))
1208(rule 4 (lower (has_type (fits_in_64 ty) (bor _ (uimm32shifted_from_value x) y)))
1209      (or_uimm32shifted ty y x))
1210
1211;; Or a register and memory (32/64-bit types).
1212(rule 1 (lower (has_type (fits_in_64 ty) (bor _ x (sinkable_load_32_64 y))))
1213      (or_mem ty x (sink_load y)))
1214(rule 2 (lower (has_type (fits_in_64 ty) (bor _ (sinkable_load_32_64 x) y)))
1215      (or_mem ty y (sink_load x)))
1216
1217;; Or two vector registers.
1218(rule 0 (lower (has_type (vr128_ty ty) (bor _ x y)))
1219      (vec_or ty x y))
1220
1221;; Or two floating registers, using vector overlay
1222(rule 11 (lower (has_type (ty_scalar_float _) (bor _ x y)))
1223      (vec_or $F64X2 x y))
1224
1225;; Or three vector registers.
1226(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x y) z)))
1227      (vec_eval ty 0b01111111 x y z))
1228(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ y z))))
1229      (vec_eval ty 0b01111111 x y z))
1230
1231;; Specialized lowerings for `(bor x (bnot y))` which is additionally produced
1232;; by Cranelift's `bor_not` instruction that is legalized into the simpler
1233;; forms early on.
1234
1235;; z15 version using a single instruction.
1236(rule 7 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bor _ x (bnot _ y))))
1237      (or_not_reg ty x y))
1238(rule 8 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bor _ (bnot _ y) x)))
1239      (or_not_reg ty x y))
1240
1241;; Or-not two vector registers.
1242(rule 9 (lower (has_type (vr128_ty ty) (bor _ x (bnot _ y))))
1243      (vec_or_not ty x y))
1244(rule 10 (lower (has_type (vr128_ty ty) (bor _ (bnot _ y) x)))
1245      (vec_or_not ty x y))
1246
1247;; 3-input bor with a single not
1248(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ (bnot _ x) y) z)))
1249      (vec_eval ty 0b11110111 x y z))
1250(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ x) (bor _ y z))))
1251      (vec_eval ty 0b11110111 x y z))
1252(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x (bnot _ y)) z)))
1253      (vec_eval ty 0b11011111 x y z))
1254(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ (bnot _ y) z))))
1255      (vec_eval ty 0b11011111 x y z))
1256(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x y) (bnot _ z))))
1257      (vec_eval ty 0b10111111 x y z))
1258(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ y (bnot _ z)))))
1259      (vec_eval ty 0b10111111 x y z))
1260
1261;; 3-input bnor
1262(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bor _ x y) z))))
1263      (vec_eval ty 0b10000000 x y z))
1264(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bor _ y z)))))
1265      (vec_eval ty 0b10000000 x y z))
1266
1267;; Or-Nor
1268(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (bor _ x y)) z)))
1269      (vec_eval ty 0b11010101 x y z))
1270(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (bor _ y z)))))
1271      (vec_eval ty 0b10001111 x y z))
1272
1273;; Or-And
1274(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (band _ x y) z)))
1275      (vec_eval ty 0b01010111 x y z))
1276(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (band _ y z))))
1277      (vec_eval ty 0b00011111 x y z))
1278
1279;; Or-Nand
1280(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (band _ x y)) z)))
1281      (vec_eval ty 0b11111101 x y z))
1282(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (band _ y z)))))
1283      (vec_eval ty 0b11101111 x y z))
1284
1285;; Or-Xor
1286(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bxor _ x y) z)))
1287      (vec_eval ty 0b01111101 x y z))
1288(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bxor _ y z))))
1289      (vec_eval ty 0b01101111 x y z))
1290
1291;; Or-Nxor
1292(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (bxor _ x y)) z)))
1293      (vec_eval ty 0b11010111 x y z))
1294(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (bxor _ y z)))))
1295      (vec_eval ty 0b10011111 x y z))
1296
1297;; Nor-And
1298(rule 30 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (band _ x y) z))))
1299      (vec_eval ty 0b10101000 x y z))
1300(rule 31 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (band _ y z)))))
1301      (vec_eval ty 0b11100000 x y z))
1302
1303;; Nor-Nand
1304(rule 32 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bnot _ (band _ x y)) z))))
1305      (vec_eval ty 0b00000010 x y z))
1306(rule 33 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bnot _ (band _ y z))))))
1307      (vec_eval ty 0b00010000 x y z))
1308
1309;; Nor-Xor
1310(rule 34 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bxor _ x y) z))))
1311      (vec_eval ty 0b10000010 x y z))
1312(rule 35 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bxor _ y z)))))
1313      (vec_eval ty 0b10010000 x y z))
1314
1315;; Nor-Nxor
1316(rule 36 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bnot _ (bxor _ x y)) z))))
1317      (vec_eval ty 0b00101000 x y z))
1318(rule 37 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bnot _ (bxor _ y z))))))
1319      (vec_eval ty 0b01100000 x y z))
1320
1321;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1322
1323;; Xor two registers.
1324(rule -1 (lower (has_type (fits_in_64 ty) (bxor _ x y)))
1325      (xor_reg ty x y))
1326
1327;; Xor a register and an immediate.
1328(rule 3 (lower (has_type (fits_in_64 ty) (bxor _ x (uimm32shifted_from_value y))))
1329      (xor_uimm32shifted ty x y))
1330(rule 4 (lower (has_type (fits_in_64 ty) (bxor _ (uimm32shifted_from_value x) y)))
1331      (xor_uimm32shifted ty y x))
1332
1333;; Xor a register and memory (32/64-bit types).
1334(rule 1 (lower (has_type (fits_in_64 ty) (bxor _ x (sinkable_load_32_64 y))))
1335      (xor_mem ty x (sink_load y)))
1336(rule 2 (lower (has_type (fits_in_64 ty) (bxor _ (sinkable_load_32_64 x) y)))
1337      (xor_mem ty y (sink_load x)))
1338
1339;; Xor two vector registers.
1340(rule 0 (lower (has_type (vr128_ty ty) (bxor _ x y)))
1341      (vec_xor ty x y))
1342
1343;; Xor two floating registers, using vector overlay
1344(rule 9 (lower (has_type (ty_scalar_float _) (bxor _ x y)))
1345      (vec_xor $F64X2 x y))
1346
1347;; Specialized lowerings for `(bxor x (bnot y))` which is additionally produced
1348;; by Cranelift's `bxor_not` instruction that is legalized into the simpler
1349;; forms early on.
1350
1351;; z15 version using a single instruction.
1352(rule 5 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bxor _ x (bnot _ y))))
1353      (not_xor_reg ty x y))
1354(rule 6 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bxor _ (bnot _ y) x)))
1355      (not_xor_reg ty x y))
1356
1357;; Xor-not two vector registers.
1358(rule 7 (lower (has_type (vr128_ty ty) (bxor _ x (bnot _ y))))
1359      (vec_not_xor ty x y))
1360(rule 8 (lower (has_type (vr128_ty ty) (bxor _ (bnot _ y) x)))
1361      (vec_not_xor ty x y))
1362
1363;; 3-input Xor
1364(rule 10 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bxor _ x y) z)))
1365      (vec_eval ty 0b01101001 x y z))
1366(rule 11 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bxor _ y z))))
1367      (vec_eval ty 0b01101001 x y z))
1368
1369;; Xor-And
1370(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (band _ x y) z)))
1371      (vec_eval ty 0b01010110 x y z))
1372(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (band _ y z))))
1373      (vec_eval ty 0b00011110 x y z))
1374
1375;; Xor-Nand
1376(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (band _ x y)) z)))
1377      (vec_eval ty 0b10101001 x y z))
1378(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (band _ y z)))))
1379      (vec_eval ty 0b11100001 x y z))
1380
1381;; Xor-Or
1382(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bor _ x y) z)))
1383      (vec_eval ty 0b01101010 x y z))
1384(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bor _ y z))))
1385      (vec_eval ty 0b01111000 x y z))
1386
1387;; Xor-Nor
1388(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (bor _ x y)) z)))
1389      (vec_eval ty 0b10010101 x y z))
1390(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (bor _ y z)))))
1391      (vec_eval ty 0b10000111 x y z))
1392
1393;; Xor-Nxor
1394(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (bxor _ x y)) z)))
1395      (vec_eval ty 0b10010110 x y z))
1396(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (bxor _ y z)))))
1397      (vec_eval ty 0b10010110 x y z))
1398
1399;; 3-input Nxor
1400(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bxor _ x y) z))))
1401      (vec_eval ty 0b10010110 x y z))
1402(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bxor _ y z)))))
1403      (vec_eval ty 0b10010110 x y z))
1404
1405;; Nxor-And
1406(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (band _ x y) z))))
1407      (vec_eval ty 0b10101001 x y z))
1408(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (band _ y z)))))
1409      (vec_eval ty 0b11100001 x y z))
1410
1411;; Nxor-Nand
1412(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (band _ x y)) z))))
1413      (vec_eval ty 0b01010110 x y z))
1414(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (band _ y z))))))
1415      (vec_eval ty 0b00011110 x y z))
1416
1417;; Nxor-Or
1418(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bor _ x y) z))))
1419      (vec_eval ty 0b10010101 x y z))
1420(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bor _ y z)))))
1421      (vec_eval ty 0b10000111 x y z))
1422
1423;; Nxor-Nor
1424(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (bor _ x y)) z))))
1425      (vec_eval ty 0b01101010 x y z))
1426(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (bor _ y z))))))
1427      (vec_eval ty 0b01111000 x y z))
1428
1429;; Xor-Nxor
1430(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (bxor _ x y)) z))))
1431      (vec_eval ty 0b01101001 x y z))
1432(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (bxor _ y z))))))
1433      (vec_eval ty 0b01101001 x y z))
1434
1435;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1436
1437;; z15 version using a NAND instruction.
1438(rule 2 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bitselect _ x y z)))
1439      (let ((rx Reg x)
1440            (if_true Reg (and_reg ty y rx))
1441            (if_false Reg (and_not_reg ty z rx)))
1442        (or_reg ty if_false if_true)))
1443
1444;; z14 version using XOR with -1.
1445(rule 1 (lower (has_type (and (mie3_disabled) (fits_in_64 ty)) (bitselect _ x y z)))
1446      (let ((rx Reg x)
1447            (if_true Reg (and_reg ty y rx))
1448            (if_false Reg (and_reg ty z (not_reg ty rx))))
1449        (or_reg ty if_false if_true)))
1450
1451;; Bitselect vector registers.
1452(rule (lower (has_type (vr128_ty ty) (bitselect _ x y z)))
1453      (vec_select ty y z x))
1454
1455;; Bitselect-not vector registers.
1456(rule 5 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x (bnot _ y) z)))
1457      (vec_eval ty 0b01011100 x y z))
1458(rule 6 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x y (bnot _ z))))
1459      (vec_eval ty 0b10100011 x y z))
1460(rule 7 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x (bnot _ y) (bnot _ z))))
1461      (vec_eval ty 0b10101100 x y z))
1462
1463;; Special-case some float-selection instructions for min/max
1464(rule 3 (lower (has_type (ty_vec128 ty) (bitselect _ (bitcast _ _ (fcmp _ (FloatCC.LessThan) x y)) x y)))
1465        (fmin_pseudo_reg ty y x))
1466(rule 4 (lower (has_type (ty_vec128 ty) (bitselect _ (bitcast _ _ (fcmp _ (FloatCC.LessThan) y x)) x y)))
1467        (fmax_pseudo_reg ty y x))
1468
1469
1470
1471;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1472
1473(rule (lower (has_type ty (bmask _ x)))
1474      (lower_bool_to_mask ty (value_nonzero x)))
1475
1476
1477;;;; Rules for `bitrev` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1478
1479(rule (lower (has_type ty (bitrev _ x)))
1480      (bitrev_bytes ty
1481        (bitrev_bits 4 0xf0f0_f0f0_f0f0_f0f0 ty
1482          (bitrev_bits 2 0xcccc_cccc_cccc_cccc ty
1483            (bitrev_bits 1 0xaaaa_aaaa_aaaa_aaaa ty x)))))
1484
1485(decl bitrev_bits (u8 u64 Type Reg) Reg)
1486(rule 1 (bitrev_bits size bitmask (fits_in_64 ty) x)
1487      (let ((mask Reg (imm ty bitmask))
1488            (xh Reg (lshl_imm (ty_ext32 ty) x size))
1489            (xl Reg (lshr_imm (ty_ext32 ty) x size))
1490            (xh_masked Reg (and_reg ty xh mask))
1491            (xl_masked Reg (and_reg ty xl (not_reg ty mask))))
1492        (or_reg ty xh_masked xl_masked)))
1493
1494(rule (bitrev_bits size bitmask (vr128_ty ty) x)
1495      (let ((mask Reg (vec_imm_splat $I64X2 bitmask))
1496            (size_reg Reg (vec_imm_splat $I8X16 size))
1497            (xh Reg (vec_lshl_by_bit x size_reg))
1498            (xl Reg (vec_lshr_by_bit x size_reg)))
1499        (vec_select ty xh xl mask)))
1500
1501(decl bitrev_bytes (Type Reg) Reg)
1502(rule (bitrev_bytes $I8 x) x)
1503(rule (bitrev_bytes $I16 x) (lshr_imm $I32 (bswap_reg $I32 x) 16))
1504(rule (bitrev_bytes $I32 x) (bswap_reg $I32 x))
1505(rule (bitrev_bytes $I64 x) (bswap_reg $I64 x))
1506(rule (bitrev_bytes $I128 x)
1507      (vec_permute $I128 x x
1508                   (vec_imm $I8X16 (imm8x16 15 14 13 12 11 10 9 8
1509                                            7 6 5 4 3 2 1 0))))
1510
1511
1512;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1513
1514(rule (lower (has_type ty (bswap _ x)))
1515      (bitrev_bytes ty x))
1516
1517;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1518
1519;; The FLOGR hardware instruction always operates on the full 64-bit register.
1520;; We can zero-extend smaller types, but then we have to compensate for the
1521;; additional leading zero bits the instruction will actually see.
1522(decl clz_offset (Type Reg) Reg)
1523(rule (clz_offset $I8 x) (add_simm16 $I8 x -56))
1524(rule (clz_offset $I16 x) (add_simm16 $I16 x -48))
1525(rule (clz_offset $I32 x) (add_simm16 $I32 x -32))
1526(rule (clz_offset $I64 x) x)
1527
1528;; Count leading zeros pre-z17, via FLOGR on an input zero-extended to 64 bits,
1529;; with the result compensated for the extra bits.
1530(rule 1 (lower (has_type (and (mie4_disabled) (fits_in_64 ty)) (clz _ x)))
1531      (let ((ext_reg Reg (put_in_reg_zext64 x))
1532            ;; Ask for a value of 64 in the all-zero 64-bit input case.
1533            ;; After compensation this will match the expected semantics.
1534            (clz Reg (clz_flogr_reg 64 ext_reg)))
1535        (clz_offset ty clz)))
1536
1537;; Count leading zeros, 128-bit full vector pre-z17.
1538(rule (lower (has_type (and (vxrs_ext3_disabled) $I128) (clz _ x)))
1539      (let ((clz_vec Reg (vec_clz $I64X2 x))
1540            (zero Reg (vec_imm $I64X2 0))
1541            (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0))
1542            (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1))
1543            (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo))
1544            (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64))))
1545        (vec_select $I128 clz_sum clz_hi mask)))
1546
1547;; Count leading zeros on z17, via CLZG on an input zero-extended to 64 bits,
1548;; with the result compensated for the extra bits.
1549(rule 3 (lower (has_type (and (mie4_enabled) (fits_in_64 ty)) (clz _ x)))
1550      (let ((ext_reg Reg (put_in_reg_zext64 x))
1551            (clz Reg (clz_reg ext_reg)))
1552        (clz_offset ty clz)))
1553
1554;; Count leading zeros, 128-bit full vector on z17.
1555(rule 2 (lower (has_type (and (vxrs_ext3_enabled) $I128) (clz _ x)))
1556        (vec_clz $I128 x))
1557
1558;;;; Rules for `cls` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1559
1560;; The result of cls is not supposed to count the sign bit itself, just
1561;; additional copies of it.  Therefore, when computing cls in terms of clz,
1562;; we need to subtract one.  Fold this into the offset computation.
1563(decl cls_offset (Type Reg) Reg)
1564(rule (cls_offset $I8 x) (add_simm16 $I8 x -57))
1565(rule (cls_offset $I16 x) (add_simm16 $I16 x -49))
1566(rule (cls_offset $I32 x) (add_simm16 $I32 x -33))
1567(rule (cls_offset $I64 x) (add_simm16 $I64 x -1))
1568
1569;; Count leading sign-bit copies pre-z17.  We don't have any instruction for that,
1570;; so we instead count the leading zeros after inverting the input if negative,
1571;; i.e. computing
1572;;        cls(x) == clz(x ^ (x >> 63)) - 1
1573;; where x is the sign-extended input.
1574(rule 1 (lower (has_type (and (mie4_disabled) (fits_in_64 ty)) (cls _ x)))
1575      (let ((ext_reg Reg (put_in_reg_sext64 x))
1576            (signbit_copies Reg (ashr_imm $I64 ext_reg 63))
1577            (inv_reg Reg (xor_reg $I64 ext_reg signbit_copies))
1578            (clz Reg (clz_flogr_reg 64 inv_reg)))
1579        (cls_offset ty clz)))
1580
1581;; Count leading sign-bit copies, 128-bit full vector pre-z17.
1582(rule (lower (has_type (and (vxrs_ext3_disabled) $I128) (cls _ x)))
1583      (let ((x_reg Reg x)
1584            (ones Reg (vec_imm_splat $I8X16 255))
1585            (signbit_copies Reg (vec_ashr_by_bit (vec_ashr_by_byte x_reg ones) ones))
1586            (inv_reg Reg (vec_xor $I128 x_reg signbit_copies))
1587            (clz_vec Reg (vec_clz $I64X2 inv_reg))
1588            (zero Reg (vec_imm $I64X2 0))
1589            (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0))
1590            (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1))
1591            (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo))
1592            (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64))))
1593        (vec_add $I128 (vec_select $I128 clz_sum clz_hi mask) ones)))
1594
1595;; Count leading sign-bit copies on z17, similar to above.
1596(rule 3 (lower (has_type (and (mie4_enabled) (fits_in_64 ty)) (cls _ x)))
1597        (let ((ext_reg Reg (put_in_reg_sext64 x))
1598              (signbit_copies Reg (ashr_imm $I64 ext_reg 63))
1599              (inv_reg Reg (xor_reg $I64 ext_reg signbit_copies))
1600              (clz Reg (clz_reg inv_reg)))
1601          (cls_offset ty clz)))
1602
1603;; Count leading sign-bit copies, 128-bit full vector on z17.
1604(rule 2 (lower (has_type (and (vxrs_ext3_enabled) $I128) (cls _ x)))
1605        (let ((x_reg Reg x)
1606              (ones Reg (vec_imm_splat $I8X16 255))
1607              (signbit_copies Reg (vec_ashr_by_bit (vec_ashr_by_byte x_reg ones) ones))
1608              (inv_reg Reg (vec_xor $I128 x_reg signbit_copies))
1609              (clz_vec Reg (vec_clz $I128 inv_reg)))
1610          (vec_add $I128 clz_vec ones)))
1611
1612;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1613
1614;; To count trailing zeros, we find the last bit set in the input via (x & -x),
1615;; count the leading zeros of that value, and subtract from 63:
1616;;
1617;;   ctz(x) == 63 - clz(x & -x)
1618;;
1619;; This works for all cases except a zero input, where the above formula would
1620;; return -1, but we are expected to return the type size.  The compensation
1621;; for this case is handled differently for 64-bit types vs. smaller types.
1622
1623;; For smaller types, we simply ensure that the extended 64-bit input is
1624;; never zero by setting a "guard bit" in the position corresponding to
1625;; the input type size.  This way the 64-bit algorithm above will handle
1626;; that case correctly automatically.
1627(rule 2 (lower (has_type (and (mie4_disabled) (gpr32_ty ty)) (ctz _ x)))
1628      (let ((rx Reg (or_uimm16shifted $I64 x (ctz_guardbit ty)))
1629            (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx)))
1630            (clz Reg (clz_flogr_reg 64 lastbit)))
1631        (sub_reg ty (imm ty 63) clz)))
1632
1633(decl ctz_guardbit (Type) UImm16Shifted)
1634(rule (ctz_guardbit $I8) (uimm16shifted 256 0))
1635(rule (ctz_guardbit $I16) (uimm16shifted 1 16))
1636(rule (ctz_guardbit $I32) (uimm16shifted 1 32))
1637
1638;; For 64-bit types, the FLOGR instruction will indicate the zero input case
1639;; via its condition code.  We check for that and replace the instruction
1640;; result with the value -1 via a conditional move, which will then lead to
1641;; the correct result after the final subtraction from 63.
1642(rule 1 (lower (has_type (and (mie4_disabled) (gpr64_ty _ty)) (ctz _ x)))
1643      (let ((rx Reg x)
1644            (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx)))
1645            (clz Reg (clz_flogr_reg -1 lastbit)))
1646        (sub_reg $I64 (imm $I64 63) clz)))
1647
1648;; Count trailing zeros, 128-bit full vector pre-z17.
1649(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (ctz _ x)))
1650      (let ((ctz_vec Reg (vec_ctz $I64X2 x))
1651            (zero Reg (vec_imm $I64X2 0))
1652            (ctz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 0))
1653            (ctz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 1))
1654            (ctz_sum Reg (vec_add $I64X2 ctz_hi ctz_lo))
1655            (mask Reg (vec_cmpeq $I64X2 ctz_lo (vec_imm_splat $I64X2 64))))
1656        (vec_select $I128 ctz_sum ctz_lo mask)))
1657
1658;; Count leading zeros on z17, via CTZG on types smaller than 64-bit,
1659;; using the same guard bit mechanism as above.
1660(rule 5 (lower (has_type (and (mie4_enabled) (gpr32_ty ty)) (ctz _ x)))
1661        (ctz_reg (or_uimm16shifted $I64 x (ctz_guardbit ty))))
1662
1663;; Count leading zeros on z17, via CTZG directly on 64-bit types.
1664(rule 4 (lower (has_type (and (mie4_enabled) (gpr64_ty _ty)) (ctz _ x)))
1665        (ctz_reg x))
1666
1667;; Count trailing zeros, 128-bit full vector on z17.
1668(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (ctz _ x)))
1669        (vec_ctz $I128 x))
1670
1671
1672;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1673
1674;; Population count for 8-bit types is supported by the POPCNT instruction.
1675(rule (lower (has_type $I8 (popcnt _ x)))
1676      (popcnt_byte x))
1677
1678;; On z15, the POPCNT instruction has a variant to compute a full 64-bit
1679;; population count, which we also use for 16- and 32-bit types.
1680(rule -1 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (popcnt _ x)))
1681      (popcnt_reg (put_in_reg_zext64 x)))
1682
1683;; On z14, we use the regular POPCNT, which computes the population count
1684;; of each input byte separately, so we need to accumulate those partial
1685;; results via a series of log2(type size in bytes) - 1 additions.  We
1686;; accumulate in the high byte, so that a final right shift will zero out
1687;; any unrelated bits to give a clean result.  (This does not work with
1688;; $I16, where we instead accumulate in the low byte and clear high bits
1689;; via an explicit and operation.)
1690
1691(rule (lower (has_type (and (mie3_disabled) $I16) (popcnt _ x)))
1692      (let ((cnt2 Reg (popcnt_byte x))
1693            (cnt1 Reg (add_reg $I32 cnt2 (lshr_imm $I32 cnt2 8))))
1694        (and_uimm16shifted $I32 cnt1 (uimm16shifted 255 0))))
1695
1696(rule (lower (has_type (and (mie3_disabled) $I32) (popcnt _ x)))
1697      (let ((cnt4 Reg (popcnt_byte x))
1698            (cnt2 Reg (add_reg $I32 cnt4 (lshl_imm $I32 cnt4 16)))
1699            (cnt1 Reg (add_reg $I32 cnt2 (lshl_imm $I32 cnt2 8))))
1700        (lshr_imm $I32 cnt1 24)))
1701
1702(rule (lower (has_type (and (mie3_disabled) $I64) (popcnt _ x)))
1703      (let ((cnt8 Reg (popcnt_byte x))
1704            (cnt4 Reg (add_reg $I64 cnt8 (lshl_imm $I64 cnt8 32)))
1705            (cnt2 Reg (add_reg $I64 cnt4 (lshl_imm $I64 cnt4 16)))
1706            (cnt1 Reg (add_reg $I64 cnt2 (lshl_imm $I64 cnt2 8))))
1707        (lshr_imm $I64 cnt1 56)))
1708
1709;; Population count for vector types.
1710(rule 1 (lower (has_type (ty_vec128 ty) (popcnt _ x)))
1711      (vec_popcnt ty x))
1712
1713;; Population count, 128-bit full vector.
1714(rule (lower (has_type $I128 (popcnt _ x)))
1715      (let ((popcnt_vec Reg (vec_popcnt $I64X2 x))
1716            (zero Reg (vec_imm $I64X2 0))
1717            (popcnt_hi Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 0))
1718            (popcnt_lo Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 1)))
1719        (vec_add $I64X2 popcnt_hi popcnt_lo)))
1720
1721
1722;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1723
1724;; Add two registers.
1725(rule (lower (has_type ty (fadd _ x y)))
1726      (fadd_reg ty x y))
1727
1728
1729;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1730
1731;; Subtract two registers.
1732(rule (lower (has_type ty (fsub _ x y)))
1733      (fsub_reg ty x y))
1734
1735
1736;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1737
1738;; Multiply two registers.
1739(rule (lower (has_type ty (fmul _ x y)))
1740      (fmul_reg ty x y))
1741
1742
1743;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1744
1745;; Divide two registers.
1746(rule (lower (has_type ty (fdiv _ x y)))
1747      (fdiv_reg ty x y))
1748
1749
1750;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1751
1752;; Minimum of two registers.
1753(rule (lower (has_type ty (fmin _ x y)))
1754      (fmin_reg ty x y))
1755
1756
1757;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1758
1759;; Maximum of two registers.
1760(rule (lower (has_type ty (fmax _ x y)))
1761      (fmax_reg ty x y))
1762
1763
1764;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1765
1766;; Copysign of two registers.
1767(rule (lower (has_type $F32 (fcopysign _ x y)))
1768      (vec_select $F32 x y (imm $F32 2147483647)))
1769(rule (lower (has_type $F64 (fcopysign _ x y)))
1770      (vec_select $F64 x y (imm $F64 9223372036854775807)))
1771(rule (lower (has_type $F128 (fcopysign _ x y)))
1772      (vec_select $F128 x y (vec_imm $F128 (imm8x16 127 255 255 255 255 255 255 255
1773                                                    255 255 255 255 255 255 255 255))))
1774(rule (lower (has_type $F32X4 (fcopysign _ x y)))
1775      (vec_select $F32X4 x y (vec_imm_bit_mask $F32X4 1 31)))
1776(rule (lower (has_type $F64X2 (fcopysign _ x y)))
1777      (vec_select $F64X2 x y (vec_imm_bit_mask $F64X2 1 63)))
1778
1779
1780;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1781
1782;; Multiply-and-add of three registers.
1783(rule (lower (has_type ty (fma _ x y z)))
1784      (fma_reg ty x y z))
1785
1786
1787;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1788
1789;; Square root of a register.
1790(rule (lower (has_type ty (sqrt _ x)))
1791      (sqrt_reg ty x))
1792
1793
1794;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1795
1796;; Negated value of a register.
1797(rule (lower (has_type ty (fneg _ x)))
1798      (fneg_reg ty x))
1799
1800
1801;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1802
1803;; Absolute value of a register.
1804(rule (lower (has_type ty (fabs _ x)))
1805      (fabs_reg ty x))
1806
1807
1808;;;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1809
1810;; Round value in a register towards positive infinity.
1811(rule (lower (has_type ty (ceil _ x)))
1812      (ceil_reg ty x))
1813
1814
1815;;;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1816
1817;; Round value in a register towards negative infinity.
1818(rule (lower (has_type ty (floor _ x)))
1819      (floor_reg ty x))
1820
1821
1822;;;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1823
1824;; Round value in a register towards zero.
1825(rule (lower (has_type ty (trunc _ x)))
1826      (trunc_reg ty x))
1827
1828
1829;;;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1830
1831;; Round value in a register towards nearest.
1832(rule (lower (has_type ty (nearest _ x)))
1833      (nearest_reg ty x))
1834
1835
1836;;;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1837
1838;; Promote a register.
1839(rule (lower (has_type dst_ty (fpromote _ x @ (value_type src_ty))))
1840      (fpromote_reg dst_ty src_ty x))
1841
1842(rule 1 (lower (has_type $F128 (fpromote _ x @ (value_type $F32))))
1843      (fpromote_reg $F128 $F64 (fpromote_reg $F64 $F32 x)))
1844
1845
1846;;;; Rules for `fvpromote_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1847
1848;; Promote a register.
1849(rule (lower (has_type $F64X2 (fvpromote_low _ x @ (value_type $F32X4))))
1850      (fpromote_reg $F64X2 $F32X4 (vec_merge_low_lane_order $I32X4 x x)))
1851
1852
1853;;;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1854
1855;; Demote a register.
1856(rule (lower (has_type dst_ty (fdemote _ x @ (value_type src_ty))))
1857      (fdemote_reg dst_ty src_ty (FpuRoundMode.Current) x))
1858
1859(rule 1 (lower (has_type $F32 (fdemote _ x @ (value_type $F128))))
1860      (fdemote_reg $F32 $F64 (FpuRoundMode.Current)
1861                   (fdemote_reg $F64 $F128 (FpuRoundMode.ShorterPrecision) x)))
1862
1863
1864;;;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1865
1866;; Demote a register.
1867(rule (lower (has_type $F32X4 (fvdemote _ x @ (value_type $F64X2))))
1868      (let ((dst Reg (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.Current) x)))
1869        (vec_pack_lane_order $I64X2 (vec_lshr_imm $I64X2 dst 32)
1870                                    (vec_imm $I64X2 0))))
1871
1872
1873;;;; Rules for `fcvt_from_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1874
1875;; Convert a 32-bit or smaller unsigned integer to $F32 (z15 instruction).
1876(rule 1 (lower (has_type $F32
1877        (fcvt_from_uint _ x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty))))))
1878      (fcvt_from_uint_reg $F32 $I32 (FpuRoundMode.ToNearestTiesToEven)
1879                          (put_in_reg_zext32 x)))
1880
1881;; Convert a 64-bit or smaller unsigned integer to $F32, via an intermediate $F64.
1882(rule (lower (has_type $F32 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty)))))
1883      (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven)
1884                   (fcvt_from_uint_reg $F64 $I64 (FpuRoundMode.ShorterPrecision)
1885                                       (put_in_reg_zext64 x))))
1886
1887;; Convert a 64-bit or smaller unsigned integer to $F64.
1888(rule (lower (has_type $F64 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty)))))
1889      (fcvt_from_uint_reg $F64 $I64 (FpuRoundMode.ToNearestTiesToEven)
1890                          (put_in_reg_zext64 x)))
1891
1892;; Convert a 32-bit or smaller unsigned integer to $F128.
1893(rule 1 (lower (has_type $F128 (fcvt_from_uint _ x @ (value_type (fits_in_32 ty)))))
1894      (fcvt_from_uint_reg $F128 $I32 (FpuRoundMode.ToNearestTiesToEven)
1895                          (put_in_reg_zext32 x)))
1896
1897;; Convert a 64-bit or smaller unsigned integer to $F128.
1898(rule (lower (has_type $F128 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty)))))
1899      (fcvt_from_uint_reg $F128 $I64 (FpuRoundMode.ToNearestTiesToEven)
1900                          (put_in_reg_zext64 x)))
1901
1902;; Convert $I32X4 to $F32X4 (z15 instruction).
1903(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4)
1904                       (fcvt_from_uint _ x @ (value_type $I32X4))))
1905      (fcvt_from_uint_reg $F32X4 $I32X4 (FpuRoundMode.ToNearestTiesToEven) x))
1906
1907;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14).
1908(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4)
1909                       (fcvt_from_uint _ x @ (value_type $I32X4))))
1910      (vec_permute $F32X4
1911        (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven)
1912          (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision)
1913                              (vec_unpacku_high $I32X4 x)))
1914        (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven)
1915          (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision)
1916                              (vec_unpacku_low $I32X4 x)))
1917        (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27))))
1918
1919;; Convert $I64X2 to $F64X2.
1920(rule (lower (has_type $F64X2 (fcvt_from_uint _ x @ (value_type $I64X2))))
1921      (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ToNearestTiesToEven) x))
1922
1923
1924;;;; Rules for `fcvt_from_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1925
1926;; Convert a 32-bit or smaller signed integer to $F32 (z15 instruction).
1927(rule 1 (lower (has_type $F32
1928        (fcvt_from_sint _ x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty))))))
1929      (fcvt_from_sint_reg $F32 $I32 (FpuRoundMode.ToNearestTiesToEven)
1930                          (put_in_reg_sext32 x)))
1931
1932;; Convert a 64-bit or smaller signed integer to $F32, via an intermediate $F64.
1933(rule (lower (has_type $F32 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty)))))
1934      (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven)
1935                   (fcvt_from_sint_reg $F64 $I64 (FpuRoundMode.ShorterPrecision)
1936                                       (put_in_reg_sext64 x))))
1937
1938;; Convert a 64-bit or smaller signed integer to $F64.
1939(rule (lower (has_type $F64 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty)))))
1940      (fcvt_from_sint_reg $F64 $I64 (FpuRoundMode.ToNearestTiesToEven)
1941                          (put_in_reg_sext64 x)))
1942
1943;; Convert a 32-bit or smaller signed integer to $F128.
1944(rule 1 (lower (has_type $F128 (fcvt_from_sint _ x @ (value_type (fits_in_32 ty)))))
1945      (fcvt_from_sint_reg $F128 $I32 (FpuRoundMode.ToNearestTiesToEven)
1946                          (put_in_reg_sext32 x)))
1947
1948;; Convert a 64-bit or smaller signed integer to $F128.
1949(rule (lower (has_type $F128 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty)))))
1950      (fcvt_from_sint_reg $F128 $I64 (FpuRoundMode.ToNearestTiesToEven)
1951                          (put_in_reg_sext64 x)))
1952
1953;; Convert $I32X4 to $F32X4 (z15 instruction).
1954(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4)
1955                       (fcvt_from_sint _ x @ (value_type $I32X4))))
1956      (fcvt_from_sint_reg $F32X4 $I32X4 (FpuRoundMode.ToNearestTiesToEven) x))
1957
1958;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14).
1959(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4)
1960                       (fcvt_from_sint _ x @ (value_type $I32X4))))
1961      (vec_permute $F32X4
1962        (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven)
1963          (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision)
1964                              (vec_unpacks_high $I32X4 x)))
1965        (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven)
1966          (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision)
1967                              (vec_unpacks_low $I32X4 x)))
1968        (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27))))
1969
1970;; Convert $I64X2 to $F64X2.
1971(rule (lower (has_type $F64X2 (fcvt_from_sint _ x @ (value_type $I64X2))))
1972      (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ToNearestTiesToEven) x))
1973
1974
1975;;;; Rules for `fcvt_to_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1976
1977;; Convert a scalar floating-point value in a register to an unsigned integer.
1978;; Traps if the input cannot be represented in the output type.
1979(rule (lower (has_type (fits_in_64 dst_ty)
1980                       (fcvt_to_uint _ x @ (value_type src_ty))))
1981      (let ((src Reg (put_in_reg x))
1982            ;; First, check whether the input is a NaN, and trap if so.
1983            (_ Reg (trap_if (fcmp_reg src_ty src src)
1984                            (floatcc_as_cond (FloatCC.Unordered))
1985                            (trap_code_bad_conversion_to_integer)))
1986            ;; Now check whether the input is out of range for the target type.
1987            (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_ub src_ty dst_ty))
1988                            (floatcc_as_cond (FloatCC.GreaterThanOrEqual))
1989                            (trap_code_integer_overflow)))
1990            (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_lb src_ty))
1991                            (floatcc_as_cond (FloatCC.LessThanOrEqual))
1992                            (trap_code_integer_overflow)))
1993            ;; Perform the conversion using the larger type size.
1994            (flt_ty Type (fcvt_flt_ty dst_ty src_ty))
1995            (int_ty Type (fcvt_int_ty dst_ty src_ty))
1996            (src_ext Reg (fpromote_reg flt_ty src_ty src)))
1997        (fcvt_to_uint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext)))
1998
1999
2000;;;; Rules for `fcvt_to_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2001
2002;; Convert a scalar floating-point value in a register to a signed integer.
2003;; Traps if the input cannot be represented in the output type.
2004(rule (lower (has_type (fits_in_64 dst_ty)
2005                       (fcvt_to_sint _ x @ (value_type src_ty))))
2006      (let ((src Reg (put_in_reg x))
2007            ;; First, check whether the input is a NaN, and trap if so.
2008            (_ Reg (trap_if (fcmp_reg src_ty src src)
2009                            (floatcc_as_cond (FloatCC.Unordered))
2010                            (trap_code_bad_conversion_to_integer)))
2011            ;; Now check whether the input is out of range for the target type.
2012            (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_ub src_ty dst_ty))
2013                            (floatcc_as_cond (FloatCC.GreaterThanOrEqual))
2014                            (trap_code_integer_overflow)))
2015            (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_lb src_ty dst_ty))
2016                            (floatcc_as_cond (FloatCC.LessThanOrEqual))
2017                            (trap_code_integer_overflow)))
2018            ;; Perform the conversion using the larger type size.
2019            (flt_ty Type (fcvt_flt_ty dst_ty src_ty))
2020            (int_ty Type (fcvt_int_ty dst_ty src_ty))
2021            (src_ext Reg (fpromote_reg flt_ty src_ty src)))
2022        ;; Perform the conversion.
2023        (fcvt_to_sint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext)))
2024
2025
2026;;;; Rules for `fcvt_to_uint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2027
2028;; Convert a scalar floating-point value in a register to an unsigned integer.
2029(rule -1 (lower (has_type (fits_in_64 dst_ty)
2030                       (fcvt_to_uint_sat _ x @ (value_type src_ty))))
2031      (let ((src Reg (put_in_reg x))
2032            ;; Perform the conversion using the larger type size.
2033            (flt_ty Type (fcvt_flt_ty dst_ty src_ty))
2034            (int_ty Type (fcvt_int_ty dst_ty src_ty))
2035            (src_ext Reg (fpromote_reg flt_ty src_ty src))
2036            (dst Reg (fcvt_to_uint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext)))
2037        ;; Clamp the output to the destination type bounds.
2038        (uint_sat_reg dst_ty int_ty dst)))
2039
2040;; Convert $F32X4 to $I32X4 (z15 instruction).
2041(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4)
2042                       (fcvt_to_uint_sat _ x @ (value_type $F32X4))))
2043      (fcvt_to_uint_reg $I32X4 $F32X4 (FpuRoundMode.ToZero) x))
2044
2045;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14).
2046(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4)
2047                       (fcvt_to_uint_sat _ x @ (value_type $F32X4))))
2048      (vec_pack_usat $I64X2
2049        (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero)
2050          (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 x x)))
2051        (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero)
2052          (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 x x)))))
2053
2054;; Convert $F64X2 to $I64X2.
2055(rule (lower (has_type $I64X2 (fcvt_to_uint_sat _ x @ (value_type $F64X2))))
2056      (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) x))
2057
2058
2059;;;; Rules for `fcvt_to_sint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2060
2061;; Convert a scalar floating-point value in a register to a signed integer.
2062(rule -1 (lower (has_type (fits_in_64 dst_ty)
2063                       (fcvt_to_sint_sat _ x @ (value_type src_ty))))
2064      (let ((src Reg (put_in_reg x))
2065            ;; Perform the conversion using the larger type size.
2066            (flt_ty Type (fcvt_flt_ty dst_ty src_ty))
2067            (int_ty Type (fcvt_int_ty dst_ty src_ty))
2068            (src_ext Reg (fpromote_reg flt_ty src_ty src))
2069            (dst Reg (fcvt_to_sint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext))
2070            ;; In most special cases, the Z instruction already yields the
2071            ;; result expected by Cranelift semantics.  The only exception
2072            ;; it the case where the input was a NaN.  We explicitly check
2073            ;; for that and force the output to 0 in that case.
2074            (sat Reg (with_flags_reg (fcmp_reg src_ty src src)
2075                                     (cmov_imm int_ty
2076                                       (floatcc_as_cond (FloatCC.Unordered)) 0 dst))))
2077        ;; Clamp the output to the destination type bounds.
2078        (sint_sat_reg dst_ty int_ty sat)))
2079
2080;; Convert $F32X4 to $I32X4 (z15 instruction).
2081(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4)
2082                       (fcvt_to_sint_sat _ src @ (value_type $F32X4))))
2083      ;; See above for why we need to handle NaNs specially.
2084      (vec_select $I32X4
2085        (fcvt_to_sint_reg $I32X4 $F32X4 (FpuRoundMode.ToZero) src)
2086        (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src)))
2087
2088;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14).
2089(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4)
2090                       (fcvt_to_sint_sat _ src @ (value_type $F32X4))))
2091      ;; See above for why we need to handle NaNs specially.
2092      (vec_select $I32X4
2093        (vec_pack_ssat $I64X2
2094          (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero)
2095            (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 src src)))
2096          (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero)
2097            (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 src src))))
2098        (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src)))
2099
2100;; Convert $F64X2 to $I64X2.
2101(rule (lower (has_type $I64X2 (fcvt_to_sint_sat _ src @ (value_type $F64X2))))
2102      ;; See above for why we need to handle NaNs specially.
2103      (vec_select $I64X2
2104        (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) src)
2105        (vec_imm $I64X2 0) (vec_fcmpeq $F64X2 src src)))
2106
2107
2108;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2109
2110;; Reinterpret a 64-bit integer value as floating-point.
2111(rule (lower (has_type $F64 (bitcast _ _ x @ (value_type $I64))))
2112      (vec_insert_lane_undef $F64X2 x 0 (zero_reg)))
2113
2114;; Reinterpret a 64-bit floating-point value as integer.
2115(rule (lower (has_type $I64 (bitcast _ _ x @ (value_type $F64))))
2116      (vec_extract_lane $F64X2 x 0 (zero_reg)))
2117
2118;; Reinterpret a 32-bit integer value as floating-point.
2119(rule (lower (has_type $F32 (bitcast _ _ x @ (value_type $I32))))
2120      (vec_insert_lane_undef $F32X4 x 0 (zero_reg)))
2121
2122;; Reinterpret a 32-bit floating-point value as integer.
2123(rule (lower (has_type $I32 (bitcast _ _ x @ (value_type $F32))))
2124      (vec_extract_lane $F32X4 x 0 (zero_reg)))
2125
2126;; Reinterpret a 16-bit integer value as floating-point.
2127(rule (lower (has_type $F16 (bitcast _ _ x @ (value_type $I16))))
2128      (vec_insert_lane_undef $F16X8 x 0 (zero_reg)))
2129
2130;; Reinterpret a 16-bit floating-point value as integer.
2131(rule (lower (has_type $I16 (bitcast _ _ x @ (value_type $F16))))
2132      (vec_extract_lane $F16X8 x 0 (zero_reg)))
2133
2134;; Bitcast between types residing in GPRs is a no-op.
2135(rule 1 (lower (has_type (gpr32_ty _)
2136                         (bitcast _ _ x @ (value_type (gpr32_ty _)))))
2137      x)
2138(rule 2 (lower (has_type (gpr64_ty _)
2139                         (bitcast _ _ x @ (value_type (gpr64_ty _)))))
2140      x)
2141
2142;; Bitcast between types residing in FPRs is a no-op.
2143(rule 3 (lower (has_type (ty_scalar_float _)
2144                         (bitcast _ _ x @ (value_type (ty_scalar_float _)))))
2145      x)
2146
2147;; Bitcast between types residing in VRs is a no-op if lane count is unchanged.
2148(rule 5 (lower (has_type (multi_lane bits count)
2149                         (bitcast _ _ x @ (value_type (multi_lane bits count)))))
2150      x)
2151
2152;; Bitcast between types residing in VRs with different lane counts is a
2153;; no-op if the operation's MemFlags indicate a byte order compatible with
2154;; the current lane order.  Otherwise, lane elements need to be swapped,
2155;; first in the input type, and then again in the output type.  This could
2156;; be optimized further, but we don't bother at the moment since due to our
2157;; choice of lane order depending on the current function ABI, this case will
2158;; currently never arise in practice.
2159(rule 4 (lower (has_type (vr128_ty out_ty)
2160                         (bitcast _ flags x @ (value_type (vr128_ty in_ty)))))
2161      (abi_vec_elt_rev (lane_order_from_memflags flags) out_ty
2162        (abi_vec_elt_rev (lane_order_from_memflags flags) in_ty x)))
2163
2164(decl abi_vec_elt_rev (LaneOrder Type Reg) Reg)
2165(rule 1 (abi_vec_elt_rev callee_lane_order (ty_vec128 ty) reg)
2166      (if-let false (lane_order_equal callee_lane_order (lane_order)))
2167      (vec_elt_rev ty reg))
2168(rule 0 (abi_vec_elt_rev _ _ reg) reg)
2169
2170
2171;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2172
2173;; Insert vector lane from general-purpose register.
2174(rule 1 (lower (insertlane _ x @ (value_type ty)
2175                         y @ (value_type in_ty)
2176                         (u8_from_uimm8 idx)))
2177      (if (ty_int_ref_scalar_64 in_ty))
2178      (vec_insert_lane ty x y (be_lane_idx ty idx) (zero_reg)))
2179
2180;; Insert vector lane from floating-point register.
2181(rule 0 (lower (insertlane _ x @ (value_type ty)
2182                         y @ (value_type (ty_scalar_float _))
2183                         (u8_from_uimm8 idx)))
2184      (vec_move_lane_and_insert ty x (be_lane_idx ty idx) y 0))
2185
2186;; Insert vector lane from another vector lane.
2187(rule 2 (lower (insertlane _ x @ (value_type ty)
2188                         (extractlane _ y (u8_from_uimm8 src_idx))
2189                         (u8_from_uimm8 dst_idx)))
2190      (vec_move_lane_and_insert ty x (be_lane_idx ty dst_idx)
2191                                   y (be_lane_idx ty src_idx)))
2192
2193;; Insert vector lane from signed 16-bit immediate.
2194(rule 3 (lower (insertlane _ x @ (value_type ty) (i16_from_value y)
2195                         (u8_from_uimm8 idx)))
2196      (vec_insert_lane_imm ty x y (be_lane_idx ty idx)))
2197
2198;; Insert vector lane from big-endian memory.
2199(rule 4 (lower (insertlane _ x @ (value_type ty) (sinkable_load y)
2200                         (u8_from_uimm8 idx)))
2201      (vec_load_lane ty x (sink_load y) (be_lane_idx ty idx)))
2202
2203;; Insert vector lane from little-endian memory.
2204(rule 5 (lower (insertlane _ x @ (value_type ty) (sinkable_load_little y)
2205                         (u8_from_uimm8 idx)))
2206      (vec_load_lane_little ty x (sink_load y) (be_lane_idx ty idx)))
2207
2208
2209;; Helper to extract one lane from a vector and insert it into another.
2210(decl vec_move_lane_and_insert (Type Reg u8 Reg u8) Reg)
2211
2212;; For 64-bit elements we always use VPDI.
2213(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 0 src src_idx)
2214      (vec_permute_dw_imm ty src src_idx dst 1))
2215(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 1 src src_idx)
2216      (vec_permute_dw_imm ty dst 0 src src_idx))
2217
2218;; If source and destination index are the same, use vec_select.
2219(rule -1 (vec_move_lane_and_insert ty dst idx src idx)
2220      (vec_select ty src
2221                  dst (vec_imm_byte_mask ty (lane_byte_mask ty idx))))
2222
2223;; Otherwise replicate source first and then use vec_select.
2224(rule -2 (vec_move_lane_and_insert ty dst dst_idx src src_idx)
2225      (vec_select ty (vec_replicate_lane ty src src_idx)
2226                  dst (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx))))
2227
2228
2229;; Helper to implement a generic little-endian variant of vec_load_lane.
2230(decl vec_load_lane_little (Type Reg MemArg u8) Reg)
2231
2232;; 8-byte little-endian loads can be performed via a normal load.
2233(rule (vec_load_lane_little ty @ (multi_lane 8 _) dst addr lane_imm)
2234      (vec_load_lane ty dst addr lane_imm))
2235
2236;; On z15, we have instructions to perform little-endian loads.
2237(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled)
2238                                 ty @ (multi_lane 16 _)) dst addr lane_imm)
2239      (vec_load_lane_rev ty dst addr lane_imm))
2240(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled)
2241                                 ty @ (multi_lane 32 _)) dst addr lane_imm)
2242      (vec_load_lane_rev ty dst addr lane_imm))
2243(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled)
2244                                 ty @ (multi_lane 64 _)) dst addr lane_imm)
2245      (vec_load_lane_rev ty dst addr lane_imm))
2246
2247;; On z14, use a little-endian load to GPR followed by vec_insert_lane.
2248(rule (vec_load_lane_little (and (vxrs_ext2_disabled)
2249                                 ty @ (multi_lane 16 _)) dst addr lane_imm)
2250      (vec_insert_lane ty dst (loadrev16 addr) lane_imm (zero_reg)))
2251(rule (vec_load_lane_little (and (vxrs_ext2_disabled)
2252                                 ty @ (multi_lane 32 _)) dst addr lane_imm)
2253      (vec_insert_lane ty dst (loadrev32 addr) lane_imm (zero_reg)))
2254(rule (vec_load_lane_little (and (vxrs_ext2_disabled)
2255                                 ty @ (multi_lane 64 _)) dst addr lane_imm)
2256      (vec_insert_lane ty dst (loadrev64 addr) lane_imm (zero_reg)))
2257
2258;; Helper to implement a generic little-endian variant of vec_load_lane_undef.
2259(decl vec_load_lane_little_undef (Type MemArg u8) Reg)
2260
2261;; 8-byte little-endian loads can be performed via a normal load.
2262(rule (vec_load_lane_little_undef ty @ (multi_lane 8 _) addr lane_imm)
2263      (vec_load_lane_undef ty addr lane_imm))
2264
2265;; On z15, we have instructions to perform little-endian loads.
2266(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled)
2267                                       ty @ (multi_lane 16 _)) addr lane_imm)
2268      (vec_load_lane_rev_undef ty addr lane_imm))
2269(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled)
2270                                       ty @ (multi_lane 32 _)) addr lane_imm)
2271      (vec_load_lane_rev_undef ty addr lane_imm))
2272(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled)
2273                                       ty @ (multi_lane 64 _)) addr lane_imm)
2274      (vec_load_lane_rev_undef ty addr lane_imm))
2275
2276;; On z14, use a little-endian load to GPR followed by vec_insert_lane_undef.
2277(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled)
2278                                       ty @ (multi_lane 16 _)) addr lane_imm)
2279      (vec_insert_lane_undef ty (loadrev16 addr) lane_imm (zero_reg)))
2280(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled)
2281                                       ty @ (multi_lane 32 _)) addr lane_imm)
2282      (vec_insert_lane_undef ty (loadrev32 addr) lane_imm (zero_reg)))
2283(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled)
2284                                       ty @ (multi_lane 64 _)) addr lane_imm)
2285      (vec_insert_lane_undef ty (loadrev64 addr) lane_imm (zero_reg)))
2286
2287
2288;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2289
2290;; Extract vector lane to general-purpose register.
2291(rule 1 (lower (has_type out_ty
2292                       (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx))))
2293      (if (ty_int_ref_scalar_64 out_ty))
2294      (vec_extract_lane ty x (be_lane_idx ty idx) (zero_reg)))
2295
2296;; Extract vector lane to floating-point register.
2297(rule 0 (lower (has_type (ty_scalar_float _)
2298                       (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx))))
2299      (vec_replicate_lane ty x (be_lane_idx ty idx)))
2300
2301;; Extract vector lane and store to big-endian memory.
2302(rule 6 (lower (store flags @ (bigendian)
2303                    (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx))
2304                    addr offset))
2305      (side_effect (vec_store_lane ty x
2306                     (lower_address flags addr offset) (be_lane_idx ty idx))))
2307
2308;; Extract vector lane and store to little-endian memory.
2309(rule 5 (lower (store flags @ (littleendian)
2310                    (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx))
2311                    addr offset))
2312      (side_effect (vec_store_lane_little ty x
2313                     (lower_address flags addr offset) (be_lane_idx ty idx))))
2314
2315
2316;; Helper to implement a generic little-endian variant of vec_store_lane.
2317(decl vec_store_lane_little (Type Reg MemArg u8) SideEffectNoResult)
2318
2319;; 8-byte little-endian stores can be performed via a normal store.
2320(rule (vec_store_lane_little ty @ (multi_lane 8 _) src addr lane_imm)
2321      (vec_store_lane ty src addr lane_imm))
2322
2323;; On z15, we have instructions to perform little-endian stores.
2324(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled)
2325                                  ty @ (multi_lane 16 _)) src addr lane_imm)
2326      (vec_store_lane_rev ty src addr lane_imm))
2327(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled)
2328                                  ty @ (multi_lane 32 _)) src addr lane_imm)
2329      (vec_store_lane_rev ty src addr lane_imm))
2330(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled)
2331                                  ty @ (multi_lane 64 _)) src addr lane_imm)
2332      (vec_store_lane_rev ty src addr lane_imm))
2333
2334;; On z14, use vec_extract_lane followed by a little-endian store from GPR.
2335(rule (vec_store_lane_little (and (vxrs_ext2_disabled)
2336                                  ty @ (multi_lane 16 _)) src addr lane_imm)
2337      (storerev16 (vec_extract_lane ty src lane_imm (zero_reg)) addr))
2338(rule (vec_store_lane_little (and (vxrs_ext2_disabled)
2339                                  ty @ (multi_lane 32 _)) src addr lane_imm)
2340      (storerev32 (vec_extract_lane ty src lane_imm (zero_reg)) addr))
2341(rule (vec_store_lane_little (and (vxrs_ext2_disabled)
2342                                  ty @ (multi_lane 64 _)) src addr lane_imm)
2343      (storerev64 (vec_extract_lane ty src lane_imm (zero_reg)) addr))
2344
2345
2346;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2347
2348;; Load replicated value from general-purpose register.
2349(rule 1 (lower (has_type ty (splat _ x @ (value_type in_ty))))
2350      (if (ty_int_ref_scalar_64 in_ty))
2351      (vec_replicate_lane ty (vec_insert_lane_undef ty x 0 (zero_reg)) 0))
2352
2353;; Load replicated value from floating-point register.
2354(rule 0 (lower (has_type ty (splat _
2355                             x @ (value_type (ty_scalar_float _)))))
2356      (vec_replicate_lane ty x 0))
2357
2358;; Load replicated value from vector lane.
2359(rule 2 (lower (has_type ty (splat _ (extractlane _ x (u8_from_uimm8 idx)))))
2360      (vec_replicate_lane ty x (be_lane_idx ty idx)))
2361
2362;; Load replicated 16-bit immediate value.
2363(rule 3 (lower (has_type ty (splat _ (i16_from_value x))))
2364      (vec_imm_replicate ty x))
2365
2366;; Load replicated value from big-endian memory.
2367(rule 4 (lower (has_type ty (splat _ (sinkable_load x))))
2368      (vec_load_replicate ty (sink_load x)))
2369
2370;; Load replicated value from little-endian memory.
2371(rule 5 (lower (has_type ty (splat _ (sinkable_load_little x))))
2372      (vec_load_replicate_little ty (sink_load x)))
2373
2374
2375;; Helper to implement a generic little-endian variant of vec_load_replicate
2376(decl vec_load_replicate_little (Type MemArg) Reg)
2377
2378;; 8-byte little-endian loads can be performed via a normal load.
2379(rule (vec_load_replicate_little ty @ (multi_lane 8 _) addr)
2380      (vec_load_replicate ty addr))
2381
2382;; On z15, we have instructions to perform little-endian loads.
2383(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled)
2384                                 ty @ (multi_lane 16 _)) addr)
2385      (vec_load_replicate_rev ty addr))
2386(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled)
2387                                 ty @ (multi_lane 32 _)) addr)
2388      (vec_load_replicate_rev ty addr))
2389(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled)
2390                                 ty @ (multi_lane 64 _)) addr)
2391      (vec_load_replicate_rev ty addr))
2392
2393;; On z14, use a little-endian load (via GPR) and replicate.
2394(rule (vec_load_replicate_little (and (vxrs_ext2_disabled)
2395                                 ty @ (multi_lane 16 _)) addr)
2396      (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0))
2397(rule (vec_load_replicate_little (and (vxrs_ext2_disabled)
2398                                 ty @ (multi_lane 32 _)) addr)
2399      (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0))
2400(rule (vec_load_replicate_little (and (vxrs_ext2_disabled)
2401                                 ty @ (multi_lane 64 _)) addr)
2402      (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0))
2403
2404
2405;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2406
2407;; Load scalar value from general-purpose register.
2408(rule 1 (lower (has_type ty (scalar_to_vector _
2409                             x @ (value_type in_ty))))
2410      (if (ty_int_ref_scalar_64 in_ty))
2411      (vec_insert_lane ty (vec_imm ty 0) x (be_lane_idx ty 0) (zero_reg)))
2412
2413;; Load scalar value from floating-point register.
2414(rule 0 (lower (has_type ty (scalar_to_vector _
2415                             x @ (value_type (ty_scalar_float _)))))
2416      (vec_move_lane_and_zero ty (be_lane_idx ty 0) x 0))
2417
2418;; Load scalar value from vector lane.
2419(rule 2 (lower (has_type ty (scalar_to_vector _
2420                            (extractlane _ x (u8_from_uimm8 idx)))))
2421      (vec_move_lane_and_zero ty (be_lane_idx ty 0) x (be_lane_idx ty idx)))
2422
2423;; Load scalar 16-bit immediate value.
2424(rule 3 (lower (has_type ty (scalar_to_vector _ (i16_from_value x))))
2425      (vec_insert_lane_imm ty (vec_imm ty 0) x (be_lane_idx ty 0)))
2426
2427;; Load scalar value from big-endian memory.
2428(rule 4 (lower (has_type ty (scalar_to_vector _ (sinkable_load x))))
2429      (vec_load_lane ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0)))
2430
2431;; Load scalar value lane from little-endian memory.
2432(rule 5 (lower (has_type ty (scalar_to_vector _ (sinkable_load_little x))))
2433      (vec_load_lane_little ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0)))
2434
2435
2436;; Helper to extract one lane from a vector and insert it into a zero vector.
2437(decl vec_move_lane_and_zero (Type u8 Reg u8) Reg)
2438
2439;; For 64-bit elements we always use VPDI.
2440(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 0 src src_idx)
2441      (vec_permute_dw_imm ty src src_idx (vec_imm ty 0) 0))
2442(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 1 src src_idx)
2443      (vec_permute_dw_imm ty (vec_imm ty 0) 0 src src_idx))
2444
2445;; If source and destination index are the same, simply mask to this lane.
2446(rule -1 (vec_move_lane_and_zero ty idx src idx)
2447      (vec_and ty src
2448               (vec_imm_byte_mask ty (lane_byte_mask ty idx))))
2449
2450;; Otherwise replicate source first and then mask to the lane.
2451(rule -2 (vec_move_lane_and_zero ty dst_idx src src_idx)
2452      (vec_and ty (vec_replicate_lane ty src src_idx)
2453               (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx))))
2454
2455
2456;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2457
2458;; General case: use vec_permute and then mask off zero lanes.
2459(rule -2 (lower (shuffle _ x y (shuffle_mask permute_mask and_mask)))
2460      (vec_and $I8X16 (vec_imm_byte_mask $I8X16 and_mask)
2461               (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask))))
2462
2463;; If the pattern has no zero lanes, just a vec_permute suffices.
2464(rule -1 (lower (shuffle _ x y (shuffle_mask permute_mask 65535)))
2465      (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask)))
2466
2467;; Special patterns that can be implemented via MERGE HIGH.
2468(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23) 65535)))
2469      (vec_merge_high $I64X2 x y))
2470(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 16 17 18 19 4 5 6 7 20 21 22 23) 65535)))
2471      (vec_merge_high $I32X4 x y))
2472(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 16 17 2 3 18 19 4 5 20 21 6 7 22 23) 65535)))
2473      (vec_merge_high $I16X8 x y))
2474(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 16 1 17 2 18 3 19 4 20 5 21 6 22 7 23) 65535)))
2475      (vec_merge_high $I8X16 x y))
2476(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 0 1 2 3 4 5 6 7) 65535)))
2477      (vec_merge_high $I64X2 y x))
2478(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 0 1 2 3 20 21 22 23 4 5 6 7) 65535)))
2479      (vec_merge_high $I32X4 y x))
2480(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 0 1 18 19 2 3 20 21 4 5 22 23 6 7) 65535)))
2481      (vec_merge_high $I16X8 y x))
2482(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 0 17 1 18 2 19 3 20 4 21 5 22 6 23 7) 65535)))
2483      (vec_merge_high $I8X16 y x))
2484(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7) 65535)))
2485      (vec_merge_high $I64X2 x x))
2486(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 0 1 2 3 4 5 6 7 4 5 6 7) 65535)))
2487      (vec_merge_high $I32X4 x x))
2488(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 0 1 2 3 2 3 4 5 4 5 6 7 6 7) 65535)))
2489      (vec_merge_high $I16X8 x x))
2490(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7) 65535)))
2491      (vec_merge_high $I8X16 x x))
2492(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23) 65535)))
2493      (vec_merge_high $I64X2 y y))
2494(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 16 17 18 19 20 21 22 23 20 21 22 23) 65535)))
2495      (vec_merge_high $I32X4 y y))
2496(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 16 17 18 19 18 19 20 21 20 21 22 23 22 23) 65535)))
2497      (vec_merge_high $I16X8 y y))
2498(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23) 65535)))
2499      (vec_merge_high $I8X16 y y))
2500
2501;; Special patterns that can be implemented via MERGE LOW.
2502(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31) 65535)))
2503      (vec_merge_low $I64X2 x y))
2504(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 24 25 26 27 12 13 14 15 28 29 30 31) 65535)))
2505      (vec_merge_low $I32X4 x y))
2506(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 24 25 10 11 26 27 12 13 28 29 14 15 30 31) 65535)))
2507      (vec_merge_low $I16X8 x y))
2508(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 24 9 25 10 26 11 27 12 28 13 29 14 30 15 31) 65535)))
2509      (vec_merge_low $I8X16 x y))
2510(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 8 9 10 11 12 13 14 15) 65535)))
2511      (vec_merge_low $I64X2 y x))
2512(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 8 9 10 11 28 29 30 31 12 13 14 15) 65535)))
2513      (vec_merge_low $I32X4 y x))
2514(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 8 9 26 27 10 11 28 29 12 13 30 31 14 15) 65535)))
2515      (vec_merge_low $I16X8 y x))
2516(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 8 25 9 26 10 27 11 28 12 29 13 30 14 31 15) 65535)))
2517      (vec_merge_low $I8X16 y x))
2518(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15) 65535)))
2519      (vec_merge_low $I64X2 x x))
2520(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 8 9 10 11 12 13 14 15 12 13 14 15) 65535)))
2521      (vec_merge_low $I32X4 x x))
2522(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 8 9 10 11 10 11 12 13 12 13 14 15 14 15) 65535)))
2523      (vec_merge_low $I16X8 x x))
2524(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15) 65535)))
2525      (vec_merge_low $I8X16 x x))
2526(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31) 65535)))
2527      (vec_merge_low $I64X2 y y))
2528(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 24 25 26 27 28 29 30 31 28 29 30 31) 65535)))
2529      (vec_merge_low $I32X4 y y))
2530(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 24 25 26 27 26 27 28 29 28 29 30 31 30 31) 65535)))
2531      (vec_merge_low $I16X8 y y))
2532(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31) 65535)))
2533      (vec_merge_low $I8X16 y y))
2534
2535;; Special patterns that can be implemented via PACK.
2536(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 20 21 22 23 28 29 30 31) 65535)))
2537      (vec_pack $I64X2 x y))
2538(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 18 19 22 23 26 27 30 31) 65535)))
2539      (vec_pack $I32X4 x y))
2540(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31) 65535)))
2541      (vec_pack $I16X8 x y))
2542(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 4 5 6 7 12 13 14 15) 65535)))
2543      (vec_pack $I64X2 y x))
2544(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 2 3 6 7 10 11 14 15) 65535)))
2545      (vec_pack $I32X4 y x))
2546(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 1 3 5 7 9 11 13 15) 65535)))
2547      (vec_pack $I16X8 y x))
2548(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 4 5 6 7 12 13 14 15) 65535)))
2549      (vec_pack $I64X2 x x))
2550(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 2 3 6 7 10 11 14 15) 65535)))
2551      (vec_pack $I32X4 x x))
2552(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 1 3 5 7 9 11 13 15) 65535)))
2553      (vec_pack $I16X8 x x))
2554(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 20 21 22 23 28 29 30 31) 65535)))
2555      (vec_pack $I64X2 y y))
2556(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 18 19 22 23 26 27 30 31) 65535)))
2557      (vec_pack $I32X4 y y))
2558(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 17 19 21 23 25 27 29 31) 65535)))
2559      (vec_pack $I16X8 y y))
2560
2561;; Special patterns that can be implemented via UNPACK HIGH.
2562(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 0 1 2 3 _ _ _ _ 4 5 6 7) 3855)))
2563      (vec_unpacku_high $I32X4 x))
2564(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 0 1 _ _ 2 3 _ _ 4 5 _ _ 6 7) 13107)))
2565      (vec_unpacku_high $I16X8 x))
2566(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 0 _ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7) 21845)))
2567      (vec_unpacku_high $I8X16 x))
2568(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 16 17 18 19 _ _ _ _ 20 21 22 23) 3855)))
2569      (vec_unpacku_high $I32X4 y))
2570(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 16 17 _ _ 18 19 _ _ 20 21 _ _ 22 23) 13107)))
2571      (vec_unpacku_high $I16X8 y))
2572(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 16 _ 17 _ 18 _ 19 _ 20 _ 21 _ 22 _ 23) 21845)))
2573      (vec_unpacku_high $I8X16 y))
2574
2575;; Special patterns that can be implemented via UNPACK LOW.
2576(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 8 9 10 11 _ _ _ _ 12 13 14 15) 3855)))
2577      (vec_unpacku_low $I32X4 x))
2578(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 8 9 _ _ 10 11 _ _ 12 13 _ _ 14 15) 13107)))
2579      (vec_unpacku_low $I16X8 x))
2580(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 8 _ 9 _ 10 _ 11 _ 12 _ 13 _ 14 _ 15) 21845)))
2581      (vec_unpacku_low $I8X16 x))
2582(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 24 25 26 27 _ _ _ _ 28 29 30 31) 3855)))
2583      (vec_unpacku_low $I32X4 y))
2584(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 24 25 _ _ 26 27 _ _ 28 29 _ _ 30 31) 13107)))
2585      (vec_unpacku_low $I16X8 y))
2586(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 24 _ 25 _ 26 _ 27 _ 28 _ 29 _ 30 _ 31) 21845)))
2587      (vec_unpacku_low $I8X16 y))
2588
2589;; Special patterns that can be implemented via PERMUTE DOUBLEWORD IMMEDIATE.
2590(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31) 65535)))
2591      (vec_permute_dw_imm $I8X16 x 0 y 1))
2592(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23) 65535)))
2593      (vec_permute_dw_imm $I8X16 x 1 y 0))
2594(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15) 65535)))
2595      (vec_permute_dw_imm $I8X16 y 0 x 1))
2596(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7) 65535)))
2597      (vec_permute_dw_imm $I8X16 y 1 x 0))
2598(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 65535)))
2599      (vec_permute_dw_imm $I8X16 x 0 x 1))
2600(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7) 65535)))
2601      (vec_permute_dw_imm $I8X16 x 1 x 0))
2602(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) 65535)))
2603      (vec_permute_dw_imm $I8X16 y 0 y 1))
2604(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23) 65535)))
2605      (vec_permute_dw_imm $I8X16 y 1 y 0))
2606
2607;;;; Rules for `blendv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2608
2609(rule 1 (lower (has_type (and (ty_vec128 ty) (vxrs_ext3_enabled)) (blendv _ p x y)))
2610  (vec_blend ty p x y))
2611
2612
2613;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2614
2615;; When using big-endian lane order, the lane mask is mostly correct, but we
2616;; need to handle mask elements outside the range 0..15 by zeroing the lane.
2617;;
2618;; To do so efficiently, we compute:
2619;;     permute-lane-element := umin (16, swizzle-lane-element)
2620;; and pass a zero vector as second operand to the permute instruction.
2621
2622(rule 1 (lower (has_type (ty_vec128 ty) (swizzle _ x y)))
2623      (if-let (LaneOrder.BigEndian) (lane_order))
2624      (vec_permute ty x (vec_imm ty 0)
2625         (vec_umin $I8X16 (vec_imm_splat $I8X16 16) y)))
2626
2627;; When using little-endian lane order, in addition to zeroing (as above),
2628;; we need to convert from little-endian to big-endian lane numbering.
2629;;
2630;; To do so efficiently, we compute:
2631;;     permute-lane-element := umax (239, ~ swizzle-lane-element)
2632;; which has the following effect:
2633;;     elements 0 .. 15 --> 255 .. 240 (i.e. 31 .. 16 mod 32)
2634;;     everything else --> 239 (i.e. 15 mod 32)
2635;;
2636;; Then, we can use a single permute instruction with
2637;;     a zero vector as first operand (covering lane 15)
2638;;     the input vector as second operand (covering lanes 16 .. 31)
2639;; to implement the required swizzle semantics.
2640
2641(rule (lower (has_type (ty_vec128 ty) (swizzle _ x y)))
2642      (if-let (LaneOrder.LittleEndian) (lane_order))
2643      (vec_permute ty (vec_imm ty 0) x
2644         (vec_umax $I8X16 (vec_imm_splat $I8X16 239)
2645           (vec_not $I8X16 y))))
2646
2647
2648;;;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2649
2650;; Load the address of a stack slot.
2651(rule (lower (has_type ty (stack_addr _ stack_slot offset)))
2652      (stack_addr_impl ty stack_slot offset))
2653
2654
2655;;;; Rules for `func_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2656
2657;; Load the address of a function, target reachable via PC-relative instruction.
2658(rule 1 (lower (func_addr _ (func_ref_data _ name (RelocDistance.Near) _)))
2659      (load_addr (memarg_symbol name 0 (memflags_trusted))))
2660
2661;; Load the address of a function, general case.
2662(rule (lower (func_addr _ (func_ref_data _ name _ _)))
2663      (load_symbol_reloc (SymbolReloc.Absolute name 0)))
2664
2665
2666;;;; Rules for `symbol_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2667
2668;; Load the address of a symbol, target reachable via PC-relative instruction.
2669(rule 1 (lower (symbol_value _ (symbol_value_data name (RelocDistance.Near)
2670                                              off)))
2671      (if-let offset (memarg_symbol_offset off))
2672      (load_addr (memarg_symbol name offset (memflags_trusted))))
2673
2674;; Load the address of a symbol, general case.
2675(rule (lower (symbol_value _ (symbol_value_data name _ offset)))
2676      (load_symbol_reloc (SymbolReloc.Absolute name offset)))
2677
2678
2679;;;; Rules for `tls_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2680
2681;; Load the address of a TLS symbol (ELF general-dynamic model).
2682(rule (lower (tls_value _ (symbol_value_data name _ 0)))
2683      (if (tls_model_is_elf_gd))
2684      (let ((symbol SymbolReloc (SymbolReloc.TlsGd name))
2685            (got Reg (load_addr (memarg_got)))
2686            (got_offset Reg (load_symbol_reloc symbol))
2687            (tls_offset Reg (lib_call_tls_get_offset got got_offset symbol)))
2688        (add_reg $I64 tls_offset (thread_pointer))))
2689
2690;; Helper to perform a call to the __tls_get_offset library routine.
2691(decl lib_call_tls_get_offset (Reg Reg SymbolReloc) Reg)
2692(rule (lib_call_tls_get_offset got got_offset symbol)
2693      (let ((tls_offset WritableReg (temp_writable_reg $I64))
2694            (_ Unit (abi_for_elf_tls_get_offset))
2695            (_ Unit (emit (MInst.ElfTlsGetOffset tls_offset got got_offset symbol))))
2696        tls_offset))
2697
2698(decl abi_for_elf_tls_get_offset () Unit)
2699(extern constructor abi_for_elf_tls_get_offset abi_for_elf_tls_get_offset)
2700
2701;; Helper to extract the current thread pointer from %a0/%a1.
2702(decl thread_pointer () Reg)
2703(rule (thread_pointer)
2704      (insert_ar (lshl_imm $I64 (load_ar 0) 32) 1))
2705
2706
2707;;;; Rules for `load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2708
2709;; Load 8-bit integers.
2710(rule (lower (has_type $I8 (load _ flags addr offset)))
2711      (zext32_mem $I8 (lower_address flags addr offset)))
2712
2713;; Load 16-bit big-endian integers.
2714(rule (lower (has_type $I16 (load _ flags @ (bigendian) addr offset)))
2715      (zext32_mem $I16 (lower_address flags addr offset)))
2716
2717;; Load 16-bit little-endian integers.
2718(rule -1 (lower (has_type $I16 (load _ flags @ (littleendian) addr offset)))
2719      (loadrev16 (lower_address flags addr offset)))
2720
2721;; Load 32-bit big-endian integers.
2722(rule (lower (has_type $I32 (load _ flags @ (bigendian) addr offset)))
2723      (load32 (lower_address flags addr offset)))
2724
2725;; Load 32-bit little-endian integers.
2726(rule -1 (lower (has_type $I32 (load _ flags @ (littleendian) addr offset)))
2727      (loadrev32 (lower_address flags addr offset)))
2728
2729;; Load 64-bit big-endian integers.
2730(rule (lower (has_type $I64 (load _ flags @ (bigendian) addr offset)))
2731      (load64 (lower_address flags addr offset)))
2732
2733;; Load 64-bit little-endian integers.
2734(rule -1 (lower (has_type $I64 (load _ flags @ (littleendian) addr offset)))
2735      (loadrev64 (lower_address flags addr offset)))
2736
2737;; Load 16-bit big-endian floating-point values (as vector lane).
2738(rule (lower (has_type $F16 (load _ flags @ (bigendian) addr offset)))
2739      (vec_load_lane_undef $F16X8 (lower_address flags addr offset) 0))
2740
2741;; Load 16-bit little-endian floating-point values (as vector lane).
2742(rule -1 (lower (has_type $F16 (load _ flags @ (littleendian) addr offset)))
2743      (vec_load_lane_little_undef $F16X8 (lower_address flags addr offset) 0))
2744
2745;; Load 32-bit big-endian floating-point values (as vector lane).
2746(rule (lower (has_type $F32 (load _ flags @ (bigendian) addr offset)))
2747      (vec_load_lane_undef $F32X4 (lower_address flags addr offset) 0))
2748
2749;; Load 32-bit little-endian floating-point values (as vector lane).
2750(rule -1 (lower (has_type $F32 (load _ flags @ (littleendian) addr offset)))
2751      (vec_load_lane_little_undef $F32X4 (lower_address flags addr offset) 0))
2752
2753;; Load 64-bit big-endian floating-point values (as vector lane).
2754(rule (lower (has_type $F64 (load _ flags @ (bigendian) addr offset)))
2755      (vec_load_lane_undef $F64X2 (lower_address flags addr offset) 0))
2756
2757;; Load 64-bit little-endian floating-point values (as vector lane).
2758(rule -1 (lower (has_type $F64 (load _ flags @ (littleendian) addr offset)))
2759      (vec_load_lane_little_undef $F64X2 (lower_address flags addr offset) 0))
2760
2761;; Load 128-bit big-endian vector values, BE lane order - direct load.
2762(rule 4 (lower (has_type (vr128_ty ty) (load _ flags @ (bigendian) addr offset)))
2763      (if-let (LaneOrder.BigEndian) (lane_order))
2764      (vec_load ty (lower_address flags addr offset)))
2765
2766;; Load 128-bit little-endian vector values, BE lane order - byte-reversed load.
2767(rule 3 (lower (has_type (vr128_ty ty) (load _ flags @ (littleendian) addr offset)))
2768      (if-let (LaneOrder.BigEndian) (lane_order))
2769      (vec_load_byte_rev ty flags addr offset))
2770
2771;; Load 128-bit big-endian vector values, LE lane order - element-reversed load.
2772(rule 2 (lower (has_type (vr128_ty ty) (load _ flags @ (bigendian) addr offset)))
2773      (if-let (LaneOrder.LittleEndian) (lane_order))
2774      (vec_load_elt_rev ty flags addr offset))
2775
2776;; Load 128-bit little-endian vector values, LE lane order - fully-reversed load.
2777(rule 1 (lower (has_type (vr128_ty ty) (load _ flags @ (littleendian) addr offset)))
2778      (if-let (LaneOrder.LittleEndian) (lane_order))
2779      (vec_load_full_rev ty flags addr offset))
2780
2781
2782;; Helper to perform a 128-bit full-vector byte-reversed load.
2783(decl vec_load_full_rev (Type MemFlags Value Offset32) Reg)
2784
2785;; Full-vector byte-reversed load via single instruction on z15.
2786(rule 1 (vec_load_full_rev (and (vxrs_ext2_enabled) (vr128_ty ty)) flags addr offset)
2787      (vec_loadrev ty (lower_address flags addr offset)))
2788
2789;; Full-vector byte-reversed load via GPRs on z14.
2790(rule (vec_load_full_rev (and (vxrs_ext2_disabled) (vr128_ty ty)) flags addr offset)
2791      (let ((lo_addr MemArg (lower_address_bias flags addr offset 0))
2792            (hi_addr MemArg (lower_address_bias flags addr offset 8))
2793            (lo_val Reg (loadrev64 lo_addr))
2794            (hi_val Reg (loadrev64 hi_addr)))
2795        (mov_to_vec128 ty hi_val lo_val)))
2796
2797
2798;; Helper to perform an element-wise byte-reversed load.
2799(decl vec_load_byte_rev (Type MemFlags Value Offset32) Reg)
2800
2801;; Element-wise byte-reversed 1x128-bit load is a full byte-reversed load.
2802(rule -1 (vec_load_byte_rev $I128 flags addr offset)
2803      (vec_load_full_rev $I128 flags addr offset))
2804
2805;; Same for `f128`.
2806(rule -1 (vec_load_byte_rev $F128 flags addr offset)
2807      (vec_load_full_rev $F128 flags addr offset))
2808
2809;; Element-wise byte-reversed 16x8-bit load is a direct load.
2810(rule (vec_load_byte_rev ty @ (multi_lane 8 16) flags addr offset)
2811      (vec_load ty (lower_address flags addr offset)))
2812
2813;; Element-wise byte-reversed load via single instruction on z15.
2814(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2))
2815                        flags addr offset)
2816      (vec_load_byte64rev ty (lower_address flags addr offset)))
2817(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4))
2818                        flags addr offset)
2819      (vec_load_byte32rev ty (lower_address flags addr offset)))
2820(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8))
2821                        flags addr offset)
2822      (vec_load_byte16rev ty (lower_address flags addr offset)))
2823
2824;; Element-wise byte-reversed load as element-swapped byte-reversed load on z14.
2825(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2))
2826                        flags addr offset)
2827      (vec_elt_rev ty (vec_load_full_rev ty flags addr offset)))
2828(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4))
2829                        flags addr offset)
2830      (vec_elt_rev ty (vec_load_full_rev ty flags addr offset)))
2831(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8))
2832                        flags addr offset)
2833      (vec_elt_rev ty (vec_load_full_rev ty flags addr offset)))
2834
2835
2836;; Helper to perform an element-reversed load.
2837(decl vec_load_elt_rev (Type MemFlags Value Offset32) Reg)
2838
2839;; Element-reversed 1x128-bit load is a direct load.
2840;; For 1x128-bit types, this is a direct load.
2841(rule -1 (vec_load_elt_rev $I128 flags addr offset)
2842      (vec_load $I128 (lower_address flags addr offset)))
2843
2844;; Same for `f128`.
2845(rule -1 (vec_load_elt_rev $F128 flags addr offset)
2846      (vec_load $F128 (lower_address flags addr offset)))
2847
2848;; Element-reversed 16x8-bit load is a full byte-reversed load.
2849(rule (vec_load_elt_rev ty @ (multi_lane 8 16) flags addr offset)
2850      (vec_load_full_rev ty flags addr offset))
2851
2852;; Element-reversed load via single instruction on z15.
2853(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2))
2854                        flags addr offset)
2855      (vec_load_elt64rev ty (lower_address flags addr offset)))
2856(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4))
2857                        flags addr offset)
2858      (vec_load_elt32rev ty (lower_address flags addr offset)))
2859(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8))
2860                        flags addr offset)
2861      (vec_load_elt16rev ty (lower_address flags addr offset)))
2862
2863;; Element-reversed load as element-swapped direct load on z14.
2864(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2))
2865                        flags addr offset)
2866      (vec_elt_rev ty (vec_load ty (lower_address flags addr offset))))
2867(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4))
2868                        flags addr offset)
2869      (vec_elt_rev ty (vec_load ty (lower_address flags addr offset))))
2870(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8))
2871                        flags addr offset)
2872      (vec_elt_rev ty (vec_load ty (lower_address flags addr offset))))
2873
2874
2875;;;; Rules for `uload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2876
2877;; 16- or 32-bit target types.
2878(rule (lower (has_type (gpr32_ty _ty) (uload8 _ flags addr offset)))
2879      (zext32_mem $I8 (lower_address flags addr offset)))
2880
2881;; 64-bit target types.
2882(rule 1 (lower (has_type (gpr64_ty _ty) (uload8 _ flags addr offset)))
2883      (zext64_mem $I8 (lower_address flags addr offset)))
2884
2885
2886;;;; Rules for `sload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2887
2888;; 16- or 32-bit target types.
2889(rule (lower (has_type (gpr32_ty _ty) (sload8 _ flags addr offset)))
2890      (sext32_mem $I8 (lower_address flags addr offset)))
2891
2892;; 64-bit target types.
2893(rule 1 (lower (has_type (gpr64_ty _ty) (sload8 _ flags addr offset)))
2894      (sext64_mem $I8 (lower_address flags addr offset)))
2895
2896
2897;;;; Rules for `uload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2898
2899;; 32-bit target type, big-endian source value.
2900(rule 3 (lower (has_type (gpr32_ty _ty)
2901                       (uload16 _ flags @ (bigendian) addr offset)))
2902      (zext32_mem $I16 (lower_address flags addr offset)))
2903
2904;; 32-bit target type, little-endian source value (via explicit extension).
2905(rule 1 (lower (has_type (gpr32_ty _ty)
2906                       (uload16 _ flags @ (littleendian) addr offset)))
2907      (let ((reg16 Reg (loadrev16 (lower_address flags addr offset))))
2908        (zext32_reg $I16 reg16)))
2909
2910;; 64-bit target type, big-endian source value.
2911(rule 4 (lower (has_type (gpr64_ty _ty)
2912                       (uload16 _ flags @ (bigendian) addr offset)))
2913      (zext64_mem $I16 (lower_address flags addr offset)))
2914
2915;; 64-bit target type, little-endian source value (via explicit extension).
2916(rule 2 (lower (has_type (gpr64_ty _ty)
2917                       (uload16 _ flags @ (littleendian) addr offset)))
2918      (let ((reg16 Reg (loadrev16 (lower_address flags addr offset))))
2919        (zext64_reg $I16 reg16)))
2920
2921
2922;;;; Rules for `sload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2923
2924;; 32-bit target type, big-endian source value.
2925(rule 2 (lower (has_type (gpr32_ty _ty)
2926                       (sload16 _ flags @ (bigendian) addr offset)))
2927      (sext32_mem $I16 (lower_address flags addr offset)))
2928
2929;; 32-bit target type, little-endian source value (via explicit extension).
2930(rule 0 (lower (has_type (gpr32_ty _ty)
2931                       (sload16 _ flags @ (littleendian) addr offset)))
2932      (let ((reg16 Reg (loadrev16 (lower_address flags addr offset))))
2933        (sext32_reg $I16 reg16)))
2934
2935;; 64-bit target type, big-endian source value.
2936(rule 3 (lower (has_type (gpr64_ty _ty)
2937                       (sload16 _ flags @ (bigendian) addr offset)))
2938      (sext64_mem $I16 (lower_address flags addr offset)))
2939
2940;; 64-bit target type, little-endian source value (via explicit extension).
2941(rule 1 (lower (has_type (gpr64_ty _ty)
2942                       (sload16 _ flags @ (littleendian) addr offset)))
2943      (let ((reg16 Reg (loadrev16 (lower_address flags addr offset))))
2944        (sext64_reg $I16 reg16)))
2945
2946
2947;;;; Rules for `uload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2948
2949;; 64-bit target type, big-endian source value.
2950(rule 1 (lower (has_type (gpr64_ty _ty)
2951                       (uload32 _ flags @ (bigendian) addr offset)))
2952      (zext64_mem $I32 (lower_address flags addr offset)))
2953
2954;; 64-bit target type, little-endian source value (via explicit extension).
2955(rule (lower (has_type (gpr64_ty _ty)
2956                       (uload32 _ flags @ (littleendian) addr offset)))
2957      (let ((reg32 Reg (loadrev32 (lower_address flags addr offset))))
2958        (zext64_reg $I32 reg32)))
2959
2960
2961;;;; Rules for `sload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2962
2963;; 64-bit target type, big-endian source value.
2964(rule 1 (lower (has_type (gpr64_ty _ty)
2965                       (sload32 _ flags @ (bigendian) addr offset)))
2966      (sext64_mem $I32 (lower_address flags addr offset)))
2967
2968;; 64-bit target type, little-endian source value (via explicit extension).
2969(rule (lower (has_type (gpr64_ty _ty)
2970                       (sload32 _ flags @ (littleendian) addr offset)))
2971      (let ((reg32 Reg (loadrev32 (lower_address flags addr offset))))
2972        (sext64_reg $I32 reg32)))
2973
2974
2975;;;; Rules for `uloadNxM` and `sloadNxM` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2976
2977;; Unsigned 8->16 bit extension.
2978(rule (lower (has_type $I16X8 (uload8x8 _ flags addr offset)))
2979      (vec_unpacku_high $I8X16 (load_v64 $I8X16 flags addr offset)))
2980
2981;; Signed 8->16 bit extension.
2982(rule (lower (has_type $I16X8 (sload8x8 _ flags addr offset)))
2983      (vec_unpacks_high $I8X16 (load_v64 $I8X16 flags addr offset)))
2984
2985;; Unsigned 16->32 bit extension.
2986(rule (lower (has_type $I32X4 (uload16x4 _ flags addr offset)))
2987      (vec_unpacku_high $I16X8 (load_v64 $I16X8 flags addr offset)))
2988
2989;; Signed 16->32 bit extension.
2990(rule (lower (has_type $I32X4 (sload16x4 _ flags addr offset)))
2991      (vec_unpacks_high $I16X8 (load_v64 $I16X8 flags addr offset)))
2992
2993;; Unsigned 32->64 bit extension.
2994(rule (lower (has_type $I64X2 (uload32x2 _ flags addr offset)))
2995      (vec_unpacku_high $I32X4 (load_v64 $I32X4 flags addr offset)))
2996
2997;; Signed 32->64 bit extension.
2998(rule (lower (has_type $I64X2 (sload32x2 _ flags addr offset)))
2999      (vec_unpacks_high $I32X4 (load_v64 $I32X4 flags addr offset)))
3000
3001
3002;; Helper to load a 64-bit half-size vector from memory.
3003(decl load_v64 (Type MemFlags Value Offset32) Reg)
3004
3005;; Any big-endian source value, BE lane order.
3006(rule -1 (load_v64 _ flags @ (bigendian) addr offset)
3007      (if-let (LaneOrder.BigEndian) (lane_order))
3008      (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0))
3009
3010;; Any little-endian source value, LE lane order.
3011(rule -2 (load_v64 _ flags @ (littleendian) addr offset)
3012      (if-let (LaneOrder.LittleEndian) (lane_order))
3013      (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0))
3014
3015;; Big-endian or little-endian 8x8-bit source value, BE lane order.
3016(rule (load_v64 (multi_lane 8 16) flags addr offset)
3017      (if-let (LaneOrder.BigEndian) (lane_order))
3018      (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0))
3019
3020;; Big-endian or little-endian 8x8-bit source value, LE lane order.
3021(rule 1 (load_v64 (multi_lane 8 16) flags addr offset)
3022      (if-let (LaneOrder.LittleEndian) (lane_order))
3023      (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0))
3024
3025;; Little-endian 4x16-bit source value, BE lane order.
3026(rule (load_v64 (multi_lane 16 8) flags @ (littleendian) addr offset)
3027      (if-let (LaneOrder.BigEndian) (lane_order))
3028      (vec_rot_imm $I16X8
3029        (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 8))
3030
3031;; Big-endian 4x16-bit source value, LE lane order.
3032(rule 1 (load_v64 (multi_lane 16 8) flags @ (bigendian) addr offset)
3033      (if-let (LaneOrder.LittleEndian) (lane_order))
3034      (vec_rot_imm $I16X8
3035        (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 8))
3036
3037;; Little-endian 2x32-bit source value, BE lane order.
3038(rule (load_v64 (multi_lane 32 4) flags @ (littleendian) addr offset)
3039      (if-let (LaneOrder.BigEndian) (lane_order))
3040      (vec_rot_imm $I64X2
3041        (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 32))
3042
3043;; Big-endian 2x32-bit source value, LE lane order.
3044(rule 1 (load_v64 (multi_lane 32 4) flags @ (bigendian) addr offset)
3045      (if-let (LaneOrder.LittleEndian) (lane_order))
3046      (vec_rot_imm $I64X2
3047        (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 32))
3048
3049
3050;;;; Rules for `store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3051
3052;; The actual store logic for integer types is identical for the `store`,
3053;; `istoreNN`, and `atomic_store` instructions, so we share common helpers.
3054
3055;; Store 8-bit integer type, main lowering entry point.
3056(rule (lower (store flags val @ (value_type $I8) addr offset))
3057      (side_effect (istore8_impl flags val addr offset)))
3058
3059;; Store 16-bit integer type, main lowering entry point.
3060(rule (lower (store flags val @ (value_type $I16) addr offset))
3061      (side_effect (istore16_impl flags val addr offset)))
3062
3063;; Store 32-bit integer type, main lowering entry point.
3064(rule (lower (store flags val @ (value_type $I32) addr offset))
3065      (side_effect (istore32_impl flags val addr offset)))
3066
3067;; Store 64-bit integer type, main lowering entry point.
3068(rule (lower (store flags val @ (value_type $I64) addr offset))
3069      (side_effect (istore64_impl flags val addr offset)))
3070
3071;; Store 16-bit big-endian floating-point type (as vector lane).
3072(rule -1 (lower (store flags @ (bigendian)
3073                    val @ (value_type $F16) addr offset))
3074      (side_effect (vec_store_lane $F16X8 val
3075                                   (lower_address flags addr offset) 0)))
3076
3077;; Store 16-bit little-endian floating-point type (as vector lane).
3078(rule (lower (store flags @ (littleendian)
3079                    val @ (value_type $F16) addr offset))
3080      (side_effect (vec_store_lane_little $F16X8 val
3081                                          (lower_address flags addr offset) 0)))
3082
3083;; Store 32-bit big-endian floating-point type (as vector lane).
3084(rule -1 (lower (store flags @ (bigendian)
3085                    val @ (value_type $F32) addr offset))
3086      (side_effect (vec_store_lane $F32X4 val
3087                                   (lower_address flags addr offset) 0)))
3088
3089;; Store 32-bit little-endian floating-point type (as vector lane).
3090(rule (lower (store flags @ (littleendian)
3091                    val @ (value_type $F32) addr offset))
3092      (side_effect (vec_store_lane_little $F32X4 val
3093                                          (lower_address flags addr offset) 0)))
3094
3095;; Store 64-bit big-endian floating-point type (as vector lane).
3096(rule -1 (lower (store flags @ (bigendian)
3097                    val @ (value_type $F64) addr offset))
3098      (side_effect (vec_store_lane $F64X2 val
3099                                   (lower_address flags addr offset) 0)))
3100
3101;; Store 64-bit little-endian floating-point type (as vector lane).
3102(rule (lower (store flags @ (littleendian)
3103                    val @ (value_type $F64) addr offset))
3104      (side_effect (vec_store_lane_little $F64X2 val
3105                                          (lower_address flags addr offset) 0)))
3106
3107;; Store 128-bit big-endian vector type, BE lane order - direct store.
3108(rule 4 (lower (store flags @ (bigendian)
3109                    val @ (value_type (vr128_ty ty)) addr offset))
3110      (if-let (LaneOrder.BigEndian) (lane_order))
3111      (side_effect (vec_store val (lower_address flags addr offset))))
3112
3113;; Store 128-bit little-endian vector type, BE lane order - byte-reversed store.
3114(rule 3 (lower (store flags @ (littleendian)
3115                    val @ (value_type (vr128_ty ty)) addr offset))
3116      (if-let (LaneOrder.BigEndian) (lane_order))
3117      (side_effect (vec_store_byte_rev ty val flags addr offset)))
3118
3119;; Store 128-bit big-endian vector type, LE lane order - element-reversed store.
3120(rule 2 (lower (store flags @ (bigendian)
3121                    val @ (value_type (vr128_ty ty)) addr offset))
3122      (if-let (LaneOrder.LittleEndian) (lane_order))
3123      (side_effect (vec_store_elt_rev ty val flags addr offset)))
3124
3125;; Store 128-bit little-endian vector type, LE lane order - fully-reversed store.
3126(rule 1 (lower (store flags @ (littleendian)
3127                    val @ (value_type (vr128_ty ty)) addr offset))
3128      (if-let (LaneOrder.LittleEndian) (lane_order))
3129      (side_effect (vec_store_full_rev ty val flags addr offset)))
3130
3131
3132;; Helper to perform a 128-bit full-vector byte-reversed store.
3133(decl vec_store_full_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult)
3134
3135;; Full-vector byte-reversed store via single instruction on z15.
3136(rule 1 (vec_store_full_rev (vxrs_ext2_enabled) val flags addr offset)
3137      (vec_storerev val (lower_address flags addr offset)))
3138
3139;; Full-vector byte-reversed store via GPRs on z14.
3140(rule (vec_store_full_rev (vxrs_ext2_disabled) val flags addr offset)
3141      (let ((lo_addr MemArg (lower_address_bias flags addr offset 0))
3142            (hi_addr MemArg (lower_address_bias flags addr offset 8))
3143            (lo_val Reg (vec_extract_lane $I64X2 val 1 (zero_reg)))
3144            (hi_val Reg (vec_extract_lane $I64X2 val 0 (zero_reg))))
3145        (side_effect_concat (storerev64 lo_val lo_addr)
3146                            (storerev64 hi_val hi_addr))))
3147
3148
3149;; Helper to perform an element-wise byte-reversed store.
3150(decl vec_store_byte_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult)
3151
3152;; Element-wise byte-reversed 1x128-bit store is a full byte-reversed store.
3153(rule -1 (vec_store_byte_rev $I128 val flags addr offset)
3154      (vec_store_full_rev $I128 val flags addr offset))
3155
3156;; Same for `f128`.
3157(rule -1 (vec_store_byte_rev $F128 val flags addr offset)
3158      (vec_store_full_rev $F128 val flags addr offset))
3159
3160;; Element-wise byte-reversed 16x8-bit store is a direct store.
3161(rule (vec_store_byte_rev (multi_lane 8 16) val flags addr offset)
3162      (vec_store val (lower_address flags addr offset)))
3163
3164;; Element-wise byte-reversed store via single instruction on z15.
3165(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2))
3166                          val flags addr offset)
3167      (vec_store_byte64rev val (lower_address flags addr offset)))
3168(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4))
3169                          val flags addr offset)
3170      (vec_store_byte32rev val (lower_address flags addr offset)))
3171(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8))
3172                          val flags addr offset)
3173      (vec_store_byte16rev val (lower_address flags addr offset)))
3174
3175;; Element-wise byte-reversed load as element-swapped byte-reversed store on z14.
3176(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2))
3177                          val flags addr offset)
3178      (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset))
3179(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4))
3180                          val flags addr offset)
3181      (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset))
3182(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8))
3183                          val flags addr offset)
3184      (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset))
3185
3186
3187;; Helper to perform an element-reversed store.
3188(decl vec_store_elt_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult)
3189
3190;; Element-reversed 1x128-bit store is a direct store.
3191(rule -1 (vec_store_elt_rev $I128 val flags addr offset)
3192      (vec_store val (lower_address flags addr offset)))
3193
3194;; Same for `f128`.
3195(rule -1 (vec_store_elt_rev $F128 val flags addr offset)
3196      (vec_store val (lower_address flags addr offset)))
3197
3198;; Element-reversed 16x8-bit store is a full byte-reversed store.
3199(rule (vec_store_elt_rev ty @ (multi_lane 8 16) val flags addr offset)
3200      (vec_store_full_rev ty val flags addr offset))
3201
3202;; Element-reversed store via single instruction on z15.
3203(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2))
3204                         val flags addr offset)
3205      (vec_store_elt64rev val (lower_address flags addr offset)))
3206(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4))
3207                         val flags addr offset)
3208      (vec_store_elt32rev val (lower_address flags addr offset)))
3209(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8))
3210                         val flags addr offset)
3211      (vec_store_elt16rev val (lower_address flags addr offset)))
3212
3213;; Element-reversed store as element-swapped direct store on z14.
3214(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2))
3215                         val flags addr offset)
3216      (vec_store (vec_elt_rev ty val) (lower_address flags addr offset)))
3217(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4))
3218                         val flags addr offset)
3219      (vec_store (vec_elt_rev ty val) (lower_address flags addr offset)))
3220(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8))
3221                         val flags addr offset)
3222      (vec_store (vec_elt_rev ty val) (lower_address flags addr offset)))
3223
3224
3225;;;; Rules for 8-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3226
3227;; Main `istore8` lowering entry point, dispatching to the helper.
3228(rule (lower (istore8 flags val addr offset))
3229      (side_effect (istore8_impl flags val addr offset)))
3230
3231;; Helper to store 8-bit integer types.
3232(decl istore8_impl (MemFlags Value Value Offset32) SideEffectNoResult)
3233
3234;; Store 8-bit integer types, register input.
3235(rule (istore8_impl flags val addr offset)
3236      (store8 (put_in_reg val) (lower_address flags addr offset)))
3237
3238;; Store 8-bit integer types, immediate input.
3239(rule 1 (istore8_impl flags (u8_from_value imm) addr offset)
3240      (store8_imm imm (lower_address flags addr offset)))
3241
3242
3243;;;; Rules for 16-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3244
3245;; Main `istore16` lowering entry point, dispatching to the helper.
3246(rule (lower (istore16 flags val addr offset))
3247      (side_effect (istore16_impl flags val addr offset)))
3248
3249;; Helper to store 16-bit integer types.
3250(decl istore16_impl (MemFlags Value Value Offset32) SideEffectNoResult)
3251
3252;; Store 16-bit big-endian integer types, register input.
3253(rule 2 (istore16_impl flags @ (bigendian) val addr offset)
3254      (store16 (put_in_reg val) (lower_address flags addr offset)))
3255
3256;; Store 16-bit little-endian integer types, register input.
3257(rule 0 (istore16_impl flags @ (littleendian) val addr offset)
3258      (storerev16 (put_in_reg val) (lower_address flags addr offset)))
3259
3260;; Store 16-bit big-endian integer types, immediate input.
3261(rule 3 (istore16_impl flags @ (bigendian) (i16_from_value imm) addr offset)
3262      (store16_imm imm (lower_address flags addr offset)))
3263
3264;; Store 16-bit little-endian integer types, immediate input.
3265(rule 1 (istore16_impl flags @ (littleendian) (i16_from_swapped_value imm) addr offset)
3266      (store16_imm imm (lower_address flags addr offset)))
3267
3268
3269;;;; Rules for 32-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3270
3271;; Main `istore32` lowering entry point, dispatching to the helper.
3272(rule (lower (istore32 flags val addr offset))
3273      (side_effect (istore32_impl flags val addr offset)))
3274
3275;; Helper to store 32-bit integer types.
3276(decl istore32_impl (MemFlags Value Value Offset32) SideEffectNoResult)
3277
3278;; Store 32-bit big-endian integer types, register input.
3279(rule 1 (istore32_impl flags @ (bigendian) val addr offset)
3280      (store32 (put_in_reg val) (lower_address flags addr offset)))
3281
3282;; Store 32-bit big-endian integer types, immediate input.
3283(rule 2 (istore32_impl flags @ (bigendian) (i16_from_value imm) addr offset)
3284      (store32_simm16 imm (lower_address flags addr offset)))
3285
3286;; Store 32-bit little-endian integer types.
3287(rule 0 (istore32_impl flags @ (littleendian) val addr offset)
3288      (storerev32 (put_in_reg val) (lower_address flags addr offset)))
3289
3290
3291;;;; Rules for 64-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3292
3293;; Helper to store 64-bit integer types.
3294(decl istore64_impl (MemFlags Value Value Offset32) SideEffectNoResult)
3295
3296;; Store 64-bit big-endian integer types, register input.
3297(rule 1 (istore64_impl flags @ (bigendian) val addr offset)
3298      (store64 (put_in_reg val) (lower_address flags addr offset)))
3299
3300;; Store 64-bit big-endian integer types, immediate input.
3301(rule 2 (istore64_impl flags @ (bigendian) (i16_from_value imm) addr offset)
3302      (store64_simm16 imm (lower_address flags addr offset)))
3303
3304;; Store 64-bit little-endian integer types.
3305(rule 0 (istore64_impl flags @ (littleendian) val addr offset)
3306      (storerev64 (put_in_reg val) (lower_address flags addr offset)))
3307
3308
3309;;;; Rules for `atomic_rmw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3310
3311;; Atomic operations that do not require a compare-and-swap loop.
3312
3313;; Atomic AND for 32/64-bit big-endian types, using a single instruction.
3314(rule 1 (lower (has_type (ty_32_or_64 ty)
3315                (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.And) addr src)))
3316      (atomic_rmw_and ty (put_in_reg src)
3317                      (lower_address flags addr (zero_offset))))
3318
3319;; Atomic AND for 32/64-bit big-endian types, using byte-swapped input/output.
3320(rule (lower (has_type (ty_32_or_64 ty)
3321               (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.And) addr src)))
3322      (bswap_reg ty (atomic_rmw_and ty (bswap_reg ty (put_in_reg src))
3323                                    (lower_address flags addr (zero_offset)))))
3324
3325;; Atomic OR for 32/64-bit big-endian types, using a single instruction.
3326(rule 1 (lower (has_type (ty_32_or_64 ty)
3327               (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Or) addr src)))
3328      (atomic_rmw_or ty (put_in_reg src)
3329                     (lower_address flags addr (zero_offset))))
3330
3331;; Atomic OR for 32/64-bit little-endian types, using byte-swapped input/output.
3332(rule (lower (has_type (ty_32_or_64 ty)
3333               (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.Or) addr src)))
3334      (bswap_reg ty (atomic_rmw_or ty (bswap_reg ty (put_in_reg src))
3335                                   (lower_address flags addr (zero_offset)))))
3336
3337;; Atomic XOR for 32/64-bit big-endian types, using a single instruction.
3338(rule 1 (lower (has_type (ty_32_or_64 ty)
3339               (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Xor) addr src)))
3340      (atomic_rmw_xor ty (put_in_reg src)
3341                      (lower_address flags addr (zero_offset))))
3342
3343;; Atomic XOR for 32/64-bit little-endian types, using byte-swapped input/output.
3344(rule (lower (has_type (ty_32_or_64 ty)
3345               (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.Xor) addr src)))
3346      (bswap_reg ty (atomic_rmw_xor ty (bswap_reg ty (put_in_reg src))
3347                                    (lower_address flags addr (zero_offset)))))
3348
3349;; Atomic ADD for 32/64-bit big-endian types, using a single instruction.
3350(rule (lower (has_type (ty_32_or_64 ty)
3351               (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Add) addr src)))
3352      (atomic_rmw_add ty (put_in_reg src)
3353                      (lower_address flags addr (zero_offset))))
3354
3355;; Atomic SUB for 32/64-bit big-endian types, using atomic ADD with negated input.
3356(rule (lower (has_type (ty_32_or_64 ty)
3357               (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Sub) addr src)))
3358      (atomic_rmw_add ty (neg_reg ty (put_in_reg src))
3359                      (lower_address flags addr (zero_offset))))
3360
3361
3362;; Atomic operations that require a compare-and-swap loop.
3363
3364;; Operations for 32/64-bit types can use a fullword compare-and-swap loop.
3365(rule -1 (lower (has_type (ty_32_or_64 ty) (atomic_rmw _ flags op addr src)))
3366      (let ((src_reg Reg (put_in_reg src))
3367            (addr_reg Reg (put_in_reg addr))
3368            ;; Create body of compare-and-swap loop.
3369            (ib VecMInstBuilder (inst_builder_new))
3370            (val0 Reg (writable_reg_to_reg (casloop_val_reg)))
3371            (val1 Reg (atomic_rmw_body ib ty flags op
3372                        (casloop_tmp_reg) val0 src_reg)))
3373        ;; Emit compare-and-swap loop and extract final result.
3374        (casloop ib ty flags addr_reg val1)))
3375
3376;; Operations for 8/16-bit types must operate on the surrounding aligned word.
3377(rule -2 (lower (has_type (ty_8_or_16 ty) (atomic_rmw _ flags op addr src)))
3378      (let ((src_reg Reg (put_in_reg src))
3379            (addr_reg Reg (put_in_reg addr))
3380            ;; Prepare access to surrounding aligned word.
3381            (bitshift Reg (casloop_bitshift addr_reg))
3382            (aligned_addr Reg (casloop_aligned_addr addr_reg))
3383            ;; Create body of compare-and-swap loop.
3384            (ib VecMInstBuilder (inst_builder_new))
3385            (val0 Reg (writable_reg_to_reg (casloop_val_reg)))
3386            (val1 Reg (casloop_rotate_in ib ty flags bitshift val0))
3387            (val2 Reg (atomic_rmw_body ib ty flags op
3388                        (casloop_tmp_reg) val1 src_reg))
3389            (val3 Reg (casloop_rotate_out ib ty flags bitshift val2)))
3390        ;; Emit compare-and-swap loop and extract final result.
3391        (casloop_subword ib ty flags aligned_addr bitshift val3)))
3392
3393;; Loop bodies for atomic read-modify-write operations.
3394(decl atomic_rmw_body (VecMInstBuilder Type MemFlags AtomicRmwOp
3395                       WritableReg Reg Reg) Reg)
3396
3397;; Loop bodies for 32-/64-bit atomic XCHG operations.
3398;; Simply use the source (possibly byte-swapped) as new target value.
3399(rule 2 (atomic_rmw_body ib (ty_32_or_64 ty) (bigendian)
3400                       (AtomicRmwOp.Xchg) tmp val src)
3401      src)
3402(rule 1 (atomic_rmw_body ib (ty_32_or_64 ty) (littleendian)
3403                       (AtomicRmwOp.Xchg) tmp val src)
3404      (bswap_reg ty src))
3405
3406;; Loop bodies for 32-/64-bit atomic NAND operations.
3407;; On z15 this can use the NN(G)RK instruction.  On z14, perform an And
3408;; operation and invert the result.  In the little-endian case, we can
3409;; simply byte-swap the source operand.
3410(rule 4 (atomic_rmw_body ib (and (mie3_enabled) (ty_32_or_64 ty)) (bigendian)
3411                       (AtomicRmwOp.Nand) tmp val src)
3412      (push_alu_reg ib (aluop_not_and ty) tmp val src))
3413(rule 3 (atomic_rmw_body ib (and (mie3_enabled) (ty_32_or_64 ty)) (littleendian)
3414                       (AtomicRmwOp.Nand) tmp val src)
3415      (push_alu_reg ib (aluop_not_and ty) tmp val (bswap_reg ty src)))
3416(rule 2 (atomic_rmw_body ib (and (mie3_disabled) (ty_32_or_64 ty)) (bigendian)
3417                       (AtomicRmwOp.Nand) tmp val src)
3418      (push_not_reg ib ty tmp
3419        (push_alu_reg ib (aluop_and ty) tmp val src)))
3420(rule 1 (atomic_rmw_body ib (and (mie3_disabled) (ty_32_or_64 ty)) (littleendian)
3421                       (AtomicRmwOp.Nand) tmp val src)
3422      (push_not_reg ib ty tmp
3423        (push_alu_reg ib (aluop_and ty) tmp val (bswap_reg ty src))))
3424
3425;; Loop bodies for 8-/16-bit atomic bit operations.
3426;; These use the "rotate-then-<op>-selected bits" family of instructions.
3427;; For the Nand operation, we again perform And and invert the result.
3428(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xchg) tmp val src)
3429      (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Insert) tmp val src))
3430(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.And) tmp val src)
3431      (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src))
3432(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Or) tmp val src)
3433      (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Or) tmp val src))
3434(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xor) tmp val src)
3435      (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Xor) tmp val src))
3436(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Nand) tmp val src)
3437      (atomic_rmw_body_invert ib ty flags tmp
3438        (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src)))
3439
3440;; RxSBG subword operation.
3441(decl atomic_rmw_body_rxsbg (VecMInstBuilder Type MemFlags RxSBGOp
3442                             WritableReg Reg Reg) Reg)
3443;; 8-bit case: use the low byte of "src" and the high byte of "val".
3444(rule (atomic_rmw_body_rxsbg ib $I8 _ op tmp val src)
3445      (push_rxsbg ib op tmp val src 32 40 24))
3446;; 16-bit big-endian case: use the low two bytes of "src" and the
3447;; high two bytes of "val".
3448(rule 1 (atomic_rmw_body_rxsbg ib $I16 (bigendian) op tmp val src)
3449      (push_rxsbg ib op tmp val src 32 48 16))
3450;; 16-bit little-endian case: use the low two bytes of "src", byte-swapped
3451;; so they end up in the high two bytes, and the low two bytes of "val".
3452(rule (atomic_rmw_body_rxsbg ib $I16 (littleendian) op tmp val src)
3453      (push_rxsbg ib op tmp val (bswap_reg $I32 src) 48 64 -16))
3454
3455;; Invert a subword.
3456(decl atomic_rmw_body_invert (VecMInstBuilder Type MemFlags WritableReg Reg) Reg)
3457;; 8-bit case: invert the high byte.
3458(rule (atomic_rmw_body_invert ib $I8 _ tmp val)
3459      (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xff000000 0)))
3460;; 16-bit big-endian case: invert the two high bytes.
3461(rule 1 (atomic_rmw_body_invert ib $I16 (bigendian) tmp val)
3462      (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff0000 0)))
3463;; 16-bit little-endian case: invert the two low bytes.
3464(rule (atomic_rmw_body_invert ib $I16 (littleendian) tmp val)
3465      (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff 0)))
3466
3467;; Loop bodies for atomic ADD/SUB operations.
3468(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Add) tmp val src)
3469      (atomic_rmw_body_addsub ib ty flags (aluop_add (ty_ext32 ty)) tmp val src))
3470(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Sub) tmp val src)
3471      (atomic_rmw_body_addsub ib ty flags (aluop_sub (ty_ext32 ty)) tmp val src))
3472
3473;; Addition or subtraction operation.
3474(decl atomic_rmw_body_addsub (VecMInstBuilder Type MemFlags ALUOp
3475                              WritableReg Reg Reg) Reg)
3476;; 32/64-bit big-endian case: just a regular add/sub operation.
3477(rule 2 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (bigendian) op tmp val src)
3478      (push_alu_reg ib op tmp val src))
3479;; 32/64-bit little-endian case: byte-swap the value loaded from memory before
3480;; and after performing the operation in native endianness.
3481(rule 1 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (littleendian) op tmp val src)
3482      (let ((val_swapped Reg (push_bswap_reg ib ty tmp val))
3483            (res_swapped Reg (push_alu_reg ib op tmp val_swapped src)))
3484        (push_bswap_reg ib ty tmp res_swapped)))
3485;; 8-bit case: perform a 32-bit addition of the source value shifted by 24 bits
3486;; to the memory value, which contains the target in its high byte.
3487(rule (atomic_rmw_body_addsub ib $I8 _ op tmp val src)
3488      (let ((src_shifted Reg (lshl_imm $I32 src 24)))
3489        (push_alu_reg ib op tmp val src_shifted)))
3490;; 16-bit big-endian case: similar, just shift the source by 16 bits.
3491(rule 3 (atomic_rmw_body_addsub ib $I16 (bigendian) op tmp val src)
3492      (let ((src_shifted Reg (lshl_imm $I32 src 16)))
3493        (push_alu_reg ib op tmp val src_shifted)))
3494;; 16-bit little-endian case: the same, but in addition we need to byte-swap
3495;; the memory value before and after the operation.  Since the value was placed
3496;; in the low two bytes by our standard rotation, we can use a 32-bit byte-swap
3497;; and the native-endian value will end up in the high bytes where we need it
3498;; to perform the operation.
3499(rule (atomic_rmw_body_addsub ib $I16 (littleendian) op tmp val src)
3500      (let ((src_shifted Reg (lshl_imm $I32 src 16))
3501            (val_swapped Reg (push_bswap_reg ib $I32 tmp val))
3502            (res_swapped Reg (push_alu_reg ib op tmp val_swapped src_shifted)))
3503        (push_bswap_reg ib $I32 tmp res_swapped)))
3504
3505;; Loop bodies for atomic MIN/MAX operations.
3506(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smin) tmp val src)
3507      (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty))
3508        (intcc_as_cond (IntCC.SignedLessThan)) tmp val src))
3509(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smax) tmp val src)
3510      (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty))
3511        (intcc_as_cond (IntCC.SignedGreaterThan)) tmp val src))
3512(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umin) tmp val src)
3513      (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty))
3514        (intcc_as_cond (IntCC.UnsignedLessThan)) tmp val src))
3515(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umax) tmp val src)
3516      (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty))
3517        (intcc_as_cond (IntCC.UnsignedGreaterThan)) tmp val src))
3518
3519;; Minimum or maximum operation.
3520(decl atomic_rmw_body_minmax (VecMInstBuilder Type MemFlags CmpOp Cond
3521                              WritableReg Reg Reg) Reg)
3522;; 32/64-bit big-endian case: just a comparison followed by a conditional
3523;; break out of the loop if the memory value does not need to change.
3524;; If it does need to change, the new value is simply the source operand.
3525(rule 2 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (bigendian)
3526                              op cond tmp val src)
3527      (let ((_ Reg (push_break_if ib (cmp_rr op src val) (invert_cond cond))))
3528        src))
3529;; 32/64-bit little-endian case: similar, but we need to byte-swap the
3530;; memory value before the comparison.  If we need to store the new value,
3531;; it also needs to be byte-swapped.
3532(rule 1 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (littleendian)
3533                              op cond tmp val src)
3534      (let ((val_swapped Reg (push_bswap_reg ib ty tmp val))
3535            (_ Reg (push_break_if ib (cmp_rr op src val_swapped)
3536                                     (invert_cond cond))))
3537        (push_bswap_reg ib ty tmp src)))
3538;; 8-bit case: compare the memory value (which contains the target in the
3539;; high byte) with the source operand shifted by 24 bits.  Note that in
3540;; the case where the high bytes are equal, the comparison may succeed
3541;; or fail depending on the unrelated low bits of the memory value, and
3542;; so we either may or may not perform the update.  But it would be an
3543;; update with the same value in any case, so this does not matter.
3544(rule (atomic_rmw_body_minmax ib $I8 _ op cond tmp val src)
3545      (let ((src_shifted Reg (lshl_imm $I32 src 24))
3546            (_ Reg (push_break_if ib (cmp_rr op src_shifted val)
3547                                     (invert_cond cond))))
3548        (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 40 0)))
3549;; 16-bit big-endian case: similar, just shift the source by 16 bits.
3550(rule 3 (atomic_rmw_body_minmax ib $I16 (bigendian) op cond tmp val src)
3551      (let ((src_shifted Reg (lshl_imm $I32 src 16))
3552            (_ Reg (push_break_if ib (cmp_rr op src_shifted val)
3553                                     (invert_cond cond))))
3554        (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 48 0)))
3555;; 16-bit little-endian case: similar, but in addition byte-swap the
3556;; memory value before and after the operation, like for _addsub_.
3557(rule (atomic_rmw_body_minmax ib $I16 (littleendian) op cond tmp val src)
3558      (let ((src_shifted Reg (lshl_imm $I32 src 16))
3559            (val_swapped Reg (push_bswap_reg ib $I32 tmp val))
3560            (_ Reg (push_break_if ib (cmp_rr op src_shifted val_swapped)
3561                                     (invert_cond cond)))
3562            (res_swapped Reg (push_rxsbg ib (RxSBGOp.Insert)
3563                                tmp val_swapped src_shifted 32 48 0)))
3564        (push_bswap_reg ib $I32 tmp res_swapped)))
3565
3566
3567;;;; Rules for `atomic_cas` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3568
3569;; 32/64-bit big-endian atomic compare-and-swap instruction.
3570(rule 2 (lower (has_type (ty_32_or_64 ty)
3571               (atomic_cas _ flags @ (bigendian) addr src1 src2)))
3572      (atomic_cas_impl ty (put_in_reg src1) (put_in_reg src2)
3573                       (lower_address flags addr (zero_offset))))
3574
3575;; 32/64-bit little-endian atomic compare-and-swap instruction.
3576;; Implemented by byte-swapping old/new inputs and the output.
3577(rule 1 (lower (has_type (ty_32_or_64 ty)
3578               (atomic_cas _ flags @ (littleendian) addr src1 src2)))
3579      (bswap_reg ty (atomic_cas_impl ty (bswap_reg ty (put_in_reg src1))
3580                                     (bswap_reg ty (put_in_reg src2))
3581                                     (lower_address flags addr (zero_offset)))))
3582
3583;; 8/16-bit atomic compare-and-swap implemented via loop.
3584(rule (lower (has_type (ty_8_or_16 ty) (atomic_cas _ flags addr src1 src2)))
3585      (let ((src1_reg Reg (put_in_reg src1))
3586            (src2_reg Reg (put_in_reg src2))
3587            (addr_reg Reg (put_in_reg addr))
3588            ;; Prepare access to the surrounding aligned word.
3589            (bitshift Reg (casloop_bitshift addr_reg))
3590            (aligned_addr Reg (casloop_aligned_addr addr_reg))
3591            ;; Create body of compare-and-swap loop.
3592            (ib VecMInstBuilder (inst_builder_new))
3593            (val0 Reg (writable_reg_to_reg (casloop_val_reg)))
3594            (val1 Reg (casloop_rotate_in ib ty flags bitshift val0))
3595            (val2 Reg (atomic_cas_body ib ty flags
3596                        (casloop_tmp_reg) val1 src1_reg src2_reg))
3597            (val3 Reg (casloop_rotate_out ib ty flags bitshift val2)))
3598        ;; Emit compare-and-swap loop and extract final result.
3599        (casloop_subword ib ty flags aligned_addr bitshift val3)))
3600
3601;; Emit loop body instructions to perform a subword compare-and-swap.
3602(decl atomic_cas_body (VecMInstBuilder Type MemFlags
3603                       WritableReg Reg Reg Reg) Reg)
3604
3605;; 8-bit case: "val" contains the value loaded from memory in the high byte.
3606;; Compare with the comparison value in the low byte of "src1".  If unequal,
3607;; break out of the loop, otherwise replace the target byte in "val" with
3608;; the low byte of "src2".
3609(rule (atomic_cas_body ib $I8 _ tmp val src1 src2)
3610      (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 40 24)
3611                                     (intcc_as_cond (IntCC.NotEqual)))))
3612        (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 40 24)))
3613
3614;; 16-bit big-endian case: Same as above, except with values in the high
3615;; two bytes of "val" and low two bytes of "src1" and "src2".
3616(rule 1 (atomic_cas_body ib $I16 (bigendian) tmp val src1 src2)
3617      (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 48 16)
3618                                     (intcc_as_cond (IntCC.NotEqual)))))
3619        (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 48 16)))
3620
3621;; 16-bit little-endian case: "val" here contains a little-endian value in the
3622;; *low* two bytes.  "src1" and "src2" contain native (i.e. big-endian) values
3623;; in their low two bytes.  Perform the operation in little-endian mode by
3624;; byte-swapping "src1" and "src" ahead of the loop.  Note that this is a
3625;; 32-bit operation so the little-endian 16-bit values end up in the *high*
3626;; two bytes of the swapped values.
3627(rule (atomic_cas_body ib $I16 (littleendian) tmp val src1 src2)
3628      (let ((src1_swapped Reg (bswap_reg $I32 src1))
3629            (src2_swapped Reg (bswap_reg $I32 src2))
3630            (_ Reg (push_break_if ib
3631                     (rxsbg_test (RxSBGOp.Xor) val src1_swapped 48 64 -16)
3632                     (intcc_as_cond (IntCC.NotEqual)))))
3633        (push_rxsbg ib (RxSBGOp.Insert) tmp val src2_swapped 48 64 -16)))
3634
3635
3636;;;; Rules for `atomic_load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3637
3638;; Atomic loads can be implemented via regular loads on this platform.
3639
3640;; 8-bit atomic load.
3641(rule (lower (has_type $I8 (atomic_load _ flags addr)))
3642      (zext32_mem $I8 (lower_address flags addr (zero_offset))))
3643
3644;; 16-bit big-endian atomic load.
3645(rule 1 (lower (has_type $I16 (atomic_load _ flags @ (bigendian) addr)))
3646      (zext32_mem $I16 (lower_address flags addr (zero_offset))))
3647
3648;; 16-bit little-endian atomic load.
3649(rule (lower (has_type $I16 (atomic_load _ flags @ (littleendian) addr)))
3650      (loadrev16 (lower_address flags addr (zero_offset))))
3651
3652;; 32-bit big-endian atomic load.
3653(rule 1 (lower (has_type $I32 (atomic_load _ flags @ (bigendian) addr)))
3654      (load32 (lower_address flags addr (zero_offset))))
3655
3656;; 32-bit little-endian atomic load.
3657(rule (lower (has_type $I32 (atomic_load _ flags @ (littleendian) addr)))
3658      (loadrev32 (lower_address flags addr (zero_offset))))
3659
3660;; 64-bit big-endian atomic load.
3661(rule 1 (lower (has_type $I64 (atomic_load _ flags @ (bigendian) addr)))
3662      (load64 (lower_address flags addr (zero_offset))))
3663
3664;; 64-bit little-endian atomic load.
3665(rule (lower (has_type $I64 (atomic_load _ flags @ (littleendian) addr)))
3666      (loadrev64 (lower_address flags addr (zero_offset))))
3667
3668
3669;;;; Rules for `atomic_store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3670
3671;; Atomic stores can be implemented via regular stores followed by a fence.
3672(decl atomic_store_impl (SideEffectNoResult) InstOutput)
3673(rule (atomic_store_impl store)
3674      (let ((_ InstOutput (side_effect store)))
3675         (side_effect (fence_impl))))
3676
3677;; 8-bit atomic store.
3678(rule (lower (atomic_store flags val @ (value_type $I8) addr))
3679      (atomic_store_impl (istore8_impl flags val addr (zero_offset))))
3680
3681;; 16-bit atomic store.
3682(rule (lower (atomic_store flags val @ (value_type $I16) addr))
3683      (atomic_store_impl (istore16_impl flags val addr (zero_offset))))
3684
3685;; 32-bit atomic store.
3686(rule (lower (atomic_store flags val @ (value_type $I32) addr))
3687      (atomic_store_impl (istore32_impl flags val addr (zero_offset))))
3688
3689;; 64-bit atomic store.
3690(rule (lower (atomic_store flags val @ (value_type $I64) addr))
3691      (atomic_store_impl (istore64_impl flags val addr (zero_offset))))
3692
3693
3694;;;; Rules for `fence` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3695
3696;; Fence to ensure sequential consistency.
3697(rule (lower (fence))
3698      (side_effect (fence_impl)))
3699
3700
3701;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3702
3703;; We want to optimize the typical use of `icmp` (generating an integer 0/1
3704;; result) followed by some user, like a `select` or a conditional branch.
3705;; Instead of first generating the integer result and later testing it again,
3706;; we want to sink the comparison to be performed at the site of use.
3707;;
3708;; To enable this, we provide generic helpers that return a `ProducesBool`
3709;; encapsulating the comparison in question, which can be used by all the
3710;; above scenarios.
3711;;
3712;; N.B. There are specific considerations when sinking a memory load into a
3713;; comparison.  When emitting an `icmp` directly, this can of course be done
3714;; as usual.  However, when we use the `ProducesBool` elsewhere, we need to
3715;; consider *three* instructions: the load, the `icmp`, and the final user
3716;; (e.g. a conditional branch).  The only way to safely sink the load would
3717;; be to sink it direct into the final user, which is only possible if there
3718;; is no *other* user of the `icmp` result.  This is not currently being
3719;; verified by the `SinkableInst` logic, so to be safe we do not perform this
3720;; optimization at all.
3721;;
3722;; The generic `icmp_val` helper therefore has a flag indicating whether
3723;; it is being invoked in a context where it is safe to sink memory loads
3724;; (e.g. when directly emitting an `icmp`), or whether it is not (e.g. when
3725;; sinking the `icmp` result into a conditional branch or select).
3726
3727;; Main `icmp` entry point.  Generate a `ProducesBool` capturing the
3728;; integer comparison and immediately lower it to a 0/1 integer result.
3729;; In this case, it is safe to sink memory loads.
3730(rule -1 (lower (has_type (fits_in_64 ty) (icmp _ int_cc x y)))
3731      (lower_bool ty (icmp_val true int_cc x y)))
3732
3733
3734;; Return a `ProducesBool` to implement any integer comparison.
3735;; The first argument is a flag to indicate whether it is safe to sink
3736;; memory loads as discussed above.
3737(decl icmp_val (bool IntCC Value Value) ProducesBool)
3738
3739;; Dispatch for signed comparisons.
3740(rule -1 (icmp_val allow_mem int_cc @ (signed) x @ (value_type (fits_in_64 _)) y)
3741      (bool (icmps_val allow_mem x y) (intcc_as_cond int_cc)))
3742;; Dispatch for unsigned comparisons.
3743(rule -2 (icmp_val allow_mem int_cc @ (unsigned) x @ (value_type (fits_in_64 _)) y)
3744      (bool (icmpu_val allow_mem x y) (intcc_as_cond int_cc)))
3745
3746
3747;; Return a `ProducesBool` to implement signed integer comparisons.
3748(decl icmps_val (bool Value Value) ProducesFlags)
3749
3750;; Compare (signed) two registers.
3751(rule 0 (icmps_val _ x @ (value_type (fits_in_64 ty)) y)
3752      (icmps_reg (ty_ext32 ty) (put_in_reg_sext32 x) (put_in_reg_sext32 y)))
3753
3754;; Compare (signed) a register and a sign-extended register.
3755(rule 3 (icmps_val _ x @ (value_type (fits_in_64 ty)) (sext32_value y))
3756      (icmps_reg_sext32 ty x y))
3757
3758;; Compare (signed) a register and an immediate.
3759(rule 2 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i16_from_value y))
3760      (icmps_simm16 (ty_ext32 ty) (put_in_reg_sext32 x) y))
3761(rule 1 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i32_from_value y))
3762      (icmps_simm32 (ty_ext32 ty) (put_in_reg_sext32 x) y))
3763
3764;; Compare (signed) a register and memory (32/64-bit types).
3765(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y))
3766      (icmps_mem ty x (sink_load y)))
3767
3768;; Compare (signed) a register and memory (16-bit types).
3769(rule 5 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_16 y))
3770      (icmps_mem_sext16 (ty_ext32 ty) (put_in_reg_sext32 x) (sink_load y)))
3771
3772;; Compare (signed) a register and sign-extended memory.
3773(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload16 y))
3774      (icmps_mem_sext16 ty x (sink_sload16 y)))
3775(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload32 y))
3776      (icmps_mem_sext32 ty x (sink_sload32 y)))
3777
3778
3779;; Return a `ProducesBool` to implement unsigned integer comparisons.
3780(decl icmpu_val (bool Value Value) ProducesFlags)
3781
3782;; Compare (unsigned) two registers.
3783(rule (icmpu_val _ x @ (value_type (fits_in_64 ty)) y)
3784      (icmpu_reg (ty_ext32 ty) (put_in_reg_zext32 x) (put_in_reg_zext32 y)))
3785
3786;; Compare (unsigned) a register and a sign-extended register.
3787(rule 1 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (zext32_value y))
3788      (icmpu_reg_zext32 ty x y))
3789
3790;; Compare (unsigned) a register and an immediate.
3791(rule 2 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (u32_from_value y))
3792      (icmpu_uimm32 (ty_ext32 ty) (put_in_reg_zext32 x) y))
3793
3794;; Compare (unsigned) a register and memory (32/64-bit types).
3795(rule 4 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y))
3796      (icmpu_mem ty x (sink_load y)))
3797
3798;; Compare (unsigned) a register and memory (16-bit types).
3799;; Note that the ISA only provides instructions with a PC-relative memory
3800;; address here, so we need to check whether the sinkable load matches this.
3801(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty))
3802                 (sinkable_load_16 ld))
3803      (if-let y (load_sym ld))
3804      (icmpu_mem_zext16 (ty_ext32 ty) (put_in_reg_zext32 x) (sink_load y)))
3805
3806;; Compare (unsigned) a register and zero-extended memory.
3807;; Note that the ISA only provides instructions with a PC-relative memory
3808;; address here, so we need to check whether the sinkable load matches this.
3809(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty))
3810                 (sinkable_uload16 ld))
3811      (if-let y (uload16_sym ld))
3812      (icmpu_mem_zext16 ty x (sink_uload16 y)))
3813(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_uload32 y))
3814      (icmpu_mem_zext32 ty x (sink_uload32 y)))
3815
3816
3817;; Compare (signed) 128-bit integers on z17.
3818(rule 2 (icmp_val _ int_cc @ (signed) x @ (value_type (and (vxrs_ext3_enabled) (vr128_ty _))) y)
3819        (bool (vec_elt_icmps x y) (intcc_as_cond int_cc)))
3820
3821;; Compare (unsigned) 128-bit integers on z17.
3822(rule 1 (icmp_val _ int_cc @ (unsigned) x @ (value_type (and (vxrs_ext3_enabled) (vr128_ty _))) y)
3823        (bool (vec_elt_icmpu x y) (intcc_as_cond int_cc)))
3824
3825;; Compare 128-bit integers for equality pre-z17.
3826;; Implemented via element-wise comparison using the all-element true CC flag.
3827(rule (icmp_val _ (IntCC.Equal) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty _))) y)
3828      (bool (vec_cmpeqs $I64X2 x y)
3829            (floatcc_as_cond (FloatCC.Equal))))
3830(rule (icmp_val _ (IntCC.NotEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty _))) y)
3831      (bool (vec_cmpeqs $I64X2 x y)
3832            (floatcc_as_cond (FloatCC.NotEqual))))
3833
3834;; Compare (signed) 128-bit integers for relational inequality pre-z17.
3835;; Implemented via synthetic instruction using VECG and VCHLGS.
3836(rule (icmp_val _ (IntCC.SignedGreaterThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3837      (vec_int128_scmphi x y))
3838(rule (icmp_val _ (IntCC.SignedLessThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3839      (vec_int128_scmphi y x))
3840(rule (icmp_val _ (IntCC.SignedGreaterThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3841      (invert_bool (vec_int128_scmphi y x)))
3842(rule (icmp_val _ (IntCC.SignedLessThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3843      (invert_bool (vec_int128_scmphi x y)))
3844
3845;; Compare (unsigned) 128-bit integers for relational inequality pre-z17.
3846;; Implemented via synthetic instruction using VECLG and VCHLGS.
3847(rule (icmp_val _ (IntCC.UnsignedGreaterThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3848      (vec_int128_ucmphi x y))
3849(rule (icmp_val _ (IntCC.UnsignedLessThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3850      (vec_int128_ucmphi y x))
3851(rule (icmp_val _ (IntCC.UnsignedGreaterThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3852      (invert_bool (vec_int128_ucmphi y x)))
3853(rule (icmp_val _ (IntCC.UnsignedLessThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y)
3854      (invert_bool (vec_int128_ucmphi x y)))
3855
3856
3857;; Vector `icmp` produces a boolean vector.
3858;; We need to handle the various IntCC flags separately here.
3859
3860(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.Equal) x y)))
3861      (vec_cmpeq ty x y))
3862(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.NotEqual) x y)))
3863      (vec_not ty (vec_cmpeq ty x y)))
3864(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedGreaterThan) x y)))
3865      (vec_cmph ty x y))
3866(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedLessThanOrEqual) x y)))
3867      (vec_not ty (vec_cmph ty x y)))
3868(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedLessThan) x y)))
3869      (vec_cmph ty y x))
3870(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedGreaterThanOrEqual) x y)))
3871      (vec_not ty (vec_cmph ty y x)))
3872(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedGreaterThan) x y)))
3873      (vec_cmphl ty x y))
3874(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedLessThanOrEqual) x y)))
3875      (vec_not ty (vec_cmphl ty x y)))
3876(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedLessThan) x y)))
3877      (vec_cmphl ty y x))
3878(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y)))
3879      (vec_not ty (vec_cmphl ty y x)))
3880
3881
3882;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3883
3884;; Main `fcmp` entry point.  Generate a `ProducesBool` capturing the
3885;; integer comparison and immediately lower it to a 0/1 integer result.
3886(rule -1 (lower (has_type (fits_in_64 ty) (fcmp _ float_cc x y)))
3887      (lower_bool ty (fcmp_val float_cc x y)))
3888
3889;; Return a `ProducesBool` to implement any floating-point comparison.
3890(decl fcmp_val (FloatCC Value Value) ProducesBool)
3891(rule (fcmp_val float_cc x @ (value_type ty) y)
3892      (bool (fcmp_reg ty x y)
3893            (floatcc_as_cond float_cc)))
3894
3895;; Vector `fcmp` produces a boolean vector.
3896;; We need to handle the various FloatCC flags separately here.
3897
3898(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Equal) x y)))
3899      (vec_fcmpeq ty x y))
3900(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.NotEqual) x y)))
3901      (vec_not ty (vec_fcmpeq ty x y)))
3902(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.GreaterThan) x y)))
3903      (vec_fcmph ty x y))
3904(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y)))
3905      (vec_not ty (vec_fcmph ty x y)))
3906(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.GreaterThanOrEqual) x y)))
3907      (vec_fcmphe ty x y))
3908(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrLessThan) x y)))
3909      (vec_not ty (vec_fcmphe ty x y)))
3910(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.LessThan) x y)))
3911      (vec_fcmph ty y x))
3912(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y)))
3913      (vec_not ty (vec_fcmph ty y x)))
3914(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.LessThanOrEqual) x y)))
3915      (vec_fcmphe ty y x))
3916(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y)))
3917      (vec_not ty (vec_fcmphe ty y x)))
3918(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Ordered) x y)))
3919      (vec_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x)))
3920(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Unordered) x y)))
3921      (vec_not_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x)))
3922(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.OrderedNotEqual) x y)))
3923      (vec_or ty (vec_fcmph ty x y) (vec_fcmph ty y x)))
3924(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrEqual) x y)))
3925      (vec_not_or ty (vec_fcmph ty x y) (vec_fcmph ty y x)))
3926
3927
3928;;;; Rules for `vall_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3929
3930;; Main `vall_true` entry point.  Generate a `ProducesBool` capturing the
3931;; comparison and immediately lower it to a 0/1 integer result.
3932(rule (lower (has_type (fits_in_64 ty) (vall_true _ x)))
3933      (lower_bool ty (vall_true_val x)))
3934
3935;; Return a `ProducesBool` to implement `vall_true`.
3936(decl vall_true_val (Value) ProducesBool)
3937(rule -1 (vall_true_val x @ (value_type ty))
3938      (bool (vec_cmpeqs ty x (vec_imm ty 0))
3939            (floatcc_as_cond (FloatCC.Unordered))))
3940
3941;; Short-circuit `vall_true` on the result of a `icmp`.
3942(rule (vall_true_val (has_type ty (icmp _ (IntCC.Equal) x y)))
3943      (bool (vec_cmpeqs ty x y)
3944            (floatcc_as_cond (FloatCC.Equal))))
3945(rule (vall_true_val (has_type ty (icmp _ (IntCC.NotEqual) x y)))
3946      (bool (vec_cmpeqs ty x y)
3947            (floatcc_as_cond (FloatCC.Unordered))))
3948(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThan) x y)))
3949      (bool (vec_cmphs ty x y)
3950            (floatcc_as_cond (FloatCC.Equal))))
3951(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedLessThanOrEqual) x y)))
3952      (bool (vec_cmphs ty x y)
3953            (floatcc_as_cond (FloatCC.Unordered))))
3954(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedLessThan) x y)))
3955      (bool (vec_cmphs ty y x)
3956            (floatcc_as_cond (FloatCC.Equal))))
3957(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThanOrEqual) x y)))
3958      (bool (vec_cmphs ty y x)
3959            (floatcc_as_cond (FloatCC.Unordered))))
3960(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThan) x y)))
3961      (bool (vec_cmphls ty x y)
3962            (floatcc_as_cond (FloatCC.Equal))))
3963(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThanOrEqual) x y)))
3964      (bool (vec_cmphls ty x y)
3965            (floatcc_as_cond (FloatCC.Unordered))))
3966(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThan) x y)))
3967      (bool (vec_cmphls ty y x)
3968            (floatcc_as_cond (FloatCC.Equal))))
3969(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y)))
3970      (bool (vec_cmphls ty y x)
3971            (floatcc_as_cond (FloatCC.Unordered))))
3972
3973;; Short-circuit `vall_true` on the result of a `fcmp` where possible.
3974(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.Equal) x y)))
3975      (bool (vec_fcmpeqs ty x y)
3976            (floatcc_as_cond (FloatCC.Equal))))
3977(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.NotEqual) x y)))
3978      (bool (vec_fcmpeqs ty x y)
3979            (floatcc_as_cond (FloatCC.Unordered))))
3980(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.GreaterThan) x y)))
3981      (bool (vec_fcmphs ty x y)
3982            (floatcc_as_cond (FloatCC.Equal))))
3983(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y)))
3984      (bool (vec_fcmphs ty x y)
3985            (floatcc_as_cond (FloatCC.Unordered))))
3986(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.GreaterThanOrEqual) x y)))
3987      (bool (vec_fcmphes ty x y)
3988            (floatcc_as_cond (FloatCC.Equal))))
3989(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThan) x y)))
3990      (bool (vec_fcmphes ty x y)
3991            (floatcc_as_cond (FloatCC.Unordered))))
3992(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.LessThan) x y)))
3993      (bool (vec_fcmphs ty y x)
3994            (floatcc_as_cond (FloatCC.Equal))))
3995(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y)))
3996      (bool (vec_fcmphs ty y x)
3997            (floatcc_as_cond (FloatCC.Unordered))))
3998(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.LessThanOrEqual) x y)))
3999      (bool (vec_fcmphes ty y x)
4000            (floatcc_as_cond (FloatCC.Equal))))
4001(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y)))
4002      (bool (vec_fcmphes ty y x)
4003            (floatcc_as_cond (FloatCC.Unordered))))
4004
4005
4006;;;; Rules for `vany_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4007
4008;; Main `vany_true` entry point.  Generate a `ProducesBool` capturing the
4009;; comparison and immediately lower it to a 0/1 integer result.
4010(rule (lower (has_type (fits_in_64 ty) (vany_true _ x)))
4011      (lower_bool ty (vany_true_val x)))
4012
4013;; Return a `ProducesBool` to implement `vany_true`.
4014(decl vany_true_val (Value) ProducesBool)
4015(rule -1 (vany_true_val x @ (value_type ty))
4016      (bool (vec_cmpeqs ty x (vec_imm ty 0))
4017            (floatcc_as_cond (FloatCC.NotEqual))))
4018
4019;; Short-circuit `vany_true` on the result of a `icmp`.
4020(rule (vany_true_val (has_type ty (icmp _ (IntCC.Equal) x y)))
4021      (bool (vec_cmpeqs ty x y)
4022            (floatcc_as_cond (FloatCC.Ordered))))
4023(rule (vany_true_val (has_type ty (icmp _ (IntCC.NotEqual) x y)))
4024      (bool (vec_cmpeqs ty x y)
4025            (floatcc_as_cond (FloatCC.NotEqual))))
4026(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThan) x y)))
4027      (bool (vec_cmphs ty x y)
4028            (floatcc_as_cond (FloatCC.Ordered))))
4029(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedLessThanOrEqual) x y)))
4030      (bool (vec_cmphs ty x y)
4031            (floatcc_as_cond (FloatCC.NotEqual))))
4032(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedLessThan) x y)))
4033      (bool (vec_cmphs ty y x)
4034            (floatcc_as_cond (FloatCC.Ordered))))
4035(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThanOrEqual) x y)))
4036      (bool (vec_cmphs ty y x)
4037            (floatcc_as_cond (FloatCC.NotEqual))))
4038(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThan) x y)))
4039      (bool (vec_cmphls ty x y)
4040            (floatcc_as_cond (FloatCC.Ordered))))
4041(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThanOrEqual) x y)))
4042      (bool (vec_cmphls ty x y)
4043            (floatcc_as_cond (FloatCC.NotEqual))))
4044(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThan) x y)))
4045      (bool (vec_cmphls ty y x)
4046            (floatcc_as_cond (FloatCC.Ordered))))
4047(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y)))
4048      (bool (vec_cmphls ty y x)
4049            (floatcc_as_cond (FloatCC.NotEqual))))
4050
4051;; Short-circuit `vany_true` on the result of a `fcmp` where possible.
4052(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.Equal) x y)))
4053      (bool (vec_fcmpeqs ty x y)
4054            (floatcc_as_cond (FloatCC.Ordered))))
4055(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.NotEqual) x y)))
4056      (bool (vec_fcmpeqs ty x y)
4057            (floatcc_as_cond (FloatCC.NotEqual))))
4058(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.GreaterThan) x y)))
4059      (bool (vec_fcmphs ty x y)
4060            (floatcc_as_cond (FloatCC.Ordered))))
4061(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y)))
4062      (bool (vec_fcmphs ty x y)
4063            (floatcc_as_cond (FloatCC.NotEqual))))
4064(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.GreaterThanOrEqual) x y)))
4065      (bool (vec_fcmphes ty x y)
4066            (floatcc_as_cond (FloatCC.Ordered))))
4067(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThan) x y)))
4068      (bool (vec_fcmphes ty x y)
4069            (floatcc_as_cond (FloatCC.NotEqual))))
4070(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.LessThan) x y)))
4071      (bool (vec_fcmphs ty y x)
4072            (floatcc_as_cond (FloatCC.Ordered))))
4073(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y)))
4074      (bool (vec_fcmphs ty y x)
4075            (floatcc_as_cond (FloatCC.NotEqual))))
4076(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.LessThanOrEqual) x y)))
4077      (bool (vec_fcmphes ty y x)
4078            (floatcc_as_cond (FloatCC.Ordered))))
4079(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y)))
4080      (bool (vec_fcmphes ty y x)
4081            (floatcc_as_cond (FloatCC.NotEqual))))
4082
4083
4084;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4085
4086(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 8 16))))
4087      (if-let (LaneOrder.LittleEndian) (lane_order))
4088      (let ((mask Reg (vec_imm $I8X16 (imm8x16 0 8 16 24 32 40 48 56
4089                                               64 72 80 88 96 104 112 120))))
4090        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4091(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 8 16))))
4092      (if-let (LaneOrder.BigEndian) (lane_order))
4093      (let ((mask Reg (vec_imm $I8X16 (imm8x16 120 112 104 96 88 80 72 64
4094                                               56 48 40 32 24 16 8 0))))
4095        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4096
4097(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 16 8))))
4098      (if-let (LaneOrder.LittleEndian) (lane_order))
4099      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4100                                               0 16 32 48 64 80 96 112))))
4101        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4102(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 16 8))))
4103      (if-let (LaneOrder.BigEndian) (lane_order))
4104      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4105                                               112 96 80 64 48 32 16 0))))
4106        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4107
4108(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 32 4))))
4109      (if-let (LaneOrder.LittleEndian) (lane_order))
4110      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4111                                               128 128 128 128 0 32 64 96))))
4112        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4113(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 32 4))))
4114      (if-let (LaneOrder.BigEndian) (lane_order))
4115      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4116                                               128 128 128 128 96 64 32 0))))
4117        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4118
4119(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 64 2))))
4120      (if-let (LaneOrder.LittleEndian) (lane_order))
4121      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4122                                               128 128 128 128 128 128 0 64))))
4123        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4124(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 64 2))))
4125      (if-let (LaneOrder.BigEndian) (lane_order))
4126      (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128
4127                                               128 128 128 128 128 128 64 0))))
4128        (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg))))
4129
4130
4131;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4132
4133;; Return a `ProducesBool` to capture the fact that the input value is nonzero.
4134;; In the common case where that input is the result of an `icmp` or `fcmp`
4135;; instruction, directly use that compare. Note that it is not safe to sink
4136;; memory loads here, see the `icmp` comment.
4137(decl value_nonzero (Value) ProducesBool)
4138(rule (value_nonzero (icmp _ int_cc x y)) (icmp_val false int_cc x y))
4139(rule (value_nonzero (fcmp _ float_cc x y)) (fcmp_val float_cc x y))
4140(rule -1 (value_nonzero val @ (value_type (gpr32_ty ty)))
4141      (bool (icmps_simm16 $I32 (put_in_reg_sext32 val) 0)
4142                          (intcc_as_cond (IntCC.NotEqual))))
4143(rule -2 (value_nonzero val @ (value_type (gpr64_ty ty)))
4144      (bool (icmps_simm16 $I64 (put_in_reg val) 0)
4145                          (intcc_as_cond (IntCC.NotEqual))))
4146(rule -3 (value_nonzero val @ (value_type (vr128_ty ty)))
4147      (bool (vec_cmpeqs $I64X2 val (vec_imm $I64X2 0))
4148            (floatcc_as_cond (FloatCC.NotEqual))))
4149
4150;; Main `select` entry point.  Lower the `value_nonzero` result.
4151(rule (lower (has_type ty (select _ val_cond val_true val_false)))
4152      (select_bool_reg ty (value_nonzero val_cond)
4153                       (put_in_reg val_true) (put_in_reg val_false)))
4154
4155;; Special-case some float-selection instructions for min/max
4156(rule 1 (lower (has_type (ty_scalar_float ty) (select _ (maybe_uextend (fcmp _ (FloatCC.LessThan) x y)) x y)))
4157        (fmin_pseudo_reg ty y x))
4158(rule 2 (lower (has_type (ty_scalar_float ty) (select _ (maybe_uextend (fcmp _ (FloatCC.LessThan) y x)) x y)))
4159        (fmax_pseudo_reg ty y x))
4160
4161
4162;;;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4163
4164;; We need to guarantee a conditional move instruction.  But on this platform
4165;; this is already the best way to implement select in general, so the
4166;; implementation of `select_spectre_guard` is identical to `select`.
4167(rule (lower (has_type ty (select_spectre_guard _
4168                             val_cond val_true val_false)))
4169      (select_bool_reg ty (value_nonzero val_cond)
4170                       (put_in_reg val_true) (put_in_reg val_false)))
4171
4172
4173;;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4174
4175;; Unconditional branch.  The target is found as first (and only) element in
4176;; the list of the current block's branch targets passed as `targets`.
4177(rule (lower_branch (jump _) (single_target label))
4178      (emit_side_effect (jump_impl label)))
4179
4180
4181;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4182
4183;; Jump table.  `targets` contains the default target followed by the
4184;; list of branch targets per index value.
4185(rule (lower_branch (br_table val_idx _) (jump_table_targets default targets))
4186      (let ((idx Reg (put_in_reg_zext64 val_idx))
4187            ;; Bounds-check the index and create a ProducesBool that
4188            ;; denotes the "default target" condition.
4189            (cond ProducesBool
4190              (bool (icmpu_uimm32 $I64 idx (jump_table_size targets))
4191                    (intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual)))))
4192        ;; Scale the index by the element size, and then emit the
4193        ;; compound instruction that does:
4194        ;;
4195        ;; [cond branch to default]
4196        ;; larl %r1, <jt-base>
4197        ;; agf %r1, 0(%r1, %rScaledIndex)
4198        ;; br %r1
4199        ;; [jt entries]
4200        ;;
4201        ;; This must be *one* instruction in the vcode because
4202        ;; we cannot allow regalloc to insert any spills/fills
4203        ;; in the middle of the sequence; otherwise, the LARL's
4204        ;; PC-rel offset to the jumptable would be incorrect.
4205        ;; (The alternative is to introduce a relocation pass
4206        ;; for inlined jumptables, which is much worse, IMHO.)
4207        (let ((shifted_idx Reg (lshl_imm $I64 idx 2)))
4208          (emit_side_effect (jt_sequence_default_bool shifted_idx default cond targets)))))
4209
4210
4211;;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4212
4213;; Two-way conditional branch on nonzero.  `targets` contains:
4214;; - element 0: target if the condition is true (i.e. value is nonzero)
4215;; - element 1: target if the condition is false (i.e. value is zero)
4216(rule (lower_branch (brif val_cond _ _) (two_targets then else))
4217      (emit_side_effect (cond_br_bool (value_nonzero val_cond) then else)))
4218
4219
4220;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4221
4222(rule (lower (trap trap_code))
4223      (side_effect (trap_impl trap_code)))
4224
4225
4226;;;; Rules for `trapz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4227
4228(rule (lower (trapz val trap_code))
4229      (side_effect (trap_if_bool (invert_bool (value_nonzero val)) trap_code)))
4230
4231
4232;;;; Rules for `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4233
4234(rule (lower (trapnz val trap_code))
4235      (side_effect (trap_if_bool (value_nonzero val) trap_code)))
4236
4237
4238;;;; Rules for `debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4239
4240(rule (lower (debugtrap))
4241      (side_effect (debugtrap_impl)))
4242
4243;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4244
4245;; UaddOverflowTrap is implemented via a ADD LOGICAL instruction, which sets the
4246;; the condition code as follows:
4247;;   0   Result zero; no carry
4248;;   1   Result not zero; no carry
4249;;   2   Result zero; carry
4250;;   3   Result not zero; carry
4251;; This means "carry" corresponds to condition code 2 or 3, i.e.
4252;; a condition mask of 2 | 1.
4253;;
4254;; As this does not match any of the encodings used with a normal integer
4255;; comparison, this cannot be represented by any IntCC value.  We need to
4256;; remap the IntCC::UnsignedGreaterThan value that we have here as result
4257;; of the unsigned_add_overflow_condition call to the correct mask.
4258
4259(rule 0 (lower (has_type (fits_in_64 ty) (uadd_overflow_trap _ x y tc)))
4260      (with_flags
4261        (add_logical_reg_with_flags_paired ty x y)
4262        (trap_if_impl (mask_as_cond 3) tc)))
4263
4264;; Add a register an a zero-extended register.
4265(rule 4 (lower (has_type (fits_in_64 ty)
4266                         (uadd_overflow_trap _ x (zext32_value y) tc)))
4267      (with_flags
4268        (add_logical_reg_zext32_with_flags_paired ty x y)
4269        (trap_if_impl (mask_as_cond 3) tc)))
4270(rule 8 (lower (has_type (fits_in_64 ty)
4271                         (uadd_overflow_trap _ (zext32_value x) y tc)))
4272      (with_flags
4273        (add_logical_reg_zext32_with_flags_paired ty y x)
4274        (trap_if_impl (mask_as_cond 3) tc)))
4275
4276;; Add a register and an immediate
4277(rule 3 (lower (has_type (fits_in_64 ty)
4278                         (uadd_overflow_trap _ x (u32_from_value y) tc)))
4279      (with_flags
4280        (add_logical_zimm32_with_flags_paired ty x y)
4281        (trap_if_impl (mask_as_cond 3) tc)))
4282(rule 7 (lower (has_type (fits_in_64 ty)
4283                         (uadd_overflow_trap _ (u32_from_value x) y tc)))
4284      (with_flags
4285        (add_logical_zimm32_with_flags_paired ty y x)
4286        (trap_if_impl (mask_as_cond 3) tc)))
4287
4288;; Add a register and memory (32/64-bit types).
4289(rule 2 (lower (has_type (fits_in_64 ty)
4290                         (uadd_overflow_trap _ x (sinkable_load_32_64 y) tc)))
4291      (with_flags
4292        (add_logical_mem_with_flags_paired ty x (sink_load y))
4293        (trap_if_impl (mask_as_cond 3) tc)))
4294(rule 6 (lower (has_type (fits_in_64 ty)
4295                         (uadd_overflow_trap _ (sinkable_load_32_64 x) y tc)))
4296      (with_flags
4297        (add_logical_mem_with_flags_paired ty y (sink_load x))
4298        (trap_if_impl (mask_as_cond 3) tc)))
4299
4300;; Add a register and zero-extended memory.
4301(rule 1 (lower (has_type (fits_in_64 ty)
4302                         (uadd_overflow_trap _ x (sinkable_uload32 y) tc)))
4303      (with_flags
4304        (add_logical_mem_zext32_with_flags_paired ty x (sink_uload32 y))
4305        (trap_if_impl (mask_as_cond 3) tc)))
4306(rule 5 (lower (has_type (fits_in_64 ty)
4307                         (uadd_overflow_trap _ (sinkable_uload32 x) y tc)))
4308      (with_flags
4309        (add_logical_mem_zext32_with_flags_paired ty y (sink_uload32 x))
4310        (trap_if_impl (mask_as_cond 3) tc)))
4311
4312;;;; Rules for `uadd_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4313
4314(rule 0 (lower (has_type (ty_32_or_64 ty) (uadd_overflow _ x y)))
4315      (let ((sum Reg (add_reg ty x y))
4316            (overflow Reg
4317              (lower_bool $I8
4318                          (bool (icmpu_reg ty sum x) (intcc_as_cond (IntCC.UnsignedLessThan))))))
4319        (output_pair sum overflow)))
4320
4321;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4322
4323(rule (lower (return args))
4324      (lower_return args))
4325
4326
4327;;;; Rules for `call` and `call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4328
4329;; Direct call to an in-range function.
4330(rule 1 (lower (call (func_ref_data sig_ref name (RelocDistance.Near) patchable) args))
4331      (let ((output ValueRegsVec (gen_call_output sig_ref))
4332            (abi Sig (abi_sig sig_ref))
4333            (_ Unit (abi_emit_call_adjust_stack abi))
4334            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4335            (defs CallRetList (gen_call_rets abi output))
4336            (info BoxCallInfo (gen_call_info abi name uses defs (try_call_none) patchable))
4337            (_ Unit (emit_side_effect (call_impl (writable_link_reg) info))))
4338        output))
4339
4340;; Direct call to an out-of-range function (implicitly via pointer).
4341(rule (lower (call (func_ref_data sig_ref name _ false) args))
4342      (let ((output ValueRegsVec (gen_call_output sig_ref))
4343            (abi Sig (abi_sig sig_ref))
4344            (_ Unit (abi_emit_call_adjust_stack abi))
4345            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4346            (defs CallRetList (gen_call_rets abi output))
4347            (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0)))
4348            (info BoxCallInfo (gen_call_info abi target uses defs (try_call_none) false))
4349            (_ Unit (emit_side_effect (call_impl (writable_link_reg) info))))
4350        output))
4351
4352;; Indirect call.
4353(rule (lower (call_indirect sig_ref ptr args))
4354      (let ((output ValueRegsVec (gen_call_output sig_ref))
4355            (abi Sig (abi_sig sig_ref))
4356            (target Reg (put_in_reg ptr))
4357            (_ Unit (abi_emit_call_adjust_stack abi))
4358            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4359            (defs CallRetList (gen_call_rets abi output))
4360            (info BoxCallInfo (gen_call_info abi target uses defs (try_call_none) false))
4361            (_ Unit (emit_side_effect (call_impl (writable_link_reg) info))))
4362        output))
4363
4364;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;
4365
4366;; Direct tail call to an in-range function.
4367(rule 1 (lower (return_call (func_ref_data sig_ref name (RelocDistance.Near) false) args))
4368      (let ((abi Sig (abi_sig sig_ref))
4369            (_ Unit (abi_emit_return_call_adjust_stack abi))
4370            (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args)))
4371            (info BoxReturnCallInfo (gen_return_call_info abi name uses)))
4372        (side_effect (return_call_impl info))))
4373
4374;; Direct tail call to an out-of-range function (implicitly via pointer).
4375(rule (lower (return_call (func_ref_data sig_ref name _ false) args))
4376      (let ((abi Sig (abi_sig sig_ref))
4377            (_ Unit (abi_emit_return_call_adjust_stack abi))
4378            (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args)))
4379            (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0)))
4380            (info BoxReturnCallInfo (gen_return_call_info abi target uses)))
4381        (side_effect (return_call_impl info))))
4382
4383;; Indirect tail call.
4384(rule (lower (return_call_indirect sig_ref ptr args))
4385      (let ((abi Sig (abi_sig sig_ref))
4386            (target Reg (put_in_reg ptr))
4387            (_ Unit (abi_emit_return_call_adjust_stack abi))
4388            (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args)))
4389            (info BoxReturnCallInfo (gen_return_call_info abi target uses)))
4390        (side_effect (return_call_impl info))))
4391
4392
4393;;;; Rules for `try_call` and `try_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4394
4395;; Direct call to an in-range function.
4396(rule 1 (lower_branch (try_call (func_ref_data sig_ref name (RelocDistance.Near) patchable) args et) targets)
4397      (let ((abi Sig (abi_sig sig_ref))
4398            (trycall OptionTryCallInfo (try_call_info et targets))
4399            (_ Unit (abi_emit_call_adjust_stack abi))
4400            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4401            (defs CallRetList (gen_try_call_rets abi))
4402            (info BoxCallInfo (gen_call_info abi name uses defs trycall patchable)))
4403        (emit_side_effect (call_impl (writable_link_reg) info))))
4404
4405;; Direct call to an out-of-range function (implicitly via pointer).
4406(rule (lower_branch (try_call (func_ref_data sig_ref name _ false) args et) targets)
4407      (let ((abi Sig (abi_sig sig_ref))
4408            (trycall OptionTryCallInfo (try_call_info et targets))
4409            (_ Unit (abi_emit_call_adjust_stack abi))
4410            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4411            (defs CallRetList (gen_try_call_rets abi))
4412            (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0)))
4413            (info BoxCallInfo (gen_call_info abi target uses defs trycall false)))
4414        (emit_side_effect (call_impl (writable_link_reg) info))))
4415
4416;; Indirect call.
4417(rule (lower_branch (try_call_indirect ptr args et) targets)
4418      (if-let (exception_sig sig_ref) et)
4419      (let ((abi Sig (abi_sig sig_ref))
4420            (trycall OptionTryCallInfo (try_call_info et targets))
4421            (target Reg (put_in_reg ptr))
4422            (_ Unit (abi_emit_call_adjust_stack abi))
4423            (uses CallArgList (gen_call_args abi (abi_prepare_args abi args)))
4424            (defs CallRetList (gen_try_call_rets abi))
4425            (info BoxCallInfo (gen_call_info abi target uses defs trycall false)))
4426        (emit_side_effect (call_impl (writable_link_reg) info))))
4427
4428
4429;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;;
4430
4431(rule (lower (get_stack_pointer _))
4432      (sp))
4433
4434(rule (lower (get_frame_pointer _))
4435      (load64 (memarg_frame_pointer_offset)))
4436
4437(rule (lower (get_return_address _))
4438      (load64 (memarg_return_address_offset)))
4439
4440;; Rules for `get_exception_handler_address` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4441
4442(rule (lower (get_exception_handler_address _ (u64_from_imm64 idx) block))
4443      (let ((succ_label MachLabel (block_exn_successor_label block idx)))
4444        (s390x_label_address succ_label)))
4445
4446;; Rules for `sequence_point` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4447
4448(rule (lower (sequence_point))
4449      (side_effect
4450       (s390x_sequence_point)))
4451