1// WebAssemblyInstrSIMD.td - WebAssembly SIMD codegen support -*- tablegen -*-//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// WebAssembly SIMD operand code-gen constructs.
12///
13//===----------------------------------------------------------------------===//
14
15// constrained immediate argument types
16foreach SIZE = [8, 16] in
17def ImmI#SIZE : ImmLeaf<i32, "return (Imm & ((1UL << "#SIZE#") - 1)) == Imm;">;
18foreach SIZE = [2, 4, 8, 16, 32] in
19def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">;
20
21// const vectors
22multiclass ConstVec<ValueType vec_t, dag ops, dag pat, string args> {
23  defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops,
24                                  [(set V128:$dst, (vec_t pat))],
25                                  "v128.const\t$dst, "#args,
26                                  "v128.const\t"#args, 0>;
27}
28defm "" : ConstVec<v16i8,
29                   (ins vec_i8imm_op:$i0, vec_i8imm_op:$i1,
30                        vec_i8imm_op:$i2, vec_i8imm_op:$i3,
31                        vec_i8imm_op:$i4, vec_i8imm_op:$i5,
32                        vec_i8imm_op:$i6, vec_i8imm_op:$i7,
33                        vec_i8imm_op:$i8, vec_i8imm_op:$i9,
34                        vec_i8imm_op:$iA, vec_i8imm_op:$iB,
35                        vec_i8imm_op:$iC, vec_i8imm_op:$iD,
36                        vec_i8imm_op:$iE, vec_i8imm_op:$iF),
37                   (build_vector ImmI8:$i0, ImmI8:$i1, ImmI8:$i2, ImmI8:$i3,
38                                 ImmI8:$i4, ImmI8:$i5, ImmI8:$i6, ImmI8:$i7,
39                                 ImmI8:$i8, ImmI8:$i9, ImmI8:$iA, ImmI8:$iB,
40                                 ImmI8:$iC, ImmI8:$iD, ImmI8:$iE, ImmI8:$iF),
41                   !strconcat("$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7, ",
42                              "$i8, $i9, $iA, $iB, $iC, $iD, $iE, $iF")>;
43defm "" : ConstVec<v8i16,
44                   (ins vec_i16imm_op:$i0, vec_i16imm_op:$i1,
45                        vec_i16imm_op:$i2, vec_i16imm_op:$i3,
46                        vec_i16imm_op:$i4, vec_i16imm_op:$i5,
47                        vec_i16imm_op:$i6, vec_i16imm_op:$i7),
48                   (build_vector
49                     ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3,
50                     ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7),
51                   "$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">;
52defm "" : ConstVec<v4i32,
53                   (ins vec_i32imm_op:$i0, vec_i32imm_op:$i1,
54                        vec_i32imm_op:$i2, vec_i32imm_op:$i3),
55                   (build_vector (i32 imm:$i0), (i32 imm:$i1),
56                                 (i32 imm:$i2), (i32 imm:$i3)),
57                   "$i0, $i1, $i2, $i3">;
58defm "" : ConstVec<v2i64,
59                  (ins vec_i64imm_op:$i0, vec_i64imm_op:$i1),
60                  (build_vector (i64 imm:$i0), (i64 imm:$i1)),
61                  "$i0, $i1">;
62defm "" : ConstVec<v4f32,
63                   (ins f32imm_op:$i0, f32imm_op:$i1,
64                        f32imm_op:$i2, f32imm_op:$i3),
65                   (build_vector (f32 fpimm:$i0), (f32 fpimm:$i1),
66                                 (f32 fpimm:$i2), (f32 fpimm:$i3)),
67                   "$i0, $i1, $i2, $i3">;
68defm "" : ConstVec<v2f64,
69                  (ins f64imm_op:$i0, f64imm_op:$i1),
70                  (build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)),
71                  "$i0, $i1">;
72
73// lane extraction
74multiclass ExtractLane<ValueType vec_t, string vec, ImmLeaf imm_t,
75                       WebAssemblyRegClass reg_t, bits<32> simdop,
76                       string suffix = "", SDNode extract = vector_extract> {
77  defm EXTRACT_LANE_#vec_t#suffix :
78      SIMD_I<(outs reg_t:$dst), (ins V128:$vec, i32imm_op:$idx),
79             (outs), (ins i32imm_op:$idx),
80             [(set reg_t:$dst, (extract (vec_t V128:$vec), (i32 imm_t:$idx)))],
81             vec#".extract_lane"#suffix#"\t$dst, $vec, $idx",
82             vec#".extract_lane"#suffix#"\t$idx", simdop>;
83}
84multiclass ExtractPat<ValueType lane_t, int mask> {
85  def _s : PatFrag<(ops node:$vec, node:$idx),
86                   (i32 (sext_inreg
87                     (i32 (vector_extract
88                       node:$vec,
89                       node:$idx
90                     )),
91                     lane_t
92                   ))>;
93  def _u : PatFrag<(ops node:$vec, node:$idx),
94                   (i32 (and
95                     (i32 (vector_extract
96                       node:$vec,
97                       node:$idx
98                     )),
99                     (i32 mask)
100                   ))>;
101}
102defm extract_i8x16 : ExtractPat<i8, 0xff>;
103defm extract_i16x8 : ExtractPat<i16, 0xffff>;
104multiclass ExtractLaneExtended<string sign, bits<32> baseInst> {
105  defm "" : ExtractLane<v16i8, "i8x16", LaneIdx16, I32,  baseInst, sign,
106                        !cast<PatFrag>("extract_i8x16"#sign)>;
107  defm "" : ExtractLane<v8i16, "i16x8", LaneIdx8, I32, !add(baseInst, 2), sign,
108                        !cast<PatFrag>("extract_i16x8"#sign)>;
109}
110let Defs = [ARGUMENTS] in {
111defm "" : ExtractLaneExtended<"_s", 9>;
112defm "" : ExtractLaneExtended<"_u", 10>;
113defm "" : ExtractLane<v4i32, "i32x4", LaneIdx4, I32, 13>;
114defm "" : ExtractLane<v2i64, "i64x2", LaneIdx2, I64, 14>;
115defm "" : ExtractLane<v4f32, "f32x4", LaneIdx4, F32, 15>;
116defm "" : ExtractLane<v2f64, "f64x2", LaneIdx2, F64, 16>;
117} // Defs = [ARGUMENTS]
118
119// follow convention of making implicit expansions unsigned
120def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))),
121          (EXTRACT_LANE_v16i8_u V128:$vec, (i32 LaneIdx16:$idx))>;
122def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))),
123          (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>;
124
125// lane replacement
126multiclass ReplaceLane<ValueType vec_t, string vec, WebAssemblyRegClass reg_t,
127                       ValueType lane_t, ImmLeaf imm_t, bits<32> simdop> {
128  defm REPLACE_LANE_#vec_t :
129      SIMD_I<(outs V128:$dst), (ins V128:$vec, i32imm_op:$idx, reg_t:$x),
130             (outs), (ins i32imm_op:$idx),
131             [(set V128:$dst, (vector_insert
132               (vec_t V128:$vec), (lane_t reg_t:$x), (i32 imm_t:$idx)))],
133             vec#".replace_lane\t$dst, $vec, $idx, $x",
134             vec#".replace_lane\t$idx", simdop>;
135}
136let Defs = [ARGUMENTS] in {
137defm "" : ReplaceLane<v16i8, "i8x16", I32, i32, LaneIdx16, 17>;
138defm "" : ReplaceLane<v8i16, "i16x8", I32, i32, LaneIdx8, 18>;
139defm "" : ReplaceLane<v4i32, "i32x4", I32, i32, LaneIdx4, 19>;
140defm "" : ReplaceLane<v2i64, "i64x2", I64, i64, LaneIdx2, 20>;
141defm "" : ReplaceLane<v4f32, "f32x4", F32, f32, LaneIdx4, 21>;
142defm "" : ReplaceLane<v2f64, "f64x2", F64, f64, LaneIdx2, 22>;
143} // Defs = [ARGUMENTS]
144
145// splats
146def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>;
147def splat4 : PatFrag<(ops node:$x), (build_vector
148                       node:$x, node:$x, node:$x, node:$x)>;
149def splat8 : PatFrag<(ops node:$x), (build_vector
150                       node:$x, node:$x, node:$x, node:$x,
151                       node:$x, node:$x, node:$x, node:$x)>;
152def splat16 : PatFrag<(ops node:$x), (build_vector
153                        node:$x, node:$x, node:$x, node:$x,
154                        node:$x, node:$x, node:$x, node:$x,
155                        node:$x, node:$x, node:$x, node:$x,
156                        node:$x, node:$x, node:$x, node:$x)>;
157multiclass Splat<ValueType vec_t, string vec, WebAssemblyRegClass reg_t,
158                 PatFrag splat_pat, bits<32> simdop> {
159  defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins),
160                             [(set (vec_t V128:$dst), (splat_pat reg_t:$x))],
161                             vec#".splat\t$dst, $x", vec#".splat", simdop>;
162}
163let Defs = [ARGUMENTS] in {
164defm "" : Splat<v16i8, "i8x16", I32, splat16, 3>;
165defm "" : Splat<v8i16, "i16x8", I32, splat8, 4>;
166defm "" : Splat<v4i32, "i32x4", I32, splat4, 5>;
167defm "" : Splat<v2i64, "i64x2", I64, splat2, 6>;
168defm "" : Splat<v4f32, "f32x4", F32, splat4, 7>;
169defm "" : Splat<v2f64, "f64x2", F64, splat2, 8>;
170} // Defs = [ARGUMENTS]
171
172// arbitrary other BUILD_VECTOR patterns
173def : Pat<(v16i8 (build_vector
174            (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3),
175            (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7),
176            (i32 I32:$x8), (i32 I32:$x9), (i32 I32:$x10), (i32 I32:$x11),
177            (i32 I32:$x12), (i32 I32:$x13), (i32 I32:$x14), (i32 I32:$x15)
178          )),
179          (v16i8 (REPLACE_LANE_v16i8
180            (v16i8 (REPLACE_LANE_v16i8
181              (v16i8 (REPLACE_LANE_v16i8
182                (v16i8 (REPLACE_LANE_v16i8
183                  (v16i8 (REPLACE_LANE_v16i8
184                    (v16i8 (REPLACE_LANE_v16i8
185                      (v16i8 (REPLACE_LANE_v16i8
186                        (v16i8 (REPLACE_LANE_v16i8
187                          (v16i8 (REPLACE_LANE_v16i8
188                            (v16i8 (REPLACE_LANE_v16i8
189                              (v16i8 (REPLACE_LANE_v16i8
190                                (v16i8 (REPLACE_LANE_v16i8
191                                  (v16i8 (REPLACE_LANE_v16i8
192                                    (v16i8 (REPLACE_LANE_v16i8
193                                      (v16i8 (REPLACE_LANE_v16i8
194                                        (v16i8 (SPLAT_v16i8 (i32 I32:$x0))),
195                                        1, I32:$x1
196                                      )),
197                                      2, I32:$x2
198                                    )),
199                                    3, I32:$x3
200                                  )),
201                                  4, I32:$x4
202                                )),
203                                5, I32:$x5
204                              )),
205                              6, I32:$x6
206                            )),
207                            7, I32:$x7
208                          )),
209                          8, I32:$x8
210                        )),
211                        9, I32:$x9
212                      )),
213                      10, I32:$x10
214                    )),
215                    11, I32:$x11
216                  )),
217                  12, I32:$x12
218                )),
219                13, I32:$x13
220              )),
221              14, I32:$x14
222            )),
223            15, I32:$x15
224          ))>;
225def : Pat<(v8i16 (build_vector
226            (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3),
227            (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7)
228          )),
229          (v8i16 (REPLACE_LANE_v8i16
230            (v8i16 (REPLACE_LANE_v8i16
231              (v8i16 (REPLACE_LANE_v8i16
232                (v8i16 (REPLACE_LANE_v8i16
233                  (v8i16 (REPLACE_LANE_v8i16
234                    (v8i16 (REPLACE_LANE_v8i16
235                      (v8i16 (REPLACE_LANE_v8i16
236                        (v8i16 (SPLAT_v8i16 (i32 I32:$x0))),
237                        1, I32:$x1
238                      )),
239                      2, I32:$x2
240                    )),
241                    3, I32:$x3
242                  )),
243                  4, I32:$x4
244                )),
245                5, I32:$x5
246              )),
247              6, I32:$x6
248            )),
249            7, I32:$x7
250          ))>;
251def : Pat<(v4i32 (build_vector
252            (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3)
253          )),
254          (v4i32 (REPLACE_LANE_v4i32
255            (v4i32 (REPLACE_LANE_v4i32
256              (v4i32 (REPLACE_LANE_v4i32
257                (v4i32 (SPLAT_v4i32 (i32 I32:$x0))),
258                1, I32:$x1
259              )),
260              2, I32:$x2
261            )),
262            3, I32:$x3
263          ))>;
264def : Pat<(v2i64 (build_vector (i64 I64:$x0), (i64 I64:$x1))),
265          (v2i64 (REPLACE_LANE_v2i64
266            (v2i64 (SPLAT_v2i64 (i64 I64:$x0))), 1, I64:$x1))>;
267def : Pat<(v4f32 (build_vector
268            (f32 F32:$x0), (f32 F32:$x1), (f32 F32:$x2), (f32 F32:$x3)
269          )),
270          (v4f32 (REPLACE_LANE_v4f32
271            (v4f32 (REPLACE_LANE_v4f32
272              (v4f32 (REPLACE_LANE_v4f32
273                (v4f32 (SPLAT_v4f32 (f32 F32:$x0))),
274                1, F32:$x1
275              )),
276              2, F32:$x2
277            )),
278            3, F32:$x3
279          ))>;
280def : Pat<(v2f64 (build_vector (f64 F64:$x0), (f64 F64:$x1))),
281          (v2f64 (REPLACE_LANE_v2f64
282            (v2f64 (SPLAT_v2f64 (f64 F64:$x0))), 1, F64:$x1))>;
283
284// arithmetic
285let Defs = [ARGUMENTS] in {
286let isCommutable = 1 in
287defm ADD : SIMDBinaryInt<add, "add ", 24>;
288defm SUB : SIMDBinaryInt<sub, "sub ", 28>;
289let isCommutable = 1 in
290defm MUL : SIMDBinaryIntNoI64x2<mul, "mul ", 32>;
291
292let isCommutable = 1 in
293defm ADD : SIMDBinaryFP<fadd, "add ", 122>;
294defm SUB : SIMDBinaryFP<fsub, "sub ", 124>;
295defm DIV : SIMDBinaryFP<fdiv, "div ", 126>;
296let isCommutable = 1 in
297defm MUL : SIMDBinaryFP<fmul, "mul ", 128>;
298} // Defs = [ARGUMENTS]
299