1;; Pulley 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;;;; Rules for Control Flow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8
9;; Helper to place a conditional `Value` provided into a register. Pulley
10;; conditional values occupy the full low 32-bits of a register and so this
11;; needs to handle situations such as when the `Value` is 64-bits an explicit
12;; comparison must be made. Additionally if `Value` is smaller than 32-bits
13;; then it must be sign-extended up to at least 32 bits.
14(decl lower_cond (Value) Cond)
15(rule 0 (lower_cond val @ (value_type (fits_in_32 _))) (Cond.If32 (zext32 val)))
16(rule 1 (lower_cond val @ (value_type $I64))
17  (Cond.IfXneq64I32 val 0))
18
19;; Peel away explicit `uextend` values to take a look at the inner value.
20(rule 2 (lower_cond (uextend val)) (lower_cond val))
21;; Conditional branches on `icmp`s.
22(rule 2 (lower_cond (icmp cc a b @ (value_type $I32))) (lower_cond_icmp32 cc a b))
23(rule 2 (lower_cond (icmp cc a b @ (value_type $I64))) (lower_cond_icmp64 cc a b))
24
25(decl lower_cond_icmp32 (IntCC Value Value) Cond)
26(rule (lower_cond_icmp32 (IntCC.Equal) a b) (Cond.IfXeq32 a b))
27(rule (lower_cond_icmp32 (IntCC.NotEqual) a b) (Cond.IfXneq32 a b))
28(rule (lower_cond_icmp32 (IntCC.SignedLessThan) a b) (Cond.IfXslt32 a b))
29(rule (lower_cond_icmp32 (IntCC.SignedLessThanOrEqual) a b) (Cond.IfXslteq32 a b))
30(rule (lower_cond_icmp32 (IntCC.UnsignedLessThan) a b) (Cond.IfXult32 a b))
31(rule (lower_cond_icmp32 (IntCC.UnsignedLessThanOrEqual) a b) (Cond.IfXulteq32 a b))
32;; Swap args for conditions pulley doesn't have
33(rule (lower_cond_icmp32 (IntCC.SignedGreaterThan) a b) (Cond.IfXslt32 b a))
34(rule (lower_cond_icmp32 (IntCC.SignedGreaterThanOrEqual) a b) (Cond.IfXslteq32 b a))
35(rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult32 b a))
36(rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq32 b a))
37
38(rule 1 (lower_cond_icmp32 (IntCC.Equal) a (i32_from_iconst b))
39  (Cond.IfXeq32I32 a b))
40(rule 1 (lower_cond_icmp32 (IntCC.NotEqual) a (i32_from_iconst b))
41  (Cond.IfXneq32I32 a b))
42(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThan) a (i32_from_iconst b))
43  (Cond.IfXslt32I32 a b))
44(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b))
45  (Cond.IfXslteq32I32 a b))
46(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThan) a (i32_from_iconst b))
47  (Cond.IfXsgt32I32 a b))
48(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b))
49  (Cond.IfXsgteq32I32 a b))
50(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThan) a (u32_from_iconst b))
51  (Cond.IfXult32I32 a b))
52(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b))
53  (Cond.IfXulteq32I32 a b))
54(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b))
55  (Cond.IfXugt32I32 a b))
56(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b))
57  (Cond.IfXugteq32I32 a b))
58
59(decl lower_cond_icmp64 (IntCC Value Value) Cond)
60(rule (lower_cond_icmp64 (IntCC.Equal) a b) (Cond.IfXeq64 a b))
61(rule (lower_cond_icmp64 (IntCC.NotEqual) a b) (Cond.IfXneq64 a b))
62(rule (lower_cond_icmp64 (IntCC.SignedLessThan) a b) (Cond.IfXslt64 a b))
63(rule (lower_cond_icmp64 (IntCC.SignedLessThanOrEqual) a b) (Cond.IfXslteq64 a b))
64(rule (lower_cond_icmp64 (IntCC.UnsignedLessThan) a b) (Cond.IfXult64 a b))
65(rule (lower_cond_icmp64 (IntCC.UnsignedLessThanOrEqual) a b) (Cond.IfXulteq64 a b))
66;; Swap args for conditions pulley doesn't have
67(rule (lower_cond_icmp64 (IntCC.SignedGreaterThan) a b) (Cond.IfXslt64 b a))
68(rule (lower_cond_icmp64 (IntCC.SignedGreaterThanOrEqual) a b) (Cond.IfXslteq64 b a))
69(rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult64 b a))
70(rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq64 b a))
71
72(rule 1 (lower_cond_icmp64 (IntCC.Equal) a (i32_from_iconst b))
73  (Cond.IfXeq64I32 a b))
74(rule 1 (lower_cond_icmp64 (IntCC.NotEqual) a (i32_from_iconst b))
75  (Cond.IfXneq64I32 a b))
76(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThan) a (i32_from_iconst b))
77  (Cond.IfXslt64I32 a b))
78(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b))
79  (Cond.IfXslteq64I32 a b))
80(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThan) a (i32_from_iconst b))
81  (Cond.IfXsgt64I32 a b))
82(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b))
83  (Cond.IfXsgteq64I32 a b))
84(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThan) a (u32_from_iconst b))
85  (Cond.IfXult64I32 a b))
86(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b))
87  (Cond.IfXulteq64I32 a b))
88(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b))
89  (Cond.IfXugt64I32 a b))
90(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b))
91  (Cond.IfXugteq64I32 a b))
92
93;; The main control-flow-lowering term: takes a control-flow instruction and
94;; target(s) and emits the necessary instructions.
95(decl partial lower_branch (Inst MachLabelSlice) Unit)
96
97;; Unconditional jumps.
98(rule (lower_branch (jump _) (single_target label))
99      (emit_side_effect (pulley_jump label)))
100
101;; Generic case for conditional branches.
102(rule -1 (lower_branch (brif c _ _) (two_targets then else))
103      (emit_side_effect (pulley_br_if (lower_cond c) then else)))
104
105;; Branch tables.
106(rule (lower_branch (br_table index _) (jump_table_targets default targets))
107      (gen_br_table index default targets))
108
109;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
110
111(rule (lower (trap code))
112      (side_effect (pulley_trap code)))
113
114;;;; Rules for `trapz` and `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
115
116(rule (lower (trapz cond code))
117  (side_effect (pulley_trap_if (cond_invert (lower_cond cond)) code)))
118
119(rule (lower (trapnz cond code))
120  (side_effect (pulley_trap_if (lower_cond cond) code)))
121
122;;;; Rules for `get_stack_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
123
124(rule (lower (get_stack_pointer))
125      (pulley_get_special (sp_reg)))
126
127;;;; Rules for `get_frame_pointer` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
128
129(rule (lower (get_frame_pointer)) (pulley_xmov_fp))
130
131;;;; Rules for `get_return_address` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
133(rule (lower (get_return_address)) (pulley_xmov_lr))
134
135;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
136
137;; N.B.: the `ret` itself is generated by the ABI.
138(rule (lower (return args))
139      (lower_return args))
140
141;; Rules for `call` and `call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
142
143;; Direct call to a pulley function.
144(rule 1 (lower (call (func_ref_data sig_ref name (reloc_distance_near)) args))
145      (let ((output ValueRegsVec (gen_call_output sig_ref))
146            (abi Sig (abi_sig sig_ref))
147            (uses CallArgList (gen_call_args abi args))
148            (defs CallRetList (gen_call_rets abi output))
149            (info BoxCallInfo (gen_call_info abi name uses defs (try_call_none)))
150            (_ Unit (emit_side_effect (call_impl info))))
151        output))
152
153;; Direct call to a host function.
154(rule (lower (call (func_ref_data sig_ref name _) args))
155      (let ((output ValueRegsVec (gen_call_output sig_ref))
156            (abi Sig (abi_sig sig_ref))
157            (uses CallArgList (gen_call_args abi args))
158            (defs CallRetList (gen_call_rets abi output))
159            (info BoxCallIndirectHostInfo (gen_call_host_info abi name uses defs (try_call_none)))
160            (_ Unit (emit_side_effect (indirect_call_host_impl info))))
161        output))
162
163;; Indirect call (assumed to be pulley->pulley).
164(rule (lower (call_indirect sig_ref ptr args))
165      (let ((output ValueRegsVec (gen_call_output sig_ref))
166            (abi Sig (abi_sig sig_ref))
167            (target Reg (put_in_reg ptr))
168            (uses CallArgList (gen_call_args abi args))
169            (defs CallRetList (gen_call_rets abi output))
170            (info BoxCallIndInfo (gen_call_ind_info abi target uses defs (try_call_none)))
171            (_ Unit (emit_side_effect (indirect_call_impl info))))
172        output))
173
174;;;; Rules for `try_call` and `try_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
175
176;; Direct call to a pulley function.
177(rule 1 (lower_branch (try_call (func_ref_data sig_ref name (reloc_distance_near)) args et) targets)
178      (let ((abi Sig (abi_sig sig_ref))
179            (trycall OptionTryCallInfo (try_call_info et targets))
180            (uses CallArgList (gen_call_args abi args))
181            (defs CallRetList (gen_try_call_rets abi))
182            (info BoxCallInfo (gen_call_info abi name uses defs trycall)))
183        (emit_side_effect (call_impl info))))
184
185;; Direct call to a host function.
186(rule (lower_branch (try_call (func_ref_data sig_ref name _) args et) targets)
187      (let ((abi Sig (abi_sig sig_ref))
188            (trycall OptionTryCallInfo (try_call_info et targets))
189            (uses CallArgList (gen_call_args abi args))
190            (defs CallRetList (gen_try_call_rets abi))
191            (info BoxCallIndirectHostInfo (gen_call_host_info abi name uses defs trycall)))
192        (emit_side_effect (indirect_call_host_impl info))))
193
194;; Indirect call (assumed to be pulley->pulley).
195(rule (lower_branch (try_call_indirect ptr args et) targets)
196      (if-let (exception_sig sig_ref) et)
197      (let ((abi Sig (abi_sig sig_ref))
198            (trycall OptionTryCallInfo (try_call_info et targets))
199            (target Reg (put_in_reg ptr))
200            (uses CallArgList (gen_call_args abi args))
201            (defs CallRetList (gen_try_call_rets abi))
202            (info BoxCallIndInfo (gen_call_ind_info abi target uses defs trycall)))
203        (emit_side_effect (indirect_call_impl info))))
204
205;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;
206
207;; Direct call to a pulley function.
208(rule 1 (lower (return_call (func_ref_data sig_ref name (reloc_distance_near)) args))
209      (let ((abi Sig (abi_sig sig_ref))
210            (uses CallArgList (gen_return_call_args abi args))
211            (info BoxReturnCallInfo (gen_return_call_info abi name uses)))
212        (side_effect (return_call_impl info))))
213
214;; Indirect call (assumed to be pulley->pulley).
215(rule (lower (return_call_indirect sig_ref ptr args))
216      (let ((abi Sig (abi_sig sig_ref))
217            (target Reg (put_in_reg ptr))
218            (uses CallArgList (gen_return_call_args abi args))
219            (info BoxReturnCallIndInfo (gen_return_call_ind_info abi target uses)))
220        (side_effect (return_indirect_call_impl info))))
221
222;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
223
224(rule (lower (has_type ty (iconst c))) (imm (i64_sextend_imm64 ty c)))
225
226;;;; Rules for `f32const`;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
227
228(rule (lower (f32const (u32_from_ieee32 x))) (pulley_fconst32 x))
229
230;;;; Rules for `f64const`;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
231
232(rule (lower (f64const (u64_from_ieee64 x))) (pulley_fconst64 x))
233
234;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
235
236(rule 0 (lower (has_type (ty_int (fits_in_64 ty)) (iadd a b))) (pulley_xadd32 a b))
237(rule 1 (lower (has_type $I64 (iadd a b))) (pulley_xadd64 a b))
238
239;; Fold constants into the instruction if possible
240(rule 10 (lower (has_type (ty_int (fits_in_32 _)) (iadd a (u32_from_iconst b))))
241  (pulley_xadd32_u32 a b))
242(rule 11 (lower (has_type (ty_int (fits_in_32 _)) (iadd a (u8_from_iconst b))))
243  (pulley_xadd32_u8 a b))
244(rule 12 (lower (has_type $I64 (iadd a (u32_from_iconst b))))
245  (pulley_xadd64_u32 a b))
246(rule 13 (lower (has_type $I64 (iadd a (u8_from_iconst b))))
247  (pulley_xadd64_u8 a b))
248
249;; If the rhs is a constant and the negated version can fit within a smaller
250;; constant then switch this to a subtraction with the negated constant.
251(rule 14 (lower (has_type (ty_int (fits_in_32 _)) (iadd a b)))
252  (if-let c (u32_from_negated_iconst b))
253  (pulley_xsub32_u32 a c))
254(rule 15 (lower (has_type $I64 (iadd a b)))
255  (if-let c (u32_from_negated_iconst b))
256  (pulley_xsub64_u32 a c))
257(rule 16 (lower (has_type (ty_int (fits_in_32 _)) (iadd a b)))
258  (if-let c (u8_from_negated_iconst b))
259  (pulley_xsub32_u8 a c))
260(rule 17 (lower (has_type $I64 (iadd a b)))
261  (if-let c (u8_from_negated_iconst b))
262  (pulley_xsub64_u8 a c))
263
264;; Helper extract a constant from a `Value`, negate it, and fit it within a
265;; `u8`.
266(decl pure partial u8_from_negated_iconst (Value) u8)
267(rule (u8_from_negated_iconst (i32_from_iconst i))
268  (if-let neg_i64 (i64_checked_neg i))
269  (if-let neg_u8 (i64_try_into_u8 neg_i64))
270  neg_u8)
271
272;; Helper extract a constant from a `Value`, negate it, and fit it within a
273;; `u32`.
274(decl pure partial u32_from_negated_iconst (Value) u32)
275(rule (u32_from_negated_iconst (i32_from_iconst i))
276  (if-let neg_i64 (i64_checked_neg i))
277  (if-let neg_u32 (i64_try_into_u32 neg_i64))
278  neg_u32)
279
280;; 128-bit addition
281(rule 1 (lower (has_type $I128 (iadd a b)))
282  (let ((a ValueRegs a)
283        (b ValueRegs b))
284    (pulley_xadd128
285      (value_regs_get a 0)
286      (value_regs_get a 1)
287      (value_regs_get b 0)
288      (value_regs_get b 1))))
289
290;; vector addition
291(rule 1 (lower (has_type $I8X16 (iadd a b))) (pulley_vaddi8x16 a b))
292(rule 1 (lower (has_type $I16X8 (iadd a b))) (pulley_vaddi16x8 a b))
293(rule 1 (lower (has_type $I32X4 (iadd a b))) (pulley_vaddi32x4 a b))
294(rule 1 (lower (has_type $I64X2 (iadd a b))) (pulley_vaddi64x2 a b))
295
296(rule 1 (lower (has_type $I8X16 (sadd_sat a b))) (pulley_vaddi8x16_sat a b))
297(rule 1 (lower (has_type $I8X16 (uadd_sat a b))) (pulley_vaddu8x16_sat a b))
298(rule 1 (lower (has_type $I16X8 (sadd_sat a b))) (pulley_vaddi16x8_sat a b))
299(rule 1 (lower (has_type $I16X8 (uadd_sat a b))) (pulley_vaddu16x8_sat a b))
300
301;; Specialized lowerings for multiply-and-add
302
303(rule 2 (lower (has_type $I32 (iadd (imul a b) c))) (pulley_xmadd32 a b c))
304(rule 3 (lower (has_type $I32 (iadd c (imul a b)))) (pulley_xmadd32 a b c))
305(rule 2 (lower (has_type $I64 (iadd (imul a b) c))) (pulley_xmadd64 a b c))
306(rule 3 (lower (has_type $I64 (iadd c (imul a b)))) (pulley_xmadd64 a b c))
307
308;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
309
310(rule (lower (has_type $I16X8 (iadd_pairwise a b))) (pulley_vaddpairwisei16x8_s a b))
311(rule (lower (has_type $I32X4 (iadd_pairwise a b))) (pulley_vaddpairwisei32x4_s a b))
312
313;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314
315(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (isub a b))) (pulley_xsub32 a b))
316(rule 1 (lower (has_type $I64 (isub a b))) (pulley_xsub64 a b))
317
318;; Fold a rhs constant into the instruction if possible.
319(rule 2 (lower (has_type (ty_int (fits_in_32 _)) (isub a (u32_from_iconst b))))
320  (pulley_xsub32_u32 a b))
321(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (isub a (u8_from_iconst b))))
322  (pulley_xsub32_u8 a b))
323(rule 4 (lower (has_type $I64 (isub a (u32_from_iconst b))))
324  (pulley_xsub64_u32 a b))
325(rule 5 (lower (has_type $I64 (isub a (u8_from_iconst b))))
326  (pulley_xsub64_u8 a b))
327
328;; If the rhs is a constant and the negated version can fit within a smaller
329;; constant then switch this to an addition with the negated constant.
330(rule 6 (lower (has_type (ty_int (fits_in_32 _)) (isub a b)))
331  (if-let c (u32_from_negated_iconst b))
332  (pulley_xadd32_u32 a c))
333(rule 7 (lower (has_type $I64 (isub a b)))
334  (if-let c (u32_from_negated_iconst b))
335  (pulley_xadd64_u32 a c))
336(rule 8 (lower (has_type (ty_int (fits_in_32 _)) (isub a b)))
337  (if-let c (u8_from_negated_iconst b))
338  (pulley_xadd32_u8 a c))
339(rule 9 (lower (has_type $I64 (isub a b)))
340  (if-let c (u8_from_negated_iconst b))
341  (pulley_xadd64_u8 a c))
342
343;; 128-bit subtraction
344(rule 1 (lower (has_type $I128 (isub a b)))
345  (let ((a ValueRegs a)
346        (b ValueRegs b))
347    (pulley_xsub128
348      (value_regs_get a 0)
349      (value_regs_get a 1)
350      (value_regs_get b 0)
351      (value_regs_get b 1))))
352
353;; vector subtraction
354(rule 1 (lower (has_type $I8X16 (isub a b))) (pulley_vsubi8x16 a b))
355(rule 1 (lower (has_type $I16X8 (isub a b))) (pulley_vsubi16x8 a b))
356(rule 1 (lower (has_type $I32X4 (isub a b))) (pulley_vsubi32x4 a b))
357(rule 1 (lower (has_type $I64X2 (isub a b))) (pulley_vsubi64x2 a b))
358
359(rule 1 (lower (has_type $I8X16 (ssub_sat a b))) (pulley_vsubi8x16_sat a b))
360(rule 1 (lower (has_type $I8X16 (usub_sat a b))) (pulley_vsubu8x16_sat a b))
361(rule 1 (lower (has_type $I16X8 (ssub_sat a b))) (pulley_vsubi16x8_sat a b))
362(rule 1 (lower (has_type $I16X8 (usub_sat a b))) (pulley_vsubu16x8_sat a b))
363
364;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365
366(rule (lower (has_type $I8 (imul a b))) (pulley_xmul32 a b))
367(rule (lower (has_type $I16 (imul a b))) (pulley_xmul32 a b))
368(rule (lower (has_type $I32 (imul a b))) (pulley_xmul32 a b))
369(rule (lower (has_type $I64 (imul a b))) (pulley_xmul64 a b))
370
371(rule 1 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i32_from_iconst b))))
372  (pulley_xmul32_s32 a b))
373(rule 2 (lower (has_type $I64 (imul a (i32_from_iconst b))))
374  (pulley_xmul64_s32 a b))
375(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (imul a (i8_from_iconst b))))
376  (pulley_xmul32_s8 a b))
377(rule 4 (lower (has_type $I64 (imul a (i8_from_iconst b))))
378  (pulley_xmul64_s8 a b))
379
380;; 128-bit (or wide) multiplication
381(rule 4 (lower (has_type $I128 (imul (uextend a) (uextend b))))
382  (pulley_xwidemul64_u (zext64 a) (zext64 b)))
383(rule 4 (lower (has_type $I128 (imul (sextend a) (sextend b))))
384  (pulley_xwidemul64_s (sext64 a) (sext64 b)))
385
386;; for I128
387(rule (lower (has_type $I128 (imul x y)))
388  (let
389    ((x_regs ValueRegs x)
390      (x_lo XReg (value_regs_get x_regs 0))
391      (x_hi XReg (value_regs_get x_regs 1))
392
393      ;; Get the high/low registers for `y`.
394      (y_regs ValueRegs y)
395      (y_lo XReg (value_regs_get y_regs 0))
396      (y_hi XReg (value_regs_get y_regs 1))
397
398      ;; 128bit mul formula:
399      ;;   dst_lo = x_lo * y_lo
400      ;;   dst_hi = mul_high(x_lo, y_lo) + (x_lo * y_hi) + (x_hi * y_lo)
401      (wide_regs ValueRegs (pulley_xwidemul64_u x_lo y_lo))
402      (wide_lo XReg (value_regs_get wide_regs 0))
403      (wide_hi XReg (value_regs_get wide_regs 1))
404      (tmp_hi1 XReg (pulley_xmul64 x_lo y_hi))
405      (tmp_hi2 XReg (pulley_xmul64 x_hi y_lo))
406      (tmp_add XReg (pulley_xadd64 wide_hi tmp_hi1))
407      (result_hi XReg (pulley_xadd64 tmp_add tmp_hi2))
408    )
409    (value_regs wide_lo result_hi)))
410
411;; vector multiplication
412(rule (lower (has_type $I8X16 (imul a b))) (pulley_vmuli8x16 a b))
413(rule (lower (has_type $I16X8 (imul a b))) (pulley_vmuli16x8 a b))
414(rule (lower (has_type $I32X4 (imul a b))) (pulley_vmuli32x4 a b))
415(rule (lower (has_type $I64X2 (imul a b))) (pulley_vmuli64x2 a b))
416
417;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
418
419(rule (lower (has_type $I8 (umulhi a b)))
420  (if-let (u6_from_u8 shift) (u64_try_into_u8 8))
421  (pulley_xshr32_u_u6 (pulley_xmul32 (zext32 a) (zext32 b)) shift))
422
423(rule (lower (has_type $I16 (umulhi a b)))
424  (if-let (u6_from_u8 shift) (u64_try_into_u8 16))
425  (pulley_xshr32_u_u6 (pulley_xmul32 (zext32 a) (zext32 b)) shift))
426
427(rule (lower (has_type $I32 (umulhi a b)))
428  (if-let (u6_from_u8 shift) (u64_try_into_u8 32))
429  (pulley_xshr64_u_u6 (pulley_xmul64 (zext64 a) (zext64 b)) shift))
430
431(rule (lower (has_type $I64 (umulhi a b)))
432  (pulley_xmulhi64_u a b))
433
434;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
435
436(rule (lower (has_type $I8 (smulhi a b)))
437  (if-let (u6_from_u8 shift) (u64_try_into_u8 8))
438  (pulley_xshr32_s_u6 (pulley_xmul32 (sext32 a) (sext32 b)) shift))
439
440(rule (lower (has_type $I16 (smulhi a b)))
441  (if-let (u6_from_u8 shift) (u64_try_into_u8 16))
442  (pulley_xshr32_s_u6 (pulley_xmul32 (sext32 a) (sext32 b)) shift))
443
444(rule (lower (has_type $I32 (smulhi a b)))
445  (if-let (u6_from_u8 shift) (u64_try_into_u8 32))
446  (pulley_xshr64_s_u6 (pulley_xmul64 (sext64 a) (sext64 b)) shift))
447
448(rule (lower (has_type $I64 (smulhi a b)))
449  (pulley_xmulhi64_s a b))
450
451;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
452
453(rule (lower (has_type $I16X8 (sqmul_round_sat a b))) (pulley_vqmulrsi16x8 a b))
454
455;;;; Rules for `sdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
456
457(rule 0 (lower (has_type (fits_in_32 _) (sdiv a b)))
458  (pulley_xdiv32_s (sext32 a) (sext32 b)))
459(rule 1 (lower (has_type $I64 (sdiv a b))) (pulley_xdiv64_s a b))
460
461;;;; Rules for `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
462
463(rule 0 (lower (has_type (fits_in_32 _) (srem a b)))
464  (pulley_xrem32_s (sext32 a) (sext32 b)))
465(rule 1 (lower (has_type $I64 (srem a b))) (pulley_xrem64_s a b))
466
467;;;; Rules for `udiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
468
469(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (udiv a b)))
470  (pulley_xdiv32_u (zext32 a) (zext32 b)))
471(rule 1 (lower (has_type $I64 (udiv a b))) (pulley_xdiv64_u a b))
472
473;;;; Rules for `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474
475(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (urem a b)))
476  (pulley_xrem32_u (zext32 a) (zext32 b)))
477(rule 1 (lower (has_type $I64 (urem a b))) (pulley_xrem64_u a b))
478
479;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
480
481(rule (lower (has_type $I8X16 (avg_round a b))) (pulley_vavground8x16 a b))
482(rule (lower (has_type $I16X8 (avg_round a b))) (pulley_vavground16x8 a b))
483
484;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
485
486(rule (lower (has_type $I8 (ishl a b)))
487  (pulley_xshl32 a (pulley_xband32_s8 b 7)))
488
489(rule (lower (has_type $I16 (ishl a b)))
490  (pulley_xshl32 a (pulley_xband32_s8 b 15)))
491
492(rule (lower (has_type $I32 (ishl a b)))
493  (pulley_xshl32 a b))
494
495(rule (lower (has_type $I64 (ishl a b)))
496  (pulley_xshl64 a b))
497
498;; Special-case constant shift amounts.
499(rule 1 (lower (has_type $I32 (ishl a b)))
500  (if-let n (u6_shift_from_iconst b))
501  (pulley_xshl32_u6 a n))
502(rule 1 (lower (has_type $I64 (ishl a b)))
503  (if-let n (u6_shift_from_iconst b))
504  (pulley_xshl64_u6 a n))
505
506;; vector shifts
507
508(rule (lower (has_type $I8X16 (ishl a b))) (pulley_vshli8x16 a b))
509(rule (lower (has_type $I16X8 (ishl a b))) (pulley_vshli16x8 a b))
510(rule (lower (has_type $I32X4 (ishl a b))) (pulley_vshli32x4 a b))
511(rule (lower (has_type $I64X2 (ishl a b))) (pulley_vshli64x2 a b))
512
513;; Helper to extract a constant from `Value`, mask it to 6 bits, and then make a
514;; `U6`.
515(decl pure partial u6_shift_from_iconst (Value) U6)
516(rule (u6_shift_from_iconst (u64_from_iconst val))
517  (if-let (u6_from_u8 x) (u64_try_into_u8 (u64_and val 0x3f)))
518  x)
519
520(decl u6_from_u8 (U6) u8)
521(extern extractor u6_from_u8 u6_from_u8)
522
523;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
524
525(rule (lower (has_type $I8 (ushr a b)))
526  (pulley_xshr32_u (zext32 a) (pulley_xband32_s8 b 7)))
527
528(rule (lower (has_type $I16 (ushr a b)))
529  (pulley_xshr32_u (zext32 a) (pulley_xband32_s8 b 15)))
530
531(rule (lower (has_type $I32 (ushr a b)))
532  (pulley_xshr32_u a b))
533
534(rule (lower (has_type $I64 (ushr a b)))
535  (pulley_xshr64_u a b))
536
537;; Special-case constant shift amounts.
538(rule 1 (lower (has_type $I32 (ushr a b)))
539  (if-let n (u6_shift_from_iconst b))
540  (pulley_xshr32_u_u6 a n))
541(rule 1 (lower (has_type $I64 (ushr a b)))
542  (if-let n (u6_shift_from_iconst b))
543  (pulley_xshr64_u_u6 a n))
544
545;; vector shifts
546
547(rule (lower (has_type $I8X16 (ushr a b))) (pulley_vshri8x16_u a b))
548(rule (lower (has_type $I16X8 (ushr a b))) (pulley_vshri16x8_u a b))
549(rule (lower (has_type $I32X4 (ushr a b))) (pulley_vshri32x4_u a b))
550(rule (lower (has_type $I64X2 (ushr a b))) (pulley_vshri64x2_u a b))
551
552;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
553
554(rule (lower (has_type $I8 (sshr a b)))
555  (pulley_xshr32_u (sext32 a) (pulley_xband32_s8 b 7)))
556
557(rule (lower (has_type $I16 (sshr a b)))
558  (pulley_xshr32_u (sext32 a) (pulley_xband32_s8 b 15)))
559
560(rule (lower (has_type $I32 (sshr a b)))
561  (pulley_xshr32_s a b))
562
563(rule (lower (has_type $I64 (sshr a b)))
564  (pulley_xshr64_s a b))
565
566;; Special-case constant shift amounts.
567(rule 1 (lower (has_type $I32 (sshr a b)))
568  (if-let n (u6_shift_from_iconst b))
569  (pulley_xshr32_s_u6 a n))
570(rule 1 (lower (has_type $I64 (sshr a b)))
571  (if-let n (u6_shift_from_iconst b))
572  (pulley_xshr64_s_u6 a n))
573
574;; vector shifts
575
576(rule (lower (has_type $I8X16 (sshr a b))) (pulley_vshri8x16_s a b))
577(rule (lower (has_type $I16X8 (sshr a b))) (pulley_vshri16x8_s a b))
578(rule (lower (has_type $I32X4 (sshr a b))) (pulley_vshri32x4_s a b))
579(rule (lower (has_type $I64X2 (sshr a b))) (pulley_vshri64x2_s a b))
580
581;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
582
583(rule 0 (lower (has_type (fits_in_32 _) (band a b))) (pulley_xband32 a b))
584(rule 1 (lower (has_type $I64 (band a b))) (pulley_xband64 a b))
585
586(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (band a (i32_from_iconst b))))
587  (pulley_xband32_s32 a b))
588(rule 4 (lower (has_type $I64 (band a (i32_from_iconst b))))
589  (pulley_xband64_s32 a b))
590(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (band a (i8_from_iconst b))))
591  (pulley_xband32_s8 a b))
592(rule 6 (lower (has_type $I64 (band a (i8_from_iconst b))))
593  (pulley_xband64_s8 a b))
594
595(rule 2 (lower (has_type (ty_vec128 _) (band a b)))
596  (pulley_vband128 a b))
597
598;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
599
600(rule 0 (lower (has_type (fits_in_32 _) (bor a b))) (pulley_xbor32 a b))
601(rule 1 (lower (has_type $I64 (bor a b))) (pulley_xbor64 a b))
602
603(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i32_from_iconst b))))
604  (pulley_xbor32_s32 a b))
605(rule 4 (lower (has_type $I64 (bor a (i32_from_iconst b))))
606  (pulley_xbor64_s32 a b))
607(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bor a (i8_from_iconst b))))
608  (pulley_xbor32_s8 a b))
609(rule 6 (lower (has_type $I64 (bor a (i8_from_iconst b))))
610  (pulley_xbor64_s8 a b))
611
612(rule 2 (lower (has_type (ty_vec128 _) (bor a b)))
613  (pulley_vbor128 a b))
614
615;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
616
617(rule 0 (lower (has_type (fits_in_32 _) (bxor a b))) (pulley_xbxor32 a b))
618(rule 1 (lower (has_type $I64 (bxor a b))) (pulley_xbxor64 a b))
619
620(rule 3 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i32_from_iconst b))))
621  (pulley_xbxor32_s32 a b))
622(rule 4 (lower (has_type $I64 (bxor a (i32_from_iconst b))))
623  (pulley_xbxor64_s32 a b))
624(rule 5 (lower (has_type (ty_int (fits_in_32 _)) (bxor a (i8_from_iconst b))))
625  (pulley_xbxor32_s8 a b))
626(rule 6 (lower (has_type $I64 (bxor a (i8_from_iconst b))))
627  (pulley_xbxor64_s8 a b))
628
629(rule 2 (lower (has_type (ty_vec128 _) (bxor a b)))
630  (pulley_vbxor128 a b))
631
632;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
633
634(rule 0 (lower (has_type (fits_in_32 _) (bnot a)))
635  (pulley_xbnot32 a))
636
637(rule 1 (lower (has_type $I64 (bnot a)))
638  (pulley_xbnot64 a))
639
640(rule 2 (lower (has_type (ty_vec128 _) (bnot a)))
641  (pulley_vbnot128 a))
642
643;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
644
645(rule (lower (has_type (ty_vec128 _) (bitselect c x y)))
646  (pulley_vbitselect128 c x y))
647
648;;;; Rules for `umin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
649
650(rule 0 (lower (has_type (fits_in_32 _) (umin a b)))
651  (pulley_xmin32_u (zext32 a) (zext32 b)))
652(rule 1 (lower (has_type $I64 (umin a b))) (pulley_xmin64_u a b))
653(rule 1 (lower (has_type $I8X16 (umin a b))) (pulley_vmin8x16_u a b))
654(rule 1 (lower (has_type $I16X8 (umin a b))) (pulley_vmin16x8_u a b))
655(rule 1 (lower (has_type $I32X4 (umin a b))) (pulley_vmin32x4_u a b))
656
657;;;; Rules for `smin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
658
659(rule 0 (lower (has_type (fits_in_32 _) (smin a b)))
660  (pulley_xmin32_s (sext32 a) (sext32 b)))
661(rule 1 (lower (has_type $I64 (smin a b))) (pulley_xmin64_s a b))
662(rule 1 (lower (has_type $I8X16 (smin a b))) (pulley_vmin8x16_s a b))
663(rule 1 (lower (has_type $I16X8 (smin a b))) (pulley_vmin16x8_s a b))
664(rule 1 (lower (has_type $I32X4 (smin a b))) (pulley_vmin32x4_s a b))
665
666;;;; Rules for `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
667
668(rule 0 (lower (has_type (fits_in_32 _) (umax a b)))
669  (pulley_xmax32_u (zext32 a) (zext32 b)))
670(rule 1 (lower (has_type $I64 (umax a b))) (pulley_xmax64_u a b))
671(rule 1 (lower (has_type $I8X16 (umax a b))) (pulley_vmax8x16_u a b))
672(rule 1 (lower (has_type $I16X8 (umax a b))) (pulley_vmax16x8_u a b))
673(rule 1 (lower (has_type $I32X4 (umax a b))) (pulley_vmax32x4_u a b))
674
675;;;; Rules for `smax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
676
677(rule 0 (lower (has_type (fits_in_32 _) (smax a b)))
678  (pulley_xmax32_s (sext32 a) (sext32 b)))
679(rule 1 (lower (has_type $I64 (smax a b))) (pulley_xmax64_s a b))
680(rule 1 (lower (has_type $I8X16 (smax a b))) (pulley_vmax8x16_s a b))
681(rule 1 (lower (has_type $I16X8 (smax a b))) (pulley_vmax16x8_s a b))
682(rule 1 (lower (has_type $I32X4 (smax a b))) (pulley_vmax32x4_s a b))
683
684;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
685
686(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (bmask a @ (value_type (fits_in_32 _)))))
687  (pulley_xbmask32 (zext32 a)))
688(rule 1 (lower (has_type $I64 (bmask a)))
689  (pulley_xbmask64 (zext64 a)))
690(rule 2 (lower (bmask a @ (value_type $I64)))
691  (pulley_xbmask64 a))
692
693;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
694
695(rule (lower (has_type $I8 (ctz a)))
696  (pulley_xctz32 (pulley_xbor32_s32 a 0x100)))
697(rule (lower (has_type $I16 (ctz a)))
698  (pulley_xctz32 (pulley_xbor32_s32 a 0x10000)))
699(rule (lower (has_type $I32 (ctz a))) (pulley_xctz32 a))
700(rule (lower (has_type $I64 (ctz a))) (pulley_xctz64 a))
701
702;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
703
704(rule (lower (has_type $I8 (clz a)))
705  (pulley_xsub32_u8 (pulley_xclz32 (zext32 a)) 24))
706(rule (lower (has_type $I16 (clz a)))
707  (pulley_xsub32_u8 (pulley_xclz32 (zext32 a)) 16))
708(rule (lower (has_type $I32 (clz a))) (pulley_xclz32 a))
709(rule (lower (has_type $I64 (clz a))) (pulley_xclz64 a))
710
711;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
712
713(rule 0 (lower (has_type (fits_in_32 _) (popcnt a))) (pulley_xpopcnt32 (zext32 a)))
714(rule 1 (lower (has_type $I64 (popcnt a))) (pulley_xpopcnt64 a))
715(rule 1 (lower (has_type $I8X16 (popcnt a))) (pulley_vpopcnt8x16 a))
716
717;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
718
719(rule (lower (has_type $I32 (rotl a b))) (pulley_xrotl32 a b))
720(rule (lower (has_type $I64 (rotl a b))) (pulley_xrotl64 a b))
721
722;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
723
724(rule (lower (has_type $I32 (rotr a b))) (pulley_xrotr32 a b))
725(rule (lower (has_type $I64 (rotr a b))) (pulley_xrotr64 a b))
726
727;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
728
729(rule (lower (icmp cc a b @ (value_type (ty_int ty))))
730      (lower_icmp ty cc a b))
731
732(decl lower_icmp (Type IntCC Value Value) XReg)
733
734(rule (lower_icmp $I64 (IntCC.Equal) a b)
735      (pulley_xeq64 a b))
736
737(rule (lower_icmp $I64 (IntCC.NotEqual) a b)
738      (pulley_xneq64 a b))
739
740(rule (lower_icmp $I64 (IntCC.SignedLessThan) a b)
741      (pulley_xslt64 a b))
742
743(rule (lower_icmp $I64 (IntCC.SignedLessThanOrEqual) a b)
744      (pulley_xslteq64 a b))
745
746(rule (lower_icmp $I64 (IntCC.UnsignedLessThan) a b)
747      (pulley_xult64 a b))
748
749(rule (lower_icmp $I64 (IntCC.UnsignedLessThanOrEqual) a b)
750      (pulley_xulteq64 a b))
751
752(rule 1 (lower_icmp (fits_in_32 _) (IntCC.Equal) a b)
753      (pulley_xeq32 (zext32 a) (zext32 b)))
754
755(rule 1 (lower_icmp (fits_in_32 _) (IntCC.NotEqual) a b)
756      (pulley_xneq32 (zext32 a) (zext32 b)))
757
758(rule 1 (lower_icmp (fits_in_32 _) (IntCC.SignedLessThan) a b)
759      (pulley_xslt32 (sext32 a) (sext32 b)))
760
761(rule 1 (lower_icmp (fits_in_32 _) (IntCC.SignedLessThanOrEqual) a b)
762      (pulley_xslteq32 (sext32 a) (sext32 b)))
763
764(rule 1 (lower_icmp (fits_in_32 _) (IntCC.UnsignedLessThan) a b)
765      (pulley_xult32 (zext32 a) (zext32 b)))
766
767(rule 1 (lower_icmp (fits_in_32 _) (IntCC.UnsignedLessThanOrEqual) a b)
768      (pulley_xulteq32 (zext32 a) (zext32 b)))
769
770;; Pulley doesn't have instructions for `>` and `>=`, so we have to reverse the
771;; operation.
772(rule (lower_icmp ty (IntCC.SignedGreaterThan) a b)
773      (lower_icmp ty (IntCC.SignedLessThan) b a))
774(rule (lower_icmp ty (IntCC.SignedGreaterThanOrEqual) a b)
775      (lower_icmp ty (IntCC.SignedLessThanOrEqual) b a))
776(rule (lower_icmp ty (IntCC.UnsignedGreaterThan) a b)
777      (lower_icmp ty (IntCC.UnsignedLessThan) b a))
778(rule (lower_icmp ty (IntCC.UnsignedGreaterThanOrEqual) a b)
779      (lower_icmp ty (IntCC.UnsignedLessThanOrEqual) b a))
780
781;; `i128` comparisons
782;;
783;; While we could pretty easily add 128-bit comparisons to the interpreter it's
784;; currently predicted that it's relatively niche to need this and that it's
785;; not performance-sensitive in an interpreter context. In lieu of adding more
786;; opcodes this is an adaptation of riscv64's lowering rules for 128-bit
787;; integers. In the future if this is a performance bottleneck it should be
788;; possible to add new opcodes to pulley for 128-bit comparisons.
789
790(rule (lower_icmp $I128 (IntCC.Equal) x y)
791  (let ((lo XReg (pulley_xbxor64 (value_regs_get x 0) (value_regs_get y 0)))
792        (hi XReg (pulley_xbxor64 (value_regs_get x 1) (value_regs_get y 1))))
793    (pulley_xeq64 (pulley_xbor64 lo hi) (pulley_xconst8 0))))
794(rule (lower_icmp $I128 (IntCC.NotEqual) x y)
795  (let ((lo XReg (pulley_xbxor64 (value_regs_get x 0) (value_regs_get y 0)))
796        (hi XReg (pulley_xbxor64 (value_regs_get x 1) (value_regs_get y 1))))
797    (pulley_xneq64 (pulley_xbor64 lo hi) (pulley_xconst8 0))))
798
799;; swap args for `>` to use `<` instead
800;;(rule 1 (lower_icmp $I128 cc @ (IntCC.SignedGreaterThan) x y)
801;;  (lower_icmp $I128 (intcc_swap_args cc) y x))
802;;(rule 1 (lower_icmp $I128 cc @ (IntCC.UnsignedGreaterThan) x y)
803;;  (lower_icmp $I128  (intcc_swap_args cc) y x))
804
805;; complement `=`-related conditions to get ones that don't use `=`.
806(rule 2 (lower_icmp $I128 cc @ (IntCC.SignedLessThanOrEqual) x y)
807  (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1))
808(rule 2 (lower_icmp $I128 cc @ (IntCC.SignedGreaterThanOrEqual) x y)
809  (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1))
810(rule 2 (lower_icmp $I128 cc @ (IntCC.UnsignedLessThanOrEqual) x y)
811  (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1))
812(rule 2 (lower_icmp $I128 cc @ (IntCC.UnsignedGreaterThanOrEqual) x y)
813  (pulley_xbxor32_s8 (lower_icmp $I128 (intcc_complement cc) x y) 1))
814
815;; Compare both the bottom and upper halves of the 128-bit values. If
816;; the top half is equal use the bottom comparison, otherwise use the upper
817;; comparison. Note that the lower comparison is always unsigned since if it's
818;; used the top halves are all zeros and the semantic values are positive.
819(rule 3 (lower_icmp $I128 cc x y)
820  (if-let (IntCC.UnsignedLessThan) (intcc_unsigned cc))
821  (let ((x_lo XReg (value_regs_get x 0))
822        (x_hi XReg (value_regs_get x 1))
823        (y_lo XReg (value_regs_get y 0))
824        (y_hi XReg (value_regs_get y 1))
825        (top_cmp XReg (lower_icmp128_hi cc x_hi y_hi))
826        (bottom_cmp XReg (pulley_xult64 x_lo y_lo)))
827    (pulley_xselect32
828      (pulley_xeq64 (pulley_xbxor64 x_hi y_hi) (pulley_xconst8 0))
829      bottom_cmp
830      top_cmp)))
831
832(decl lower_icmp128_hi (IntCC XReg XReg) XReg)
833(rule (lower_icmp128_hi (IntCC.SignedLessThan) a b) (pulley_xslt64 a b))
834(rule (lower_icmp128_hi (IntCC.UnsignedLessThan) a b) (pulley_xult64 a b))
835
836;; vector comparisons
837
838(rule 1 (lower (icmp cc a @ (value_type (ty_vec128 ty)) b))
839  (lower_vcmp ty cc a b))
840
841(decl lower_vcmp (Type IntCC Value Value) VReg)
842(rule (lower_vcmp $I8X16 (IntCC.Equal) a b) (pulley_veq8x16 a b))
843(rule (lower_vcmp $I8X16 (IntCC.NotEqual) a b) (pulley_vneq8x16 a b))
844(rule (lower_vcmp $I8X16 (IntCC.SignedLessThan) a b) (pulley_vslt8x16 a b))
845(rule (lower_vcmp $I8X16 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq8x16 a b))
846(rule (lower_vcmp $I8X16 (IntCC.UnsignedLessThan) a b) (pulley_vult8x16 a b))
847(rule (lower_vcmp $I8X16 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq8x16 a b))
848(rule (lower_vcmp $I16X8 (IntCC.Equal) a b) (pulley_veq16x8 a b))
849(rule (lower_vcmp $I16X8 (IntCC.NotEqual) a b) (pulley_vneq16x8 a b))
850(rule (lower_vcmp $I16X8 (IntCC.SignedLessThan) a b) (pulley_vslt16x8 a b))
851(rule (lower_vcmp $I16X8 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq16x8 a b))
852(rule (lower_vcmp $I16X8 (IntCC.UnsignedLessThan) a b) (pulley_vult16x8 a b))
853(rule (lower_vcmp $I16X8 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq16x8 a b))
854(rule (lower_vcmp $I32X4 (IntCC.Equal) a b) (pulley_veq32x4 a b))
855(rule (lower_vcmp $I32X4 (IntCC.NotEqual) a b) (pulley_vneq32x4 a b))
856(rule (lower_vcmp $I32X4 (IntCC.SignedLessThan) a b) (pulley_vslt32x4 a b))
857(rule (lower_vcmp $I32X4 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq32x4 a b))
858(rule (lower_vcmp $I32X4 (IntCC.UnsignedLessThan) a b) (pulley_vult32x4 a b))
859(rule (lower_vcmp $I32X4 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq32x4 a b))
860(rule (lower_vcmp $I64X2 (IntCC.Equal) a b) (pulley_veq64x2 a b))
861(rule (lower_vcmp $I64X2 (IntCC.NotEqual) a b) (pulley_vneq64x2 a b))
862(rule (lower_vcmp $I64X2 (IntCC.SignedLessThan) a b) (pulley_vslt64x2 a b))
863(rule (lower_vcmp $I64X2 (IntCC.SignedLessThanOrEqual) a b) (pulley_vslteq64x2 a b))
864(rule (lower_vcmp $I64X2 (IntCC.UnsignedLessThan) a b) (pulley_vult64x2 a b))
865(rule (lower_vcmp $I64X2 (IntCC.UnsignedLessThanOrEqual) a b) (pulley_vulteq64x2 a b))
866
867;; Sweap operand order of ops pulley doesn't support
868(rule (lower_vcmp ty cc @ (IntCC.SignedGreaterThan) a b)
869  (lower_vcmp ty (intcc_swap_args cc) b a))
870(rule (lower_vcmp ty cc @ (IntCC.SignedGreaterThanOrEqual) a b)
871  (lower_vcmp ty (intcc_swap_args cc) b a))
872(rule (lower_vcmp ty cc @ (IntCC.UnsignedGreaterThan) a b)
873  (lower_vcmp ty (intcc_swap_args cc) b a))
874(rule (lower_vcmp ty cc @ (IntCC.UnsignedGreaterThanOrEqual) a b)
875  (lower_vcmp ty (intcc_swap_args cc) b a))
876
877;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
878
879(rule (lower (fcmp cc a b @ (value_type (ty_scalar_float ty))))
880  (lower_fcmp ty cc a b))
881
882(rule 1 (lower (fcmp cc a b @ (value_type (ty_vec128 ty))))
883  (lower_vfcmp ty cc a b))
884
885(decl lower_fcmp (Type FloatCC Value Value) XReg)
886
887(rule (lower_fcmp $F32 (FloatCC.Equal) a b) (pulley_feq32 a b))
888(rule (lower_fcmp $F64 (FloatCC.Equal) a b) (pulley_feq64 a b))
889(rule (lower_fcmp $F32 (FloatCC.NotEqual) a b) (pulley_fneq32 a b))
890(rule (lower_fcmp $F64 (FloatCC.NotEqual) a b) (pulley_fneq64 a b))
891(rule (lower_fcmp $F32 (FloatCC.LessThan) a b) (pulley_flt32 a b))
892(rule (lower_fcmp $F64 (FloatCC.LessThan) a b) (pulley_flt64 a b))
893(rule (lower_fcmp $F32 (FloatCC.LessThanOrEqual) a b) (pulley_flteq32 a b))
894(rule (lower_fcmp $F64 (FloatCC.LessThanOrEqual) a b) (pulley_flteq64 a b))
895
896;; Ordered == !a.is_nan() && !b.is_nan()
897(rule (lower_fcmp ty (FloatCC.Ordered) a b)
898  (pulley_xband32 (lower_fcmp ty (FloatCC.Equal) a a) (lower_fcmp ty (FloatCC.Equal) b b)))
899
900;; OrderedNotEqual == a < b || a > b
901(rule (lower_fcmp ty (FloatCC.OrderedNotEqual) a b)
902  (pulley_xbor32 (lower_fcmp ty (FloatCC.LessThan) a b) (lower_fcmp ty (FloatCC.GreaterThan) a b)))
903
904;; Pulley doesn't have instructions for `>` and `>=`, so we have to reverse the
905;; operation.
906(rule (lower_fcmp ty (FloatCC.GreaterThan) a b)
907  (lower_fcmp ty (FloatCC.LessThan) b a))
908(rule (lower_fcmp ty (FloatCC.GreaterThanOrEqual) a b)
909  (lower_fcmp ty (FloatCC.LessThanOrEqual) b a))
910
911;; For other `Unordered*` comparisons generate its complement and invert the result.
912(rule -1 (lower_fcmp ty cc a b)
913  (if-let true (floatcc_unordered cc))
914  (pulley_xbxor32_s8 (lower_fcmp ty (floatcc_complement cc) a b) 1))
915
916(decl lower_vfcmp (Type FloatCC Value Value) VReg)
917
918(rule (lower_vfcmp $F32X4 (FloatCC.Equal) a b) (pulley_veqf32x4 a b))
919(rule (lower_vfcmp $F64X2 (FloatCC.Equal) a b) (pulley_veqf64x2 a b))
920(rule (lower_vfcmp $F32X4 (FloatCC.NotEqual) a b) (pulley_vneqf32x4 a b))
921(rule (lower_vfcmp $F64X2 (FloatCC.NotEqual) a b) (pulley_vneqf64x2 a b))
922(rule (lower_vfcmp $F32X4 (FloatCC.LessThan) a b) (pulley_vltf32x4 a b))
923(rule (lower_vfcmp $F64X2 (FloatCC.LessThan) a b) (pulley_vltf64x2 a b))
924(rule (lower_vfcmp $F32X4 (FloatCC.LessThanOrEqual) a b) (pulley_vlteqf32x4 a b))
925(rule (lower_vfcmp $F64X2 (FloatCC.LessThanOrEqual) a b) (pulley_vlteqf64x2 a b))
926
927(rule (lower_vfcmp ty (FloatCC.Unordered) a b)
928  (pulley_vbor128
929    (lower_vfcmp ty (FloatCC.NotEqual) a a)
930    (lower_vfcmp ty (FloatCC.NotEqual) b b)))
931
932;; NB: Pulley doesn't have lowerings for `Ordered` or `Unordered*` `FloatCC`
933;; conditions as that's not needed by wasm at this time.
934
935;; Pulley doesn't have instructions for `>` and `>=`, so we have to reverse the
936;; operation.
937(rule (lower_vfcmp ty (FloatCC.GreaterThan) a b)
938  (lower_vfcmp ty (FloatCC.LessThan) b a))
939(rule (lower_vfcmp ty (FloatCC.GreaterThanOrEqual) a b)
940  (lower_vfcmp ty (FloatCC.LessThanOrEqual) b a))
941
942;;;; Rules for `load` and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
943
944(rule (lower (has_type (ty_int (fits_in_64 ty)) (load flags addr offset)))
945  (gen_xload addr offset flags ty (ExtKind.None)))
946
947(rule 1 (lower (has_type (ty_scalar_float ty) (load flags addr offset)))
948  (gen_fload addr offset flags ty))
949
950(rule 3 (lower (has_type $I128 (load flags addr offset)))
951  (if-let offsetp8 (i32_checked_add offset 8))
952  (let ((lo XReg (pulley_xload (amode addr offset) $I64 flags))
953        (hi XReg (pulley_xload (amode addr offsetp8) $I64 flags)))
954    (value_regs lo hi)))
955
956(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload8 flags addr offset)))
957  (gen_xload addr offset flags $I8 (ExtKind.Zero32)))
958
959(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload16 flags addr offset)))
960  (gen_xload addr offset flags $I16 (ExtKind.Zero32)))
961
962(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (uload32 flags addr offset)))
963  (gen_xload addr offset flags $I32 (ExtKind.None)))
964
965(rule 1 (lower (has_type $I64 (uload8 flags addr offset)))
966  (gen_xload addr offset flags $I8 (ExtKind.Zero64)))
967
968(rule 1 (lower (has_type $I64 (uload16 flags addr offset)))
969  (gen_xload addr offset flags $I16 (ExtKind.Zero64)))
970
971(rule 1 (lower (has_type $I64 (uload32 flags addr offset)))
972  (gen_xload addr offset flags $I32 (ExtKind.Zero64)))
973
974(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload8 flags addr offset)))
975  (gen_xload addr offset flags $I8 (ExtKind.Sign32)))
976
977(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload16 flags addr offset)))
978  (gen_xload addr offset flags $I16 (ExtKind.Sign32)))
979
980(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (sload32 flags addr offset)))
981  (gen_xload addr offset flags $I32 (ExtKind.None)))
982
983(rule 1 (lower (has_type $I64 (sload8 flags addr offset)))
984  (gen_xload addr offset flags $I8 (ExtKind.Sign64)))
985
986(rule 1 (lower (has_type $I64 (sload16 flags addr offset)))
987  (gen_xload addr offset flags $I16 (ExtKind.Sign64)))
988
989(rule 1 (lower (has_type $I64 (sload32 flags addr offset)))
990  (gen_xload addr offset flags $I32 (ExtKind.Sign64)))
991
992(rule 2 (lower (has_type (ty_vec128 ty) (load flags addr offset)))
993  (gen_vload addr offset flags ty (VExtKind.None)))
994
995(rule (lower (has_type ty (sload8x8 flags addr offset)))
996  (gen_vload addr offset flags ty (VExtKind.S8x8)))
997
998(rule (lower (has_type ty (uload8x8 flags addr offset)))
999  (gen_vload addr offset flags ty (VExtKind.U8x8)))
1000
1001(rule (lower (has_type ty (sload16x4 flags addr offset)))
1002  (gen_vload addr offset flags ty (VExtKind.S16x4)))
1003
1004(rule (lower (has_type ty (uload16x4 flags addr offset)))
1005  (gen_vload addr offset flags ty (VExtKind.U16x4)))
1006
1007(rule (lower (has_type ty (sload32x2 flags addr offset)))
1008  (gen_vload addr offset flags ty (VExtKind.S32x2)))
1009
1010(rule (lower (has_type ty (uload32x2 flags addr offset)))
1011  (gen_vload addr offset flags ty (VExtKind.U32x2)))
1012
1013;; Helper to generate an `xload*` instruction, of which there are many. This
1014;; falls back to the pseudo-instruction `XLoad` which has code in `emit.rs` to
1015;; emit lots of forms but it additionally supports more specific pattern-matched
1016;; versions too.
1017(decl gen_xload (Value Offset32 MemFlags Type ExtKind) XReg)
1018
1019;; Base case: use `pulley_xload` pseudo-inst for big-endian loads/stores with
1020;; no extension. This should only be used for host-things on wasm and
1021;; intentionally is minimal at this time as we don't currently need to match
1022;; all `ExtKind` variants.
1023(rule 0 (gen_xload addr offset flags ty (ExtKind.None))
1024  (if-let true (memflags_nontrapping flags))
1025  (if-let (Endianness.Big) (endianness flags))
1026  (pulley_xload (amode addr offset) ty flags))
1027
1028;; Base case: use `*_o32` addressing modes for little-endian and nontrapping
1029;; loads/stores
1030(rule 0 (gen_xload addr offset flags ty ext)
1031  (if-let true (memflags_nontrapping flags))
1032  (if-let (Endianness.Little) (endianness flags))
1033  (emit_addro32_xload (addro32 addr offset) ty ext))
1034
1035(decl emit_addro32_xload (AddrO32 Type ExtKind) XReg)
1036(rule (emit_addro32_xload addr $I8 (ExtKind.None)) (pulley_xload8_u32_o32 addr))
1037(rule (emit_addro32_xload addr $I8 (ExtKind.Sign32)) (pulley_xload8_s32_o32 addr))
1038(rule (emit_addro32_xload addr $I8 (ExtKind.Zero32)) (pulley_xload8_u32_o32 addr))
1039(rule (emit_addro32_xload addr $I8 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload8_s32_o32 addr)))
1040(rule (emit_addro32_xload addr $I8 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload8_u32_o32 addr)))
1041(rule (emit_addro32_xload addr $I16 (ExtKind.None)) (pulley_xload16le_u32_o32 addr))
1042(rule (emit_addro32_xload addr $I16 (ExtKind.Sign32)) (pulley_xload16le_s32_o32 addr))
1043(rule (emit_addro32_xload addr $I16 (ExtKind.Zero32)) (pulley_xload16le_u32_o32 addr))
1044(rule (emit_addro32_xload addr $I16 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload16le_s32_o32 addr)))
1045(rule (emit_addro32_xload addr $I16 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload16le_u32_o32 addr)))
1046(rule (emit_addro32_xload addr $I32 (ExtKind.None)) (pulley_xload32le_o32 addr))
1047(rule (emit_addro32_xload addr $I32 (ExtKind.Sign32)) (pulley_xload32le_o32 addr))
1048(rule (emit_addro32_xload addr $I32 (ExtKind.Zero32)) (pulley_xload32le_o32 addr))
1049(rule (emit_addro32_xload addr $I32 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload32le_o32 addr)))
1050(rule (emit_addro32_xload addr $I32 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload32le_o32 addr)))
1051(rule (emit_addro32_xload addr $I64 _ext) (pulley_xload64le_o32 addr))
1052
1053;; Special case: wasm loads/stores that map trap use the `*_z` addressing modes
1054;; which generates a trap for load-from-null.
1055(rule 1 (gen_xload addr offset flags ty ext)
1056  (if-let true (memflags_is_wasm flags))
1057  (emit_addrz_xload (addrz addr offset) ty ext))
1058
1059(decl emit_addrz_xload (AddrZ Type ExtKind) XReg)
1060(rule (emit_addrz_xload addr $I8 (ExtKind.None)) (pulley_xload8_u32_z addr))
1061(rule (emit_addrz_xload addr $I8 (ExtKind.Sign32)) (pulley_xload8_s32_z addr))
1062(rule (emit_addrz_xload addr $I8 (ExtKind.Zero32)) (pulley_xload8_u32_z addr))
1063(rule (emit_addrz_xload addr $I8 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload8_s32_z addr)))
1064(rule (emit_addrz_xload addr $I8 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload8_u32_z addr)))
1065(rule (emit_addrz_xload addr $I16 (ExtKind.None)) (pulley_xload16le_u32_z addr))
1066(rule (emit_addrz_xload addr $I16 (ExtKind.Sign32)) (pulley_xload16le_s32_z addr))
1067(rule (emit_addrz_xload addr $I16 (ExtKind.Zero32)) (pulley_xload16le_u32_z addr))
1068(rule (emit_addrz_xload addr $I16 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload16le_s32_z addr)))
1069(rule (emit_addrz_xload addr $I16 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload16le_u32_z addr)))
1070(rule (emit_addrz_xload addr $I32 (ExtKind.None)) (pulley_xload32le_z addr))
1071(rule (emit_addrz_xload addr $I32 (ExtKind.Sign32)) (pulley_xload32le_z addr))
1072(rule (emit_addrz_xload addr $I32 (ExtKind.Zero32)) (pulley_xload32le_z addr))
1073(rule (emit_addrz_xload addr $I32 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload32le_z addr)))
1074(rule (emit_addrz_xload addr $I32 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload32le_z addr)))
1075(rule (emit_addrz_xload addr $I64 _ext) (pulley_xload64le_z addr))
1076
1077;; Special case: wasm loads/stores that may trap use the `*_g32` addressing
1078;; modes. This is a superset of the `*_z` modes above and requires extracting
1079;; a bounds check from within `addr` using a `select` condition.
1080(rule 2 (gen_xload addr offset flags ty ext)
1081  (if-let addrg32 (wasm_g32 addr offset flags ty))
1082  (gen_xload_g32 addrg32 ty ext))
1083
1084;; Base case of "g32" loads, emit the instructions
1085(decl gen_xload_g32 (G32 Type ExtKind) XReg)
1086(rule 0 (gen_xload_g32 addr ty ext) (emit_addrg32_xload addr ty ext))
1087
1088(decl emit_addrg32_xload (AddrG32 Type ExtKind) XReg)
1089(rule (emit_addrg32_xload addr $I8 (ExtKind.None)) (pulley_xload8_u32_g32 addr))
1090(rule (emit_addrg32_xload addr $I8 (ExtKind.Sign32)) (pulley_xload8_s32_g32 addr))
1091(rule (emit_addrg32_xload addr $I8 (ExtKind.Zero32)) (pulley_xload8_u32_g32 addr))
1092(rule (emit_addrg32_xload addr $I8 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload8_s32_g32 addr)))
1093(rule (emit_addrg32_xload addr $I8 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload8_u32_g32 addr)))
1094(rule (emit_addrg32_xload addr $I16 (ExtKind.None)) (pulley_xload16le_u32_g32 addr))
1095(rule (emit_addrg32_xload addr $I16 (ExtKind.Sign32)) (pulley_xload16le_s32_g32 addr))
1096(rule (emit_addrg32_xload addr $I16 (ExtKind.Zero32)) (pulley_xload16le_u32_g32 addr))
1097(rule (emit_addrg32_xload addr $I16 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload16le_s32_g32 addr)))
1098(rule (emit_addrg32_xload addr $I16 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload16le_u32_g32 addr)))
1099(rule (emit_addrg32_xload addr $I32 (ExtKind.None)) (pulley_xload32le_g32 addr))
1100(rule (emit_addrg32_xload addr $I32 (ExtKind.Sign32)) (pulley_xload32le_g32 addr))
1101(rule (emit_addrg32_xload addr $I32 (ExtKind.Zero32)) (pulley_xload32le_g32 addr))
1102(rule (emit_addrg32_xload addr $I32 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload32le_g32 addr)))
1103(rule (emit_addrg32_xload addr $I32 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload32le_g32 addr)))
1104(rule (emit_addrg32_xload addr $I64 _ext) (pulley_xload64le_g32 addr))
1105
1106;; Special case of "g32" load - if a "g32bne" mode is possible instead use that.
1107(rule 1 (gen_xload_g32 addr ty ext)
1108  (if-let addrbne (addrg32bne addr))
1109  (emit_addrg32bne_xload addrbne ty ext))
1110
1111(decl emit_addrg32bne_xload (AddrG32Bne Type ExtKind) XReg)
1112(rule (emit_addrg32bne_xload addr $I8 (ExtKind.None)) (pulley_xload8_u32_g32bne addr))
1113(rule (emit_addrg32bne_xload addr $I8 (ExtKind.Sign32)) (pulley_xload8_s32_g32bne addr))
1114(rule (emit_addrg32bne_xload addr $I8 (ExtKind.Zero32)) (pulley_xload8_u32_g32bne addr))
1115(rule (emit_addrg32bne_xload addr $I8 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload8_s32_g32bne addr)))
1116(rule (emit_addrg32bne_xload addr $I8 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload8_u32_g32bne addr)))
1117(rule (emit_addrg32bne_xload addr $I16 (ExtKind.None)) (pulley_xload16le_u32_g32bne addr))
1118(rule (emit_addrg32bne_xload addr $I16 (ExtKind.Sign32)) (pulley_xload16le_s32_g32bne addr))
1119(rule (emit_addrg32bne_xload addr $I16 (ExtKind.Zero32)) (pulley_xload16le_u32_g32bne addr))
1120(rule (emit_addrg32bne_xload addr $I16 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload16le_s32_g32bne addr)))
1121(rule (emit_addrg32bne_xload addr $I16 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload16le_u32_g32bne addr)))
1122(rule (emit_addrg32bne_xload addr $I32 (ExtKind.None)) (pulley_xload32le_g32bne addr))
1123(rule (emit_addrg32bne_xload addr $I32 (ExtKind.Sign32)) (pulley_xload32le_g32bne addr))
1124(rule (emit_addrg32bne_xload addr $I32 (ExtKind.Zero32)) (pulley_xload32le_g32bne addr))
1125(rule (emit_addrg32bne_xload addr $I32 (ExtKind.Sign64)) (pulley_sext32 (pulley_xload32le_g32bne addr)))
1126(rule (emit_addrg32bne_xload addr $I32 (ExtKind.Zero64)) (pulley_zext32 (pulley_xload32le_g32bne addr)))
1127(rule (emit_addrg32bne_xload addr $I64 _ext) (pulley_xload64le_g32bne addr))
1128
1129;; Analog of `gen_xload`, but for floating-point registers
1130(decl gen_fload (Value Offset32 MemFlags Type) FReg)
1131
1132;; Base case: nontrapping loads/stores use the `fload` helper which bottoms out
1133;; in `emit.rs` using the `*_o32` addressing mode.
1134(rule 0 (gen_fload addr offset flags ty)
1135  (if-let true (memflags_nontrapping flags))
1136  (pulley_fload (amode addr offset) ty flags))
1137
1138;; Base case: use trapping loads stores with the `*_z` addressing mode for
1139;; wasm-looking loads/stores.
1140(rule 1 (gen_fload addr offset flags ty)
1141  (if-let true (memflags_is_wasm flags))
1142  (emit_addrz_fload (addrz addr offset) ty))
1143
1144(decl emit_addrz_fload (AddrZ Type) FReg)
1145(rule (emit_addrz_fload addr $F32) (pulley_fload32le_z addr))
1146(rule (emit_addrz_fload addr $F64) (pulley_fload64le_z addr))
1147
1148;; Special case: use `*_g32` addressing when the bounds-check can be
1149;; pattern-matched.
1150(rule 2 (gen_fload addr offset flags ty)
1151  (if-let addrg32 (wasm_g32 addr offset flags ty))
1152  (emit_addrg32_fload addrg32 ty))
1153
1154(decl emit_addrg32_fload (AddrG32 Type) FReg)
1155(rule (emit_addrg32_fload addr $F32) (pulley_fload32le_g32 addr))
1156(rule (emit_addrg32_fload addr $F64) (pulley_fload64le_g32 addr))
1157
1158;; Analog of `gen_xload`, but for vector registers.
1159(decl gen_vload (Value Offset32 MemFlags Type VExtKind) VReg)
1160
1161;; Base case: nontrapping loads/stores use the `*_o32` addressing mode through
1162;; helpers in `emit.rs` and the `pulley_vload` pseudo-inst. Note that this
1163;; intentionally doesn't support all extension kinds.
1164(rule 0 (gen_vload addr offset flags ty (VExtKind.None))
1165  (if-let true (memflags_nontrapping flags))
1166  (pulley_vload (amode addr offset) ty flags))
1167
1168;; Base case: wasm loads/stores using the `*_z` addressing mode.
1169(rule 1 (gen_vload addr offset flags ty ext)
1170  (if-let true (memflags_is_wasm flags))
1171  (emit_addrz_vload (addrz addr offset) ty ext))
1172
1173(decl emit_addrz_vload (AddrZ Type VExtKind) VReg)
1174(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.None)) (pulley_vload128le_z addr))
1175(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.S8x8)) (pulley_vload8x8_s_z addr))
1176(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.U8x8)) (pulley_vload8x8_u_z addr))
1177(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.S16x4)) (pulley_vload16x4le_s_z addr))
1178(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.U16x4)) (pulley_vload16x4le_u_z addr))
1179(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.S32x2)) (pulley_vload32x2le_s_z addr))
1180(rule (emit_addrz_vload addr (ty_vec128 _) (VExtKind.U32x2)) (pulley_vload32x2le_u_z addr))
1181
1182;; Special case: use `*_g32` addressing when the bounds-check can be
1183;; pattern-matched.
1184(rule 2 (gen_vload addr offset flags (ty_vec128 ty) (VExtKind.None))
1185  (if-let addrg32 (wasm_g32 addr offset flags ty))
1186  (pulley_vload128le_g32 addrg32))
1187
1188;;;; Rules for `store` and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1189
1190(rule (lower (store flags src @ (value_type (ty_int (fits_in_64 ty))) addr offset))
1191  (side_effect (gen_store src addr offset flags ty)))
1192
1193(rule 1 (lower (store flags src @ (value_type (ty_scalar_float ty)) addr offset))
1194  (side_effect (gen_store src addr offset flags ty)))
1195
1196(rule (lower (istore8 flags src addr offset))
1197  (side_effect (gen_store src addr offset flags $I8)))
1198
1199(rule (lower (istore16 flags src addr offset))
1200  (side_effect (gen_store src addr offset flags $I16)))
1201
1202(rule (lower (istore32 flags src addr offset))
1203  (side_effect (gen_store src addr offset flags $I32)))
1204
1205(rule 2 (lower (store flags src @ (value_type (ty_vec128 ty)) addr offset))
1206  (side_effect (gen_store src addr offset flags ty)))
1207
1208;; i128 stores
1209
1210(rule 3 (lower (store flags src @ (value_type $I128) addr offset))
1211  (let
1212    ((src_regs ValueRegs src)
1213      (src_lo XReg (value_regs_get src_regs 0))
1214      (src_hi XReg (value_regs_get src_regs 1))
1215      (addrp0 XReg addr)
1216      (addrp8 Amode (Amode.RegOffset addrp0 8)))
1217  (side_effect (emit_store_i128 flags src_lo src_hi (Amode.RegOffset addrp0 0) addrp8))))
1218
1219;; Helper to handle big/little endian to determine which order the lo/hi
1220;; halves of the i128 are stored.
1221(decl emit_store_i128 (MemFlags XReg XReg Amode Amode) SideEffectNoResult)
1222(rule 0 (emit_store_i128 flags lo hi addrp0 addrp8)
1223  (if-let (Endianness.Little) (endianness flags))
1224  (let ((_ InstOutput (side_effect (pulley_xstore addrp0 lo $I64 flags))))
1225    (pulley_xstore addrp8 hi $I64 flags)))
1226(rule 1 (emit_store_i128 flags lo hi addrp0 addrp8)
1227  (if-let (Endianness.Big) (endianness flags))
1228  (let ((_ InstOutput (side_effect (pulley_xstore addrp0 hi $I64 flags))))
1229    (pulley_xstore addrp8 lo $I64 flags)))
1230
1231;; Helper function to store the first argument into the second argument. This
1232;; only stores up to the width of the `Type` specified, regardless of what the
1233;; type of the first argument is.
1234(decl gen_store (Value Value Offset32 MemFlags Type) SideEffectNoResult)
1235
1236;; Base cases: normal typed loads/stores
1237(rule 0 (gen_store src addr offset flags (ty_int ty))
1238  (if-let true (memflags_nontrapping flags))
1239  (pulley_xstore (amode addr offset) src ty flags))
1240(rule 1 (gen_store src addr offset flags (ty_scalar_float ty))
1241  (if-let true (memflags_nontrapping flags))
1242  (pulley_fstore (amode addr offset) src ty flags))
1243(rule 2 (gen_store src addr offset flags (ty_vec128 ty))
1244  (if-let true (memflags_nontrapping flags))
1245  (pulley_vstore (amode addr offset) src ty flags))
1246
1247;; Base case: wasm stores
1248(rule 3 (gen_store src addr offset flags ty)
1249  (if-let true (memflags_is_wasm flags))
1250  (emit_addrz_store (addrz addr offset) src ty))
1251
1252(decl emit_addrz_store (AddrZ Value Type) SideEffectNoResult)
1253(rule (emit_addrz_store addr val $I8) (pulley_xstore8_z addr val))
1254(rule (emit_addrz_store addr val $I16) (pulley_xstore16le_z addr val))
1255(rule (emit_addrz_store addr val $I32) (pulley_xstore32le_z addr val))
1256(rule (emit_addrz_store addr val $I64) (pulley_xstore64le_z addr val))
1257(rule (emit_addrz_store addr val $F32) (pulley_fstore32le_z addr val))
1258(rule (emit_addrz_store addr val $F64) (pulley_fstore64le_z addr val))
1259(rule 1 (emit_addrz_store addr val (ty_vec128 _)) (pulley_vstore128le_z addr val))
1260
1261;; special case: wasm stores with a folded bounds check
1262(rule 4 (gen_store src addr offset flags ty)
1263  (if-let addrg32 (wasm_g32 addr offset flags ty))
1264  (emit_addrg32_store addrg32 src ty))
1265
1266(decl emit_addrg32_store (AddrG32 Value Type) SideEffectNoResult)
1267(rule (emit_addrg32_store addr val $I8) (pulley_xstore8_g32 addr val))
1268(rule (emit_addrg32_store addr val $I16) (pulley_xstore16le_g32 addr val))
1269(rule (emit_addrg32_store addr val $I32) (pulley_xstore32le_g32 addr val))
1270(rule (emit_addrg32_store addr val $I64) (pulley_xstore64le_g32 addr val))
1271(rule (emit_addrg32_store addr val $F32) (pulley_fstore32le_g32 addr val))
1272(rule (emit_addrg32_store addr val $F64) (pulley_fstore64le_g32 addr val))
1273(rule 1 (emit_addrg32_store addr val (ty_vec128 _)) (pulley_vstore128le_g32 addr val))
1274
1275;;;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1276
1277(rule (lower (stack_addr stack_slot offset))
1278      (lower_stack_addr stack_slot offset))
1279
1280(decl lower_stack_addr (StackSlot Offset32) XReg)
1281(rule (lower_stack_addr stack_slot offset)
1282      (let ((dst WritableXReg (temp_writable_xreg))
1283            (_ Unit (emit (abi_stackslot_addr dst stack_slot offset))))
1284        dst))
1285
1286;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1287
1288(rule 0 (lower (has_type (fits_in_32 _) (uextend val)))
1289  (zext32 val))
1290
1291(rule 1 (lower (has_type $I64 (uextend val)))
1292  (zext64 val))
1293
1294(rule 1 (lower (has_type $I128 (uextend val)))
1295  (value_regs (zext64 val) (pulley_xzero)))
1296
1297;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1298
1299(rule 0 (lower (has_type (fits_in_32 _) (sextend val)))
1300  (sext32 val))
1301
1302(rule 1 (lower (has_type $I64 (sextend val)))
1303  (sext64 val))
1304
1305(rule 1 (lower (has_type $I128 (sextend val)))
1306  (if-let (u6_from_u8 shift) (u64_try_into_u8 63))
1307  (let ((lo XReg (sext64 val))
1308        (hi XReg (pulley_xshr64_s_u6 lo shift)))
1309    (value_regs lo hi)))
1310
1311;;;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1312
1313(rule (lower (has_type (fits_in_64 _ty) (ireduce src)))
1314  src)
1315
1316;;;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1317
1318(rule (lower (has_type $I128 (iconcat a b)))
1319  (value_regs a b))
1320
1321;;;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1322
1323(rule (lower (isplit x @ (value_type $I128)))
1324  (let ((lo XReg (value_regs_get x 0))
1325        (hi XReg (value_regs_get x 1)))
1326    (output_pair lo hi)))
1327
1328;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1329
1330(rule (lower (has_type $I32 (uadd_overflow_trap a b tc)))
1331  (pulley_xadd32_uoverflow_trap a b tc))
1332
1333(rule (lower (has_type $I64 (uadd_overflow_trap a b tc)))
1334  (pulley_xadd64_uoverflow_trap a b tc))
1335
1336;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1337
1338(rule 0 (lower (has_type (ty_int (fits_in_32 _)) (select c a b)))
1339  (pulley_xselect32 (emit_cond (lower_cond c)) a b))
1340
1341(rule 1 (lower (has_type $I64 (select c a b)))
1342  (pulley_xselect64 (emit_cond (lower_cond c)) a b))
1343
1344(rule 1 (lower (has_type $F32 (select c a b)))
1345  (pulley_fselect32 (emit_cond (lower_cond c)) a b))
1346
1347(rule 1 (lower (has_type $F64 (select c a b)))
1348  (pulley_fselect64 (emit_cond (lower_cond c)) a b))
1349
1350(rule 2 (lower (has_type (ty_vec128 _) (select c a b)))
1351  (pulley_vselect (emit_cond (lower_cond c)) a b))
1352
1353;; Helper to emit a conditional into a register itself.
1354(decl emit_cond (Cond) XReg)
1355(rule (emit_cond (Cond.If32 reg)) reg)
1356(rule (emit_cond (Cond.IfNot32 reg)) (pulley_xeq32 reg (pulley_xconst8 0)))
1357(rule (emit_cond (Cond.IfXeq32 src1 src2)) (pulley_xeq32 src1 src2))
1358(rule (emit_cond (Cond.IfXneq32 src1 src2)) (pulley_xneq32 src1 src2))
1359(rule (emit_cond (Cond.IfXslt32 src1 src2)) (pulley_xslt32 src1 src2))
1360(rule (emit_cond (Cond.IfXslteq32 src1 src2)) (pulley_xslteq32 src1 src2))
1361(rule (emit_cond (Cond.IfXult32 src1 src2)) (pulley_xult32 src1 src2))
1362(rule (emit_cond (Cond.IfXulteq32 src1 src2)) (pulley_xulteq32 src1 src2))
1363(rule (emit_cond (Cond.IfXeq64 src1 src2)) (pulley_xeq64 src1 src2))
1364(rule (emit_cond (Cond.IfXneq64 src1 src2)) (pulley_xneq64 src1 src2))
1365(rule (emit_cond (Cond.IfXslt64 src1 src2)) (pulley_xslt64 src1 src2))
1366(rule (emit_cond (Cond.IfXslteq64 src1 src2)) (pulley_xslteq64 src1 src2))
1367(rule (emit_cond (Cond.IfXult64 src1 src2)) (pulley_xult64 src1 src2))
1368(rule (emit_cond (Cond.IfXulteq64 src1 src2)) (pulley_xulteq64 src1 src2))
1369
1370(rule (emit_cond (Cond.IfXeq32I32 src1 src2)) (pulley_xeq32 src1 (imm src2)))
1371(rule (emit_cond (Cond.IfXneq32I32 src1 src2)) (pulley_xneq32 src1 (imm src2)))
1372(rule (emit_cond (Cond.IfXslt32I32 src1 src2)) (pulley_xslt32 src1 (imm src2)))
1373(rule (emit_cond (Cond.IfXslteq32I32 src1 src2)) (pulley_xslteq32 src1 (imm src2)))
1374(rule (emit_cond (Cond.IfXult32I32 src1 src2)) (pulley_xult32 src1 (imm src2)))
1375(rule (emit_cond (Cond.IfXulteq32I32 src1 src2)) (pulley_xulteq32 src1 (imm src2)))
1376
1377;; Note the operand swaps here
1378(rule (emit_cond (Cond.IfXsgt32I32 src1 src2)) (pulley_xslt32 (imm src2) src1))
1379(rule (emit_cond (Cond.IfXsgteq32I32 src1 src2)) (pulley_xslteq32 (imm src2) src1))
1380(rule (emit_cond (Cond.IfXugt32I32 src1 src2)) (pulley_xult32 (imm src2) src1))
1381(rule (emit_cond (Cond.IfXugteq32I32 src1 src2)) (pulley_xulteq32 (imm src2) src1))
1382
1383(rule (emit_cond (Cond.IfXeq64I32 src1 src2)) (pulley_xeq64 src1 (imm src2)))
1384(rule (emit_cond (Cond.IfXneq64I32 src1 src2)) (pulley_xneq64 src1 (imm src2)))
1385(rule (emit_cond (Cond.IfXslt64I32 src1 src2)) (pulley_xslt64 src1 (imm src2)))
1386(rule (emit_cond (Cond.IfXslteq64I32 src1 src2)) (pulley_xslteq64 src1 (imm src2)))
1387(rule (emit_cond (Cond.IfXult64I32 src1 src2)) (pulley_xult64 src1 (imm src2)))
1388(rule (emit_cond (Cond.IfXulteq64I32 src1 src2)) (pulley_xulteq64 src1 (imm src2)))
1389
1390;; Note the operand swaps here
1391(rule (emit_cond (Cond.IfXsgt64I32 src1 src2)) (pulley_xslt64 (imm src2) src1))
1392(rule (emit_cond (Cond.IfXsgteq64I32 src1 src2)) (pulley_xslteq64 (imm src2) src1))
1393(rule (emit_cond (Cond.IfXugt64I32 src1 src2)) (pulley_xult64 (imm src2) src1))
1394(rule (emit_cond (Cond.IfXugteq64I32 src1 src2)) (pulley_xulteq64 (imm src2) src1))
1395
1396;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1397
1398(rule (lower (has_type $F32 (bitcast _flags val @ (value_type $I32))))
1399  (pulley_bitcast_float_from_int_32 val))
1400
1401(rule (lower (has_type $F64 (bitcast _flags val @ (value_type $I64))))
1402  (pulley_bitcast_float_from_int_64 val))
1403
1404(rule (lower (has_type $I32 (bitcast _flags val @ (value_type $F32))))
1405  (pulley_bitcast_int_from_float_32 val))
1406
1407(rule (lower (has_type $I64 (bitcast _flags val @ (value_type $F64))))
1408  (pulley_bitcast_int_from_float_64 val))
1409
1410(rule 1 (lower (has_type (ty_vec128 _) (bitcast _flags val @ (value_type (ty_vec128 _)))))
1411  val)
1412
1413(rule 2 (lower (has_type ty (bitcast _flags a @ (value_type ty)))) a)
1414
1415;;;; Rules for `fcvt_to_{u,s}int` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1416
1417(rule (lower (has_type $I32 (fcvt_to_uint val @ (value_type $F32))))
1418  (pulley_x32_from_f32_u val))
1419
1420(rule (lower (has_type $I32 (fcvt_to_uint val @ (value_type $F64))))
1421  (pulley_x32_from_f64_u val))
1422
1423(rule (lower (has_type $I64 (fcvt_to_uint val @ (value_type $F32))))
1424  (pulley_x64_from_f32_u val))
1425
1426(rule (lower (has_type $I64 (fcvt_to_uint val @ (value_type $F64))))
1427  (pulley_x64_from_f64_u val))
1428
1429(rule (lower (has_type $I32 (fcvt_to_sint val @ (value_type $F32))))
1430  (pulley_x32_from_f32_s val))
1431
1432(rule (lower (has_type $I32 (fcvt_to_sint val @ (value_type $F64))))
1433  (pulley_x32_from_f64_s val))
1434
1435(rule (lower (has_type $I64 (fcvt_to_sint val @ (value_type $F32))))
1436  (pulley_x64_from_f32_s val))
1437
1438(rule (lower (has_type $I64 (fcvt_to_sint val @ (value_type $F64))))
1439  (pulley_x64_from_f64_s val))
1440
1441;;;; Rules for `fcvt_from_{u,s}int` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1442
1443(rule 0 (lower (has_type $F32 (fcvt_from_uint val @ (value_type (fits_in_32 _)))))
1444  (pulley_f32_from_x32_u (zext32 val)))
1445
1446(rule 1 (lower (has_type $F32 (fcvt_from_uint val @ (value_type $I64))))
1447  (pulley_f32_from_x64_u val))
1448
1449(rule 0 (lower (has_type $F64 (fcvt_from_uint val @ (value_type (fits_in_32 _)))))
1450  (pulley_f64_from_x32_u (zext32 val)))
1451
1452(rule 1 (lower (has_type $F64 (fcvt_from_uint val @ (value_type $I64))))
1453  (pulley_f64_from_x64_u val))
1454
1455(rule 0 (lower (has_type $F32 (fcvt_from_sint val @ (value_type (fits_in_32 _)))))
1456  (pulley_f32_from_x32_s (sext32 val)))
1457
1458(rule 1 (lower (has_type $F32 (fcvt_from_sint val @ (value_type $I64))))
1459  (pulley_f32_from_x64_s val))
1460
1461(rule 0 (lower (has_type $F64 (fcvt_from_sint val @ (value_type (fits_in_32 _)))))
1462  (pulley_f64_from_x32_s (sext32 val)))
1463
1464(rule 1 (lower (has_type $F64 (fcvt_from_sint val @ (value_type $I64))))
1465  (pulley_f64_from_x64_s val))
1466
1467(rule (lower (has_type $F32X4 (fcvt_from_sint val @ (value_type $I32X4))))
1468  (pulley_vf32x4_from_i32x4_s val))
1469
1470(rule (lower (has_type $F32X4 (fcvt_from_uint val @ (value_type $I32X4))))
1471  (pulley_vf32x4_from_i32x4_u val))
1472
1473(rule (lower (has_type $F64X2 (fcvt_from_sint val @ (value_type $I64X2))))
1474  (pulley_vf64x2_from_i64x2_s val))
1475
1476(rule (lower (has_type $F64X2 (fcvt_from_uint val @ (value_type $I64X2))))
1477  (pulley_vf64x2_from_i64x2_u val))
1478
1479;;;; Rules for `fcvt_to_{u,s}int_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1480
1481(rule (lower (has_type $I32 (fcvt_to_uint_sat val @ (value_type $F32))))
1482  (pulley_x32_from_f32_u_sat val))
1483
1484(rule (lower (has_type $I32 (fcvt_to_uint_sat val @ (value_type $F64))))
1485  (pulley_x32_from_f64_u_sat val))
1486
1487(rule (lower (has_type $I64 (fcvt_to_uint_sat val @ (value_type $F32))))
1488  (pulley_x64_from_f32_u_sat val))
1489
1490(rule (lower (has_type $I64 (fcvt_to_uint_sat val @ (value_type $F64))))
1491  (pulley_x64_from_f64_u_sat val))
1492
1493(rule (lower (has_type $I32 (fcvt_to_sint_sat val @ (value_type $F32))))
1494  (pulley_x32_from_f32_s_sat val))
1495
1496(rule (lower (has_type $I32 (fcvt_to_sint_sat val @ (value_type $F64))))
1497  (pulley_x32_from_f64_s_sat val))
1498
1499(rule (lower (has_type $I64 (fcvt_to_sint_sat val @ (value_type $F32))))
1500  (pulley_x64_from_f32_s_sat val))
1501
1502(rule (lower (has_type $I64 (fcvt_to_sint_sat val @ (value_type $F64))))
1503  (pulley_x64_from_f64_s_sat val))
1504
1505(rule (lower (has_type $I32X4 (fcvt_to_sint_sat val @ (value_type $F32X4))))
1506  (pulley_vi32x4_from_f32x4_s val))
1507
1508(rule (lower (has_type $I32X4 (fcvt_to_uint_sat val @ (value_type $F32X4))))
1509  (pulley_vi32x4_from_f32x4_u val))
1510
1511(rule (lower (has_type $I64X2 (fcvt_to_sint_sat val @ (value_type $F64X2))))
1512  (pulley_vi64x2_from_f64x2_s val))
1513
1514(rule (lower (has_type $I64X2 (fcvt_to_uint_sat val @ (value_type $F64X2))))
1515  (pulley_vi64x2_from_f64x2_u val))
1516
1517;;;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1518
1519(rule (lower (has_type $F32 (fdemote val @ (value_type $F64))))
1520  (pulley_f32_from_f64 val))
1521
1522;;;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1523
1524(rule (lower (has_type $F64 (fpromote val @ (value_type $F32))))
1525  (pulley_f64_from_f32 val))
1526
1527;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1528
1529(rule (lower (has_type $F32 (fcopysign a b)))
1530  (pulley_fcopysign32 a b))
1531
1532(rule (lower (has_type $F64 (fcopysign a b)))
1533  (pulley_fcopysign64 a b))
1534
1535;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1536
1537(rule (lower (has_type $F32 (fadd a b))) (pulley_fadd32 a b))
1538(rule (lower (has_type $F64 (fadd a b))) (pulley_fadd64 a b))
1539(rule (lower (has_type $F32X4 (fadd a b))) (pulley_vaddf32x4 a b))
1540(rule (lower (has_type $F64X2 (fadd a b))) (pulley_vaddf64x2 a b))
1541
1542;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1543
1544(rule (lower (has_type $F32 (fsub a b))) (pulley_fsub32 a b))
1545(rule (lower (has_type $F64 (fsub a b))) (pulley_fsub64 a b))
1546(rule (lower (has_type $F32X4 (fsub a b))) (pulley_vsubf32x4 a b))
1547(rule (lower (has_type $F64X2 (fsub a b))) (pulley_vsubf64x2 a b))
1548
1549;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1550
1551(rule (lower (has_type $F32 (fmul a b))) (pulley_fmul32 a b))
1552(rule (lower (has_type $F64 (fmul a b))) (pulley_fmul64 a b))
1553(rule (lower (has_type $F32X4 (fmul a b))) (pulley_vmulf32x4 a b))
1554(rule (lower (has_type $F64X2 (fmul a b))) (pulley_vmulf64x2 a b))
1555
1556;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1557
1558(rule (lower (has_type $F32 (fdiv a b))) (pulley_fdiv32 a b))
1559(rule (lower (has_type $F64 (fdiv a b))) (pulley_fdiv64 a b))
1560(rule (lower (has_type $F32X4 (fdiv a b))) (pulley_vdivf32x4 a b))
1561(rule (lower (has_type $F64X2 (fdiv a b))) (pulley_vdivf64x2 a b))
1562
1563;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1564
1565(rule (lower (has_type $F32 (fmax a b))) (pulley_fmaximum32 a b))
1566(rule (lower (has_type $F64 (fmax a b))) (pulley_fmaximum64 a b))
1567(rule (lower (has_type $F32X4 (fmax a b))) (pulley_vmaximumf32x4 a b))
1568(rule (lower (has_type $F64X2 (fmax a b))) (pulley_vmaximumf64x2 a b))
1569
1570;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1571
1572(rule (lower (has_type $F32 (fmin a b))) (pulley_fminimum32 a b))
1573(rule (lower (has_type $F64 (fmin a b))) (pulley_fminimum64 a b))
1574(rule (lower (has_type $F32X4 (fmin a b))) (pulley_vminimumf32x4 a b))
1575(rule (lower (has_type $F64X2 (fmin a b))) (pulley_vminimumf64x2 a b))
1576
1577;;;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1578
1579(rule (lower (has_type $F32 (trunc a))) (pulley_ftrunc32 a))
1580(rule (lower (has_type $F64 (trunc a))) (pulley_ftrunc64 a))
1581(rule (lower (has_type $F32X4 (trunc a))) (pulley_vtrunc32x4 a))
1582(rule (lower (has_type $F64X2 (trunc a))) (pulley_vtrunc64x2 a))
1583
1584;;;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1585
1586(rule (lower (has_type $F32 (floor a))) (pulley_ffloor32 a))
1587(rule (lower (has_type $F64 (floor a))) (pulley_ffloor64 a))
1588(rule (lower (has_type $F32X4 (floor a)))
1589      (pulley_vfloor32x4 a))
1590(rule (lower (has_type $F64X2 (floor a)))
1591      (pulley_vfloor64x2 a))
1592
1593;;;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1594
1595(rule (lower (has_type $F32 (ceil a))) (pulley_fceil32 a))
1596(rule (lower (has_type $F64 (ceil a))) (pulley_fceil64 a))
1597(rule (lower (has_type $F64X2 (ceil a)))
1598      (pulley_vceil64x2 a))
1599(rule (lower (has_type $F32X4 (ceil a)))
1600      (pulley_vceil32x4 a))
1601
1602;;;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1603
1604(rule (lower (has_type $F32 (nearest a))) (pulley_fnearest32 a))
1605(rule (lower (has_type $F64 (nearest a))) (pulley_fnearest64 a))
1606(rule (lower (has_type $F32X4 (nearest a)))
1607      (pulley_vnearest32x4 a))
1608(rule (lower (has_type $F64X2 (nearest a)))
1609      (pulley_vnearest64x2 a))
1610
1611;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1612
1613(rule (lower (has_type $F32 (sqrt a))) (pulley_fsqrt32 a))
1614(rule (lower (has_type $F64 (sqrt a))) (pulley_fsqrt64 a))
1615(rule (lower (has_type $F32X4 (sqrt a)))
1616      (pulley_vsqrt32x4 a))
1617(rule (lower (has_type $F64X2 (sqrt a)))
1618      (pulley_vsqrt64x2 a))
1619
1620;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1621
1622(rule (lower (has_type $F32 (fneg a))) (pulley_fneg32 a))
1623(rule (lower (has_type $F64 (fneg a))) (pulley_fneg64 a))
1624(rule (lower (has_type $F32X4 (fneg a))) (pulley_vnegf32x4 a))
1625(rule (lower (has_type $F64X2 (fneg a))) (pulley_vnegf64x2 a))
1626
1627;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1628
1629(rule 0 (lower (has_type (fits_in_32 _) (ineg a))) (pulley_xneg32 (sext32 a)))
1630(rule 1 (lower (has_type $I64 (ineg a))) (pulley_xneg64 a))
1631
1632;; vector negation
1633
1634(rule 1 (lower (has_type $I8X16 (ineg a))) (pulley_vneg8x16 a))
1635(rule 1 (lower (has_type $I16X8 (ineg a))) (pulley_vneg16x8 a))
1636(rule 1 (lower (has_type $I32X4 (ineg a))) (pulley_vneg32x4 a))
1637(rule 1 (lower (has_type $I64X2 (ineg a))) (pulley_vneg64x2 a))
1638
1639;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1640
1641(rule (lower (has_type $F32 (fabs a))) (pulley_fabs32 a))
1642(rule (lower (has_type $F64 (fabs a))) (pulley_fabs64 a))
1643(rule (lower (has_type $F32X4 (fabs a))) (pulley_vabsf32x4 a))
1644(rule (lower (has_type $F64X2 (fabs a))) (pulley_vabsf64x2 a))
1645
1646;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1647
1648(rule (lower (has_type (ty_vec128 _) (vconst (u128_from_constant a)))) (pulley_vconst128 a))
1649
1650;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1651
1652(rule (lower (has_type $I16 (bswap a)))
1653  (if-let (u6_from_u8 shift) (u64_try_into_u8 16))
1654  (pulley_xshr32_u_u6 (pulley_bswap32 a) shift))
1655(rule (lower (has_type $I32 (bswap a))) (pulley_bswap32 a))
1656(rule (lower (has_type $I64 (bswap a))) (pulley_bswap64 a))
1657
1658;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1659
1660(rule 0 (lower (has_type (fits_in_32 _) (iabs a))) (pulley_xabs32 (sext32 a)))
1661(rule 1 (lower (has_type $I64 (iabs a))) (pulley_xabs64 a))
1662(rule 1 (lower (has_type $I8X16 (iabs a))) (pulley_vabs8x16 a))
1663(rule 1 (lower (has_type $I16X8 (iabs a))) (pulley_vabs16x8 a))
1664(rule 1 (lower (has_type $I32X4 (iabs a))) (pulley_vabs32x4 a))
1665(rule 1 (lower (has_type $I64X2 (iabs a))) (pulley_vabs64x2 a))
1666
1667;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1668
1669(rule (lower (has_type $I8X16 (splat a))) (pulley_vsplatx8 a))
1670(rule (lower (has_type $I16X8 (splat a))) (pulley_vsplatx16 a))
1671(rule (lower (has_type $I32X4 (splat a))) (pulley_vsplatx32 a))
1672(rule (lower (has_type $I64X2 (splat a))) (pulley_vsplatx64 a))
1673(rule (lower (has_type $F32X4 (splat a))) (pulley_vsplatf32 a))
1674(rule (lower (has_type $F64X2 (splat a))) (pulley_vsplatf64 a))
1675
1676;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1677
1678(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I8X16))))
1679  (pulley_vbitmask8x16 a))
1680(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I16X8))))
1681  (pulley_vbitmask16x8 a))
1682(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I32X4))))
1683  (pulley_vbitmask32x4 a))
1684(rule (lower (has_type (fits_in_32 _) (vhigh_bits a @ (value_type $I64X2))))
1685  (pulley_vbitmask64x2 a))
1686
1687;;;; Rules for `vall_true`; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1688
1689(rule (lower (vall_true a @ (value_type $I8X16))) (pulley_valltrue8x16 a))
1690(rule (lower (vall_true a @ (value_type $I16X8))) (pulley_valltrue16x8 a))
1691(rule (lower (vall_true a @ (value_type $I32X4))) (pulley_valltrue32x4 a))
1692(rule (lower (vall_true a @ (value_type $I64X2))) (pulley_valltrue64x2 a))
1693(rule (lower (vall_true a @ (value_type $F32X4))) (pulley_valltrue32x4 a))
1694(rule (lower (vall_true a @ (value_type $F64X2))) (pulley_valltrue64x2 a))
1695
1696;;;; Rules for `vany_true`; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1697
1698(rule (lower (vany_true a @ (value_type $I8X16))) (pulley_vanytrue8x16 a))
1699(rule (lower (vany_true a @ (value_type $I16X8))) (pulley_vanytrue16x8 a))
1700(rule (lower (vany_true a @ (value_type $I32X4))) (pulley_vanytrue32x4 a))
1701(rule (lower (vany_true a @ (value_type $I64X2))) (pulley_vanytrue64x2 a))
1702(rule (lower (vany_true a @ (value_type $F32X4))) (pulley_vanytrue32x4 a))
1703(rule (lower (vany_true a @ (value_type $F64X2))) (pulley_vanytrue64x2 a))
1704
1705;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1706
1707(rule (lower (swiden_low a @ (value_type $I8X16))) (pulley_vwidenlow8x16_s a))
1708(rule (lower (swiden_low a @ (value_type $I16X8))) (pulley_vwidenlow16x8_s a))
1709(rule (lower (swiden_low a @ (value_type $I32X4))) (pulley_vwidenlow32x4_s a))
1710
1711;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1712
1713(rule (lower (swiden_high a @ (value_type $I8X16))) (pulley_vwidenhigh8x16_s a))
1714(rule (lower (swiden_high a @ (value_type $I16X8))) (pulley_vwidenhigh16x8_s a))
1715(rule (lower (swiden_high a @ (value_type $I32X4))) (pulley_vwidenhigh32x4_s a))
1716
1717;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1718
1719(rule (lower (uwiden_low a @ (value_type $I8X16))) (pulley_vwidenlow8x16_u a))
1720(rule (lower (uwiden_low a @ (value_type $I16X8))) (pulley_vwidenlow16x8_u a))
1721(rule (lower (uwiden_low a @ (value_type $I32X4))) (pulley_vwidenlow32x4_u a))
1722
1723;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1724
1725(rule (lower (uwiden_high a @ (value_type $I8X16))) (pulley_vwidenhigh8x16_u a))
1726(rule (lower (uwiden_high a @ (value_type $I16X8))) (pulley_vwidenhigh16x8_u a))
1727(rule (lower (uwiden_high a @ (value_type $I32X4))) (pulley_vwidenhigh32x4_u a))
1728
1729;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1730
1731(rule (lower (snarrow a @ (value_type $I16X8) b)) (pulley_vnarrow16x8_s a b))
1732(rule (lower (snarrow a @ (value_type $I32X4) b)) (pulley_vnarrow32x4_s a b))
1733(rule (lower (snarrow a @ (value_type $I64X2) b)) (pulley_vnarrow64x2_s a b))
1734
1735;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1736
1737(rule (lower (unarrow a @ (value_type $I16X8) b)) (pulley_vnarrow16x8_u a b))
1738(rule (lower (unarrow a @ (value_type $I32X4) b)) (pulley_vnarrow32x4_u a b))
1739
1740;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1741
1742(rule (lower (uunarrow a @ (value_type $I64X2) b)) (pulley_vunarrow64x2_u a b))
1743
1744;;;; Rules for `fvpromote_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1745
1746(rule (lower (fvpromote_low a @ (value_type $F32X4))) (pulley_vfpromotelow a))
1747
1748;;;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1749
1750(rule (lower (fvdemote a @ (value_type $F64X2))) (pulley_vfdemote a))
1751
1752;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1753
1754(rule (lower (extractlane a @ (value_type $I8X16) (u8_from_uimm8 lane)))
1755  (pulley_xextractv8x16 a lane))
1756(rule (lower (extractlane a @ (value_type $I16X8) (u8_from_uimm8 lane)))
1757  (pulley_xextractv16x8 a lane))
1758(rule (lower (extractlane a @ (value_type $I32X4) (u8_from_uimm8 lane)))
1759  (pulley_xextractv32x4 a lane))
1760(rule (lower (extractlane a @ (value_type $I64X2) (u8_from_uimm8 lane)))
1761  (pulley_xextractv64x2 a lane))
1762(rule (lower (extractlane a @ (value_type $F32X4) (u8_from_uimm8 lane)))
1763  (pulley_fextractv32x4 a lane))
1764(rule (lower (extractlane a @ (value_type $F64X2) (u8_from_uimm8 lane)))
1765  (pulley_fextractv64x2 a lane))
1766
1767;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1768
1769(rule (lower (insertlane a @ (value_type $I8X16) b (u8_from_uimm8 lane)))
1770  (pulley_vinsertx8 a b lane))
1771(rule (lower (insertlane a @ (value_type $I16X8) b (u8_from_uimm8 lane)))
1772  (pulley_vinsertx16 a b lane))
1773(rule (lower (insertlane a @ (value_type $I32X4) b (u8_from_uimm8 lane)))
1774  (pulley_vinsertx32 a b lane))
1775(rule (lower (insertlane a @ (value_type $I64X2) b (u8_from_uimm8 lane)))
1776  (pulley_vinsertx64 a b lane))
1777(rule (lower (insertlane a @ (value_type $F32X4) b (u8_from_uimm8 lane)))
1778  (pulley_vinsertf32 a b lane))
1779(rule (lower (insertlane a @ (value_type $F64X2) b (u8_from_uimm8 lane)))
1780  (pulley_vinsertf64 a b lane))
1781
1782;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1783
1784;; Note that this doesn't use special pulley instructions at this time and
1785;; generates a bytecode-wise relatively inefficient lowering. Should be
1786;; relatively easy to optimize if necessary in the future.
1787
1788(rule (lower (scalar_to_vector a @ (value_type $I8)))
1789  (pulley_vinsertx8 (pulley_vconst128 0) a 0))
1790(rule (lower (scalar_to_vector a @ (value_type $I16)))
1791  (pulley_vinsertx16 (pulley_vconst128 0) a 0))
1792(rule (lower (scalar_to_vector a @ (value_type $I32)))
1793  (pulley_vinsertx32 (pulley_vconst128 0) a 0))
1794(rule (lower (scalar_to_vector a @ (value_type $I64)))
1795  (pulley_vinsertx64 (pulley_vconst128 0) a 0))
1796(rule (lower (scalar_to_vector a @ (value_type $F32)))
1797  (pulley_vinsertf32 (pulley_vconst128 0) a 0))
1798(rule (lower (scalar_to_vector a @ (value_type $F64)))
1799  (pulley_vinsertf64 (pulley_vconst128 0) a 0))
1800
1801;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1802
1803(rule (lower (has_type $I8X16 (shuffle a b (u128_from_immediate mask))))
1804  (pulley_vshuffle a b mask))
1805
1806;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1807
1808(rule 1 (lower (has_type $I8X16 (swizzle a b))) (pulley_vswizzlei8x16 a b))
1809
1810;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1811
1812(rule (lower (has_type $F32X4 (fma a b c))) (pulley_vfma32x4 a b c))
1813(rule (lower (has_type $F64X2 (fma a b c))) (pulley_vfma64x2 a b c))
1814