/src/WasmEdge/lib/llvm/compiler/vectorInstr.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "compiler/function_compiler.h" |
5 | | |
6 | | #include <array> |
7 | | #include <limits> |
8 | | #include <numeric> |
9 | | |
10 | | namespace WasmEdge { |
11 | | |
12 | | Expect<void> |
13 | 117k | FunctionCompiler::compileVectorOp(const AST::Instruction &Instr) noexcept { |
14 | 117k | switch (Instr.getOpCode()) { |
15 | 4.87k | case OpCode::V128__load: |
16 | 4.87k | compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
17 | 4.87k | Instr.getMemoryAlign(), Context.Int128x1Ty); |
18 | 4.87k | break; |
19 | 221 | case OpCode::V128__load8x8_s: |
20 | 221 | compileVectorLoadOp( |
21 | 221 | Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(), |
22 | 221 | LLVM::Type::getVectorType(Context.Int8Ty, 8), Context.Int16x8Ty, true); |
23 | 221 | break; |
24 | 46 | case OpCode::V128__load8x8_u: |
25 | 46 | compileVectorLoadOp( |
26 | 46 | Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(), |
27 | 46 | LLVM::Type::getVectorType(Context.Int8Ty, 8), Context.Int16x8Ty, false); |
28 | 46 | break; |
29 | 310 | case OpCode::V128__load16x4_s: |
30 | 310 | compileVectorLoadOp( |
31 | 310 | Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(), |
32 | 310 | LLVM::Type::getVectorType(Context.Int16Ty, 4), Context.Int32x4Ty, true); |
33 | 310 | break; |
34 | 501 | case OpCode::V128__load16x4_u: |
35 | 501 | compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
36 | 501 | Instr.getMemoryAlign(), |
37 | 501 | LLVM::Type::getVectorType(Context.Int16Ty, 4), |
38 | 501 | Context.Int32x4Ty, false); |
39 | 501 | break; |
40 | 136 | case OpCode::V128__load32x2_s: |
41 | 136 | compileVectorLoadOp( |
42 | 136 | Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(), |
43 | 136 | LLVM::Type::getVectorType(Context.Int32Ty, 2), Context.Int64x2Ty, true); |
44 | 136 | break; |
45 | 182 | case OpCode::V128__load32x2_u: |
46 | 182 | compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
47 | 182 | Instr.getMemoryAlign(), |
48 | 182 | LLVM::Type::getVectorType(Context.Int32Ty, 2), |
49 | 182 | Context.Int64x2Ty, false); |
50 | 182 | break; |
51 | 75 | case OpCode::V128__load8_splat: |
52 | 75 | compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
53 | 75 | Instr.getMemoryAlign(), Context.Int8Ty, |
54 | 75 | Context.Int8x16Ty); |
55 | 75 | break; |
56 | 136 | case OpCode::V128__load16_splat: |
57 | 136 | compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
58 | 136 | Instr.getMemoryAlign(), Context.Int16Ty, |
59 | 136 | Context.Int16x8Ty); |
60 | 136 | break; |
61 | 182 | case OpCode::V128__load32_splat: |
62 | 182 | compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
63 | 182 | Instr.getMemoryAlign(), Context.Int32Ty, |
64 | 182 | Context.Int32x4Ty); |
65 | 182 | break; |
66 | 157 | case OpCode::V128__load64_splat: |
67 | 157 | compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
68 | 157 | Instr.getMemoryAlign(), Context.Int64Ty, |
69 | 157 | Context.Int64x2Ty); |
70 | 157 | break; |
71 | 80 | case OpCode::V128__load32_zero: |
72 | 80 | compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
73 | 80 | Instr.getMemoryAlign(), Context.Int32Ty, |
74 | 80 | Context.Int128Ty, false); |
75 | 80 | break; |
76 | 140 | case OpCode::V128__load64_zero: |
77 | 140 | compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
78 | 140 | Instr.getMemoryAlign(), Context.Int64Ty, |
79 | 140 | Context.Int128Ty, false); |
80 | 140 | break; |
81 | 235 | case OpCode::V128__store: |
82 | 235 | compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
83 | 235 | Instr.getMemoryAlign(), Context.Int128x1Ty, false, true); |
84 | 235 | break; |
85 | 216 | case OpCode::V128__load8_lane: |
86 | 216 | compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
87 | 216 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
88 | 216 | Context.Int8Ty, Context.Int8x16Ty); |
89 | 216 | break; |
90 | 148 | case OpCode::V128__load16_lane: |
91 | 148 | compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
92 | 148 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
93 | 148 | Context.Int16Ty, Context.Int16x8Ty); |
94 | 148 | break; |
95 | 112 | case OpCode::V128__load32_lane: |
96 | 112 | compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
97 | 112 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
98 | 112 | Context.Int32Ty, Context.Int32x4Ty); |
99 | 112 | break; |
100 | 22 | case OpCode::V128__load64_lane: |
101 | 22 | compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
102 | 22 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
103 | 22 | Context.Int64Ty, Context.Int64x2Ty); |
104 | 22 | break; |
105 | 169 | case OpCode::V128__store8_lane: |
106 | 169 | compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
107 | 169 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
108 | 169 | Context.Int8Ty, Context.Int8x16Ty); |
109 | 169 | break; |
110 | 80 | case OpCode::V128__store16_lane: |
111 | 80 | compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
112 | 80 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
113 | 80 | Context.Int16Ty, Context.Int16x8Ty); |
114 | 80 | break; |
115 | 106 | case OpCode::V128__store32_lane: |
116 | 106 | compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
117 | 106 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
118 | 106 | Context.Int32Ty, Context.Int32x4Ty); |
119 | 106 | break; |
120 | 35 | case OpCode::V128__store64_lane: |
121 | 35 | compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(), |
122 | 35 | Instr.getMemoryAlign(), Instr.getMemoryLane(), |
123 | 35 | Context.Int64Ty, Context.Int64x2Ty); |
124 | 35 | break; |
125 | | |
126 | | // SIMD Const Instructions |
127 | 353 | case OpCode::V128__const: { |
128 | 353 | const auto Value = Instr.getNum().get<uint64x2_t>(); |
129 | 353 | auto Vector = |
130 | 353 | LLVM::Value::getConstVector64(LLContext, {Value[0], Value[1]}); |
131 | 353 | stackPush(Builder.createBitCast(Vector, Context.Int64x2Ty)); |
132 | 353 | break; |
133 | 0 | } |
134 | | |
135 | | // SIMD Shuffle Instructions |
136 | 13 | case OpCode::I8x16__shuffle: { |
137 | 13 | auto V2 = Builder.createBitCast(stackPop(), Context.Int8x16Ty); |
138 | 13 | auto V1 = Builder.createBitCast(stackPop(), Context.Int8x16Ty); |
139 | 13 | const auto V3 = Instr.getNum().get<uint128_t>(); |
140 | 13 | std::array<uint8_t, 16> Mask; |
141 | 221 | for (size_t I = 0; I < 16; ++I) { |
142 | 208 | auto Num = static_cast<uint8_t>(V3 >> (I * 8)); |
143 | 208 | if constexpr (Endian::native == Endian::little) { |
144 | 208 | Mask[I] = Num; |
145 | | } else { |
146 | | Mask[15 - I] = Num < 16 ? 15 - Num : 47 - Num; |
147 | | } |
148 | 208 | } |
149 | 13 | stackPush(Builder.createBitCast( |
150 | 13 | Builder.createShuffleVector( |
151 | 13 | V1, V2, LLVM::Value::getConstVector8(LLContext, Mask)), |
152 | 13 | Context.Int64x2Ty)); |
153 | 13 | break; |
154 | 0 | } |
155 | | |
156 | | // SIMD Lane Instructions |
157 | 61 | case OpCode::I8x16__extract_lane_s: |
158 | 61 | compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(), |
159 | 61 | Context.Int32Ty, true); |
160 | 61 | break; |
161 | 28 | case OpCode::I8x16__extract_lane_u: |
162 | 28 | compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(), |
163 | 28 | Context.Int32Ty, false); |
164 | 28 | break; |
165 | 203 | case OpCode::I8x16__replace_lane: |
166 | 203 | compileReplaceLaneOp(Context.Int8x16Ty, Instr.getMemoryLane()); |
167 | 203 | break; |
168 | 447 | case OpCode::I16x8__extract_lane_s: |
169 | 447 | compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(), |
170 | 447 | Context.Int32Ty, true); |
171 | 447 | break; |
172 | 392 | case OpCode::I16x8__extract_lane_u: |
173 | 392 | compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(), |
174 | 392 | Context.Int32Ty, false); |
175 | 392 | break; |
176 | 367 | case OpCode::I16x8__replace_lane: |
177 | 367 | compileReplaceLaneOp(Context.Int16x8Ty, Instr.getMemoryLane()); |
178 | 367 | break; |
179 | 62 | case OpCode::I32x4__extract_lane: |
180 | 62 | compileExtractLaneOp(Context.Int32x4Ty, Instr.getMemoryLane()); |
181 | 62 | break; |
182 | 197 | case OpCode::I32x4__replace_lane: |
183 | 197 | compileReplaceLaneOp(Context.Int32x4Ty, Instr.getMemoryLane()); |
184 | 197 | break; |
185 | 126 | case OpCode::I64x2__extract_lane: |
186 | 126 | compileExtractLaneOp(Context.Int64x2Ty, Instr.getMemoryLane()); |
187 | 126 | break; |
188 | 11 | case OpCode::I64x2__replace_lane: |
189 | 11 | compileReplaceLaneOp(Context.Int64x2Ty, Instr.getMemoryLane()); |
190 | 11 | break; |
191 | 56 | case OpCode::F32x4__extract_lane: |
192 | 56 | compileExtractLaneOp(Context.Floatx4Ty, Instr.getMemoryLane()); |
193 | 56 | break; |
194 | 20 | case OpCode::F32x4__replace_lane: |
195 | 20 | compileReplaceLaneOp(Context.Floatx4Ty, Instr.getMemoryLane()); |
196 | 20 | break; |
197 | 68 | case OpCode::F64x2__extract_lane: |
198 | 68 | compileExtractLaneOp(Context.Doublex2Ty, Instr.getMemoryLane()); |
199 | 68 | break; |
200 | 7 | case OpCode::F64x2__replace_lane: |
201 | 7 | compileReplaceLaneOp(Context.Doublex2Ty, Instr.getMemoryLane()); |
202 | 7 | break; |
203 | | |
204 | | // SIMD Numeric Instructions |
205 | 89 | case OpCode::I8x16__swizzle: |
206 | 89 | compileVectorSwizzle(); |
207 | 89 | break; |
208 | 36.2k | case OpCode::I8x16__splat: |
209 | 36.2k | compileSplatOp(Context.Int8x16Ty); |
210 | 36.2k | break; |
211 | 8.37k | case OpCode::I16x8__splat: |
212 | 8.37k | compileSplatOp(Context.Int16x8Ty); |
213 | 8.37k | break; |
214 | 1.24k | case OpCode::I32x4__splat: |
215 | 1.24k | compileSplatOp(Context.Int32x4Ty); |
216 | 1.24k | break; |
217 | 526 | case OpCode::I64x2__splat: |
218 | 526 | compileSplatOp(Context.Int64x2Ty); |
219 | 526 | break; |
220 | 339 | case OpCode::F32x4__splat: |
221 | 339 | compileSplatOp(Context.Floatx4Ty); |
222 | 339 | break; |
223 | 60 | case OpCode::F64x2__splat: |
224 | 60 | compileSplatOp(Context.Doublex2Ty); |
225 | 60 | break; |
226 | 99 | case OpCode::I8x16__eq: |
227 | 99 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntEQ); |
228 | 99 | break; |
229 | 410 | case OpCode::I8x16__ne: |
230 | 410 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntNE); |
231 | 410 | break; |
232 | 63 | case OpCode::I8x16__lt_s: |
233 | 63 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLT); |
234 | 63 | break; |
235 | 65 | case OpCode::I8x16__lt_u: |
236 | 65 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULT); |
237 | 65 | break; |
238 | 221 | case OpCode::I8x16__gt_s: |
239 | 221 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGT); |
240 | 221 | break; |
241 | 212 | case OpCode::I8x16__gt_u: |
242 | 212 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGT); |
243 | 212 | break; |
244 | 110 | case OpCode::I8x16__le_s: |
245 | 110 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLE); |
246 | 110 | break; |
247 | 133 | case OpCode::I8x16__le_u: |
248 | 133 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULE); |
249 | 133 | break; |
250 | 530 | case OpCode::I8x16__ge_s: |
251 | 530 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGE); |
252 | 530 | break; |
253 | 92 | case OpCode::I8x16__ge_u: |
254 | 92 | compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGE); |
255 | 92 | break; |
256 | 167 | case OpCode::I16x8__eq: |
257 | 167 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntEQ); |
258 | 167 | break; |
259 | 175 | case OpCode::I16x8__ne: |
260 | 175 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntNE); |
261 | 175 | break; |
262 | 49 | case OpCode::I16x8__lt_s: |
263 | 49 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLT); |
264 | 49 | break; |
265 | 226 | case OpCode::I16x8__lt_u: |
266 | 226 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULT); |
267 | 226 | break; |
268 | 229 | case OpCode::I16x8__gt_s: |
269 | 229 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGT); |
270 | 229 | break; |
271 | 129 | case OpCode::I16x8__gt_u: |
272 | 129 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGT); |
273 | 129 | break; |
274 | 74 | case OpCode::I16x8__le_s: |
275 | 74 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLE); |
276 | 74 | break; |
277 | 81 | case OpCode::I16x8__le_u: |
278 | 81 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULE); |
279 | 81 | break; |
280 | 136 | case OpCode::I16x8__ge_s: |
281 | 136 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGE); |
282 | 136 | break; |
283 | 67 | case OpCode::I16x8__ge_u: |
284 | 67 | compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGE); |
285 | 67 | break; |
286 | 60 | case OpCode::I32x4__eq: |
287 | 60 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntEQ); |
288 | 60 | break; |
289 | 91 | case OpCode::I32x4__ne: |
290 | 91 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntNE); |
291 | 91 | break; |
292 | 48 | case OpCode::I32x4__lt_s: |
293 | 48 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLT); |
294 | 48 | break; |
295 | 128 | case OpCode::I32x4__lt_u: |
296 | 128 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULT); |
297 | 128 | break; |
298 | 201 | case OpCode::I32x4__gt_s: |
299 | 201 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGT); |
300 | 201 | break; |
301 | 221 | case OpCode::I32x4__gt_u: |
302 | 221 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGT); |
303 | 221 | break; |
304 | 258 | case OpCode::I32x4__le_s: |
305 | 258 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLE); |
306 | 258 | break; |
307 | 239 | case OpCode::I32x4__le_u: |
308 | 239 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULE); |
309 | 239 | break; |
310 | 65 | case OpCode::I32x4__ge_s: |
311 | 65 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGE); |
312 | 65 | break; |
313 | 158 | case OpCode::I32x4__ge_u: |
314 | 158 | compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGE); |
315 | 158 | break; |
316 | 122 | case OpCode::I64x2__eq: |
317 | 122 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntEQ); |
318 | 122 | break; |
319 | 48 | case OpCode::I64x2__ne: |
320 | 48 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntNE); |
321 | 48 | break; |
322 | 46 | case OpCode::I64x2__lt_s: |
323 | 46 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLT); |
324 | 46 | break; |
325 | 162 | case OpCode::I64x2__gt_s: |
326 | 162 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGT); |
327 | 162 | break; |
328 | 49 | case OpCode::I64x2__le_s: |
329 | 49 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLE); |
330 | 49 | break; |
331 | 73 | case OpCode::I64x2__ge_s: |
332 | 73 | compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGE); |
333 | 73 | break; |
334 | 1.34k | case OpCode::F32x4__eq: |
335 | 1.34k | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOEQ, Context.Int32x4Ty); |
336 | 1.34k | break; |
337 | 53 | case OpCode::F32x4__ne: |
338 | 53 | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealUNE, Context.Int32x4Ty); |
339 | 53 | break; |
340 | 710 | case OpCode::F32x4__lt: |
341 | 710 | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLT, Context.Int32x4Ty); |
342 | 710 | break; |
343 | 82 | case OpCode::F32x4__gt: |
344 | 82 | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOGT, Context.Int32x4Ty); |
345 | 82 | break; |
346 | 362 | case OpCode::F32x4__le: |
347 | 362 | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLE, Context.Int32x4Ty); |
348 | 362 | break; |
349 | 77 | case OpCode::F32x4__ge: |
350 | 77 | compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOGE, Context.Int32x4Ty); |
351 | 77 | break; |
352 | 56 | case OpCode::F64x2__eq: |
353 | 56 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOEQ, Context.Int64x2Ty); |
354 | 56 | break; |
355 | 101 | case OpCode::F64x2__ne: |
356 | 101 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealUNE, Context.Int64x2Ty); |
357 | 101 | break; |
358 | 134 | case OpCode::F64x2__lt: |
359 | 134 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLT, Context.Int64x2Ty); |
360 | 134 | break; |
361 | 57 | case OpCode::F64x2__gt: |
362 | 57 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGT, Context.Int64x2Ty); |
363 | 57 | break; |
364 | 148 | case OpCode::F64x2__le: |
365 | 148 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLE, Context.Int64x2Ty); |
366 | 148 | break; |
367 | 82 | case OpCode::F64x2__ge: |
368 | 82 | compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGE, Context.Int64x2Ty); |
369 | 82 | break; |
370 | 360 | case OpCode::V128__not: |
371 | 360 | Stack.back() = Builder.createNot(Stack.back()); |
372 | 360 | break; |
373 | 107 | case OpCode::V128__and: { |
374 | 107 | auto RHS = stackPop(); |
375 | 107 | auto LHS = stackPop(); |
376 | 107 | stackPush(Builder.createAnd(LHS, RHS)); |
377 | 107 | break; |
378 | 0 | } |
379 | 85 | case OpCode::V128__andnot: { |
380 | 85 | auto RHS = stackPop(); |
381 | 85 | auto LHS = stackPop(); |
382 | 85 | stackPush(Builder.createAnd(LHS, Builder.createNot(RHS))); |
383 | 85 | break; |
384 | 0 | } |
385 | 122 | case OpCode::V128__or: { |
386 | 122 | auto RHS = stackPop(); |
387 | 122 | auto LHS = stackPop(); |
388 | 122 | stackPush(Builder.createOr(LHS, RHS)); |
389 | 122 | break; |
390 | 0 | } |
391 | 59 | case OpCode::V128__xor: { |
392 | 59 | auto RHS = stackPop(); |
393 | 59 | auto LHS = stackPop(); |
394 | 59 | stackPush(Builder.createXor(LHS, RHS)); |
395 | 59 | break; |
396 | 0 | } |
397 | 130 | case OpCode::V128__bitselect: { |
398 | 130 | auto C = stackPop(); |
399 | 130 | auto V2 = stackPop(); |
400 | 130 | auto V1 = stackPop(); |
401 | 130 | stackPush( |
402 | 130 | Builder.createXor(Builder.createAnd(Builder.createXor(V1, V2), C), V2)); |
403 | 130 | break; |
404 | 0 | } |
405 | 131 | case OpCode::V128__any_true: |
406 | 131 | compileVectorAnyTrue(); |
407 | 131 | break; |
408 | 1.31k | case OpCode::I8x16__abs: |
409 | 1.31k | compileVectorAbs(Context.Int8x16Ty); |
410 | 1.31k | break; |
411 | 2.28k | case OpCode::I8x16__neg: |
412 | 2.28k | compileVectorNeg(Context.Int8x16Ty); |
413 | 2.28k | break; |
414 | 140 | case OpCode::I8x16__popcnt: |
415 | 140 | compileVectorPopcnt(); |
416 | 140 | break; |
417 | 294 | case OpCode::I8x16__all_true: |
418 | 294 | compileVectorAllTrue(Context.Int8x16Ty); |
419 | 294 | break; |
420 | 685 | case OpCode::I8x16__bitmask: |
421 | 685 | compileVectorBitMask(Context.Int8x16Ty); |
422 | 685 | break; |
423 | 92 | case OpCode::I8x16__narrow_i16x8_s: |
424 | 92 | compileVectorNarrow(Context.Int16x8Ty, true); |
425 | 92 | break; |
426 | 188 | case OpCode::I8x16__narrow_i16x8_u: |
427 | 188 | compileVectorNarrow(Context.Int16x8Ty, false); |
428 | 188 | break; |
429 | 111 | case OpCode::I8x16__shl: |
430 | 111 | compileVectorShl(Context.Int8x16Ty); |
431 | 111 | break; |
432 | 1.09k | case OpCode::I8x16__shr_s: |
433 | 1.09k | compileVectorAShr(Context.Int8x16Ty); |
434 | 1.09k | break; |
435 | 86 | case OpCode::I8x16__shr_u: |
436 | 86 | compileVectorLShr(Context.Int8x16Ty); |
437 | 86 | break; |
438 | 41 | case OpCode::I8x16__add: |
439 | 41 | compileVectorVectorAdd(Context.Int8x16Ty); |
440 | 41 | break; |
441 | 527 | case OpCode::I8x16__add_sat_s: |
442 | 527 | compileVectorVectorAddSat(Context.Int8x16Ty, true); |
443 | 527 | break; |
444 | 64 | case OpCode::I8x16__add_sat_u: |
445 | 64 | compileVectorVectorAddSat(Context.Int8x16Ty, false); |
446 | 64 | break; |
447 | 66 | case OpCode::I8x16__sub: |
448 | 66 | compileVectorVectorSub(Context.Int8x16Ty); |
449 | 66 | break; |
450 | 191 | case OpCode::I8x16__sub_sat_s: |
451 | 191 | compileVectorVectorSubSat(Context.Int8x16Ty, true); |
452 | 191 | break; |
453 | 82 | case OpCode::I8x16__sub_sat_u: |
454 | 82 | compileVectorVectorSubSat(Context.Int8x16Ty, false); |
455 | 82 | break; |
456 | 84 | case OpCode::I8x16__min_s: |
457 | 84 | compileVectorVectorSMin(Context.Int8x16Ty); |
458 | 84 | break; |
459 | 105 | case OpCode::I8x16__min_u: |
460 | 105 | compileVectorVectorUMin(Context.Int8x16Ty); |
461 | 105 | break; |
462 | 326 | case OpCode::I8x16__max_s: |
463 | 326 | compileVectorVectorSMax(Context.Int8x16Ty); |
464 | 326 | break; |
465 | 104 | case OpCode::I8x16__max_u: |
466 | 104 | compileVectorVectorUMax(Context.Int8x16Ty); |
467 | 104 | break; |
468 | 151 | case OpCode::I8x16__avgr_u: |
469 | 151 | compileVectorVectorUAvgr(Context.Int8x16Ty); |
470 | 151 | break; |
471 | 206 | case OpCode::I16x8__abs: |
472 | 206 | compileVectorAbs(Context.Int16x8Ty); |
473 | 206 | break; |
474 | 187 | case OpCode::I16x8__neg: |
475 | 187 | compileVectorNeg(Context.Int16x8Ty); |
476 | 187 | break; |
477 | 144 | case OpCode::I16x8__all_true: |
478 | 144 | compileVectorAllTrue(Context.Int16x8Ty); |
479 | 144 | break; |
480 | 97 | case OpCode::I16x8__bitmask: |
481 | 97 | compileVectorBitMask(Context.Int16x8Ty); |
482 | 97 | break; |
483 | 42 | case OpCode::I16x8__narrow_i32x4_s: |
484 | 42 | compileVectorNarrow(Context.Int32x4Ty, true); |
485 | 42 | break; |
486 | 361 | case OpCode::I16x8__narrow_i32x4_u: |
487 | 361 | compileVectorNarrow(Context.Int32x4Ty, false); |
488 | 361 | break; |
489 | 976 | case OpCode::I16x8__extend_low_i8x16_s: |
490 | 976 | compileVectorExtend(Context.Int8x16Ty, true, true); |
491 | 976 | break; |
492 | 107 | case OpCode::I16x8__extend_high_i8x16_s: |
493 | 107 | compileVectorExtend(Context.Int8x16Ty, true, false); |
494 | 107 | break; |
495 | 363 | case OpCode::I16x8__extend_low_i8x16_u: |
496 | 363 | compileVectorExtend(Context.Int8x16Ty, false, true); |
497 | 363 | break; |
498 | 12 | case OpCode::I16x8__extend_high_i8x16_u: |
499 | 12 | compileVectorExtend(Context.Int8x16Ty, false, false); |
500 | 12 | break; |
501 | 112 | case OpCode::I16x8__shl: |
502 | 112 | compileVectorShl(Context.Int16x8Ty); |
503 | 112 | break; |
504 | 332 | case OpCode::I16x8__shr_s: |
505 | 332 | compileVectorAShr(Context.Int16x8Ty); |
506 | 332 | break; |
507 | 124 | case OpCode::I16x8__shr_u: |
508 | 124 | compileVectorLShr(Context.Int16x8Ty); |
509 | 124 | break; |
510 | 142 | case OpCode::I16x8__add: |
511 | 142 | compileVectorVectorAdd(Context.Int16x8Ty); |
512 | 142 | break; |
513 | 16 | case OpCode::I16x8__add_sat_s: |
514 | 16 | compileVectorVectorAddSat(Context.Int16x8Ty, true); |
515 | 16 | break; |
516 | 384 | case OpCode::I16x8__add_sat_u: |
517 | 384 | compileVectorVectorAddSat(Context.Int16x8Ty, false); |
518 | 384 | break; |
519 | 279 | case OpCode::I16x8__sub: |
520 | 279 | compileVectorVectorSub(Context.Int16x8Ty); |
521 | 279 | break; |
522 | 30 | case OpCode::I16x8__sub_sat_s: |
523 | 30 | compileVectorVectorSubSat(Context.Int16x8Ty, true); |
524 | 30 | break; |
525 | 89 | case OpCode::I16x8__sub_sat_u: |
526 | 89 | compileVectorVectorSubSat(Context.Int16x8Ty, false); |
527 | 89 | break; |
528 | 104 | case OpCode::I16x8__mul: |
529 | 104 | compileVectorVectorMul(Context.Int16x8Ty); |
530 | 104 | break; |
531 | 156 | case OpCode::I16x8__min_s: |
532 | 156 | compileVectorVectorSMin(Context.Int16x8Ty); |
533 | 156 | break; |
534 | 119 | case OpCode::I16x8__min_u: |
535 | 119 | compileVectorVectorUMin(Context.Int16x8Ty); |
536 | 119 | break; |
537 | 82 | case OpCode::I16x8__max_s: |
538 | 82 | compileVectorVectorSMax(Context.Int16x8Ty); |
539 | 82 | break; |
540 | 527 | case OpCode::I16x8__max_u: |
541 | 527 | compileVectorVectorUMax(Context.Int16x8Ty); |
542 | 527 | break; |
543 | 110 | case OpCode::I16x8__avgr_u: |
544 | 110 | compileVectorVectorUAvgr(Context.Int16x8Ty); |
545 | 110 | break; |
546 | 64 | case OpCode::I16x8__extmul_low_i8x16_s: |
547 | 64 | compileVectorExtMul(Context.Int8x16Ty, true, true); |
548 | 64 | break; |
549 | 199 | case OpCode::I16x8__extmul_high_i8x16_s: |
550 | 199 | compileVectorExtMul(Context.Int8x16Ty, true, false); |
551 | 199 | break; |
552 | 108 | case OpCode::I16x8__extmul_low_i8x16_u: |
553 | 108 | compileVectorExtMul(Context.Int8x16Ty, false, true); |
554 | 108 | break; |
555 | 389 | case OpCode::I16x8__extmul_high_i8x16_u: |
556 | 389 | compileVectorExtMul(Context.Int8x16Ty, false, false); |
557 | 389 | break; |
558 | 142 | case OpCode::I16x8__q15mulr_sat_s: |
559 | 142 | compileVectorVectorQ15MulSat(); |
560 | 142 | break; |
561 | 369 | case OpCode::I16x8__extadd_pairwise_i8x16_s: |
562 | 369 | compileVectorExtAddPairwise(Context.Int8x16Ty, true); |
563 | 369 | break; |
564 | 340 | case OpCode::I16x8__extadd_pairwise_i8x16_u: |
565 | 340 | compileVectorExtAddPairwise(Context.Int8x16Ty, false); |
566 | 340 | break; |
567 | 56 | case OpCode::I32x4__abs: |
568 | 56 | compileVectorAbs(Context.Int32x4Ty); |
569 | 56 | break; |
570 | 192 | case OpCode::I32x4__neg: |
571 | 192 | compileVectorNeg(Context.Int32x4Ty); |
572 | 192 | break; |
573 | 182 | case OpCode::I32x4__all_true: |
574 | 182 | compileVectorAllTrue(Context.Int32x4Ty); |
575 | 182 | break; |
576 | 84 | case OpCode::I32x4__bitmask: |
577 | 84 | compileVectorBitMask(Context.Int32x4Ty); |
578 | 84 | break; |
579 | 106 | case OpCode::I32x4__extend_low_i16x8_s: |
580 | 106 | compileVectorExtend(Context.Int16x8Ty, true, true); |
581 | 106 | break; |
582 | 530 | case OpCode::I32x4__extend_high_i16x8_s: |
583 | 530 | compileVectorExtend(Context.Int16x8Ty, true, false); |
584 | 530 | break; |
585 | 1.92k | case OpCode::I32x4__extend_low_i16x8_u: |
586 | 1.92k | compileVectorExtend(Context.Int16x8Ty, false, true); |
587 | 1.92k | break; |
588 | 152 | case OpCode::I32x4__extend_high_i16x8_u: |
589 | 152 | compileVectorExtend(Context.Int16x8Ty, false, false); |
590 | 152 | break; |
591 | 1.08k | case OpCode::I32x4__shl: |
592 | 1.08k | compileVectorShl(Context.Int32x4Ty); |
593 | 1.08k | break; |
594 | 244 | case OpCode::I32x4__shr_s: |
595 | 244 | compileVectorAShr(Context.Int32x4Ty); |
596 | 244 | break; |
597 | 439 | case OpCode::I32x4__shr_u: |
598 | 439 | compileVectorLShr(Context.Int32x4Ty); |
599 | 439 | break; |
600 | 173 | case OpCode::I32x4__add: |
601 | 173 | compileVectorVectorAdd(Context.Int32x4Ty); |
602 | 173 | break; |
603 | 111 | case OpCode::I32x4__sub: |
604 | 111 | compileVectorVectorSub(Context.Int32x4Ty); |
605 | 111 | break; |
606 | 178 | case OpCode::I32x4__mul: |
607 | 178 | compileVectorVectorMul(Context.Int32x4Ty); |
608 | 178 | break; |
609 | 81 | case OpCode::I32x4__min_s: |
610 | 81 | compileVectorVectorSMin(Context.Int32x4Ty); |
611 | 81 | break; |
612 | 57 | case OpCode::I32x4__min_u: |
613 | 57 | compileVectorVectorUMin(Context.Int32x4Ty); |
614 | 57 | break; |
615 | 89 | case OpCode::I32x4__max_s: |
616 | 89 | compileVectorVectorSMax(Context.Int32x4Ty); |
617 | 89 | break; |
618 | 75 | case OpCode::I32x4__max_u: |
619 | 75 | compileVectorVectorUMax(Context.Int32x4Ty); |
620 | 75 | break; |
621 | 96 | case OpCode::I32x4__extmul_low_i16x8_s: |
622 | 96 | compileVectorExtMul(Context.Int16x8Ty, true, true); |
623 | 96 | break; |
624 | 69 | case OpCode::I32x4__extmul_high_i16x8_s: |
625 | 69 | compileVectorExtMul(Context.Int16x8Ty, true, false); |
626 | 69 | break; |
627 | 241 | case OpCode::I32x4__extmul_low_i16x8_u: |
628 | 241 | compileVectorExtMul(Context.Int16x8Ty, false, true); |
629 | 241 | break; |
630 | 115 | case OpCode::I32x4__extmul_high_i16x8_u: |
631 | 115 | compileVectorExtMul(Context.Int16x8Ty, false, false); |
632 | 115 | break; |
633 | 1.14k | case OpCode::I32x4__extadd_pairwise_i16x8_s: |
634 | 1.14k | compileVectorExtAddPairwise(Context.Int16x8Ty, true); |
635 | 1.14k | break; |
636 | 1.00k | case OpCode::I32x4__extadd_pairwise_i16x8_u: |
637 | 1.00k | compileVectorExtAddPairwise(Context.Int16x8Ty, false); |
638 | 1.00k | break; |
639 | 115 | case OpCode::I32x4__dot_i16x8_s: { |
640 | 115 | auto ExtendTy = Context.Int16x8Ty.getExtendedElementVectorType(); |
641 | 115 | auto Undef = LLVM::Value::getUndef(ExtendTy); |
642 | 115 | auto LHS = Builder.createSExt( |
643 | 115 | Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy); |
644 | 115 | auto RHS = Builder.createSExt( |
645 | 115 | Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy); |
646 | 115 | auto M = Builder.createMul(LHS, RHS); |
647 | 115 | auto L = Builder.createShuffleVector( |
648 | 115 | M, Undef, LLVM::Value::getConstVector32(LLContext, {0U, 2U, 4U, 6U})); |
649 | 115 | auto R = Builder.createShuffleVector( |
650 | 115 | M, Undef, LLVM::Value::getConstVector32(LLContext, {1U, 3U, 5U, 7U})); |
651 | 115 | auto V = Builder.createAdd(L, R); |
652 | 115 | stackPush(Builder.createBitCast(V, Context.Int64x2Ty)); |
653 | 115 | break; |
654 | 0 | } |
655 | 914 | case OpCode::I64x2__abs: |
656 | 914 | compileVectorAbs(Context.Int64x2Ty); |
657 | 914 | break; |
658 | 528 | case OpCode::I64x2__neg: |
659 | 528 | compileVectorNeg(Context.Int64x2Ty); |
660 | 528 | break; |
661 | 281 | case OpCode::I64x2__all_true: |
662 | 281 | compileVectorAllTrue(Context.Int64x2Ty); |
663 | 281 | break; |
664 | 264 | case OpCode::I64x2__bitmask: |
665 | 264 | compileVectorBitMask(Context.Int64x2Ty); |
666 | 264 | break; |
667 | 370 | case OpCode::I64x2__extend_low_i32x4_s: |
668 | 370 | compileVectorExtend(Context.Int32x4Ty, true, true); |
669 | 370 | break; |
670 | 712 | case OpCode::I64x2__extend_high_i32x4_s: |
671 | 712 | compileVectorExtend(Context.Int32x4Ty, true, false); |
672 | 712 | break; |
673 | 212 | case OpCode::I64x2__extend_low_i32x4_u: |
674 | 212 | compileVectorExtend(Context.Int32x4Ty, false, true); |
675 | 212 | break; |
676 | 565 | case OpCode::I64x2__extend_high_i32x4_u: |
677 | 565 | compileVectorExtend(Context.Int32x4Ty, false, false); |
678 | 565 | break; |
679 | 117 | case OpCode::I64x2__shl: |
680 | 117 | compileVectorShl(Context.Int64x2Ty); |
681 | 117 | break; |
682 | 325 | case OpCode::I64x2__shr_s: |
683 | 325 | compileVectorAShr(Context.Int64x2Ty); |
684 | 325 | break; |
685 | 71 | case OpCode::I64x2__shr_u: |
686 | 71 | compileVectorLShr(Context.Int64x2Ty); |
687 | 71 | break; |
688 | 50 | case OpCode::I64x2__add: |
689 | 50 | compileVectorVectorAdd(Context.Int64x2Ty); |
690 | 50 | break; |
691 | 249 | case OpCode::I64x2__sub: |
692 | 249 | compileVectorVectorSub(Context.Int64x2Ty); |
693 | 249 | break; |
694 | 80 | case OpCode::I64x2__mul: |
695 | 80 | compileVectorVectorMul(Context.Int64x2Ty); |
696 | 80 | break; |
697 | 37 | case OpCode::I64x2__extmul_low_i32x4_s: |
698 | 37 | compileVectorExtMul(Context.Int32x4Ty, true, true); |
699 | 37 | break; |
700 | 403 | case OpCode::I64x2__extmul_high_i32x4_s: |
701 | 403 | compileVectorExtMul(Context.Int32x4Ty, true, false); |
702 | 403 | break; |
703 | 30 | case OpCode::I64x2__extmul_low_i32x4_u: |
704 | 30 | compileVectorExtMul(Context.Int32x4Ty, false, true); |
705 | 30 | break; |
706 | 169 | case OpCode::I64x2__extmul_high_i32x4_u: |
707 | 169 | compileVectorExtMul(Context.Int32x4Ty, false, false); |
708 | 169 | break; |
709 | 118 | case OpCode::F32x4__abs: |
710 | 118 | compileVectorFAbs(Context.Floatx4Ty); |
711 | 118 | break; |
712 | 158 | case OpCode::F32x4__neg: |
713 | 158 | compileVectorFNeg(Context.Floatx4Ty); |
714 | 158 | break; |
715 | 167 | case OpCode::F32x4__sqrt: |
716 | 167 | compileVectorFSqrt(Context.Floatx4Ty); |
717 | 167 | break; |
718 | 122 | case OpCode::F32x4__add: |
719 | 122 | compileVectorVectorFAdd(Context.Floatx4Ty); |
720 | 122 | break; |
721 | 257 | case OpCode::F32x4__sub: |
722 | 257 | compileVectorVectorFSub(Context.Floatx4Ty); |
723 | 257 | break; |
724 | 38 | case OpCode::F32x4__mul: |
725 | 38 | compileVectorVectorFMul(Context.Floatx4Ty); |
726 | 38 | break; |
727 | 161 | case OpCode::F32x4__div: |
728 | 161 | compileVectorVectorFDiv(Context.Floatx4Ty); |
729 | 161 | break; |
730 | 144 | case OpCode::F32x4__min: |
731 | 144 | compileVectorVectorFMin(Context.Floatx4Ty); |
732 | 144 | break; |
733 | 38 | case OpCode::F32x4__max: |
734 | 38 | compileVectorVectorFMax(Context.Floatx4Ty); |
735 | 38 | break; |
736 | 51 | case OpCode::F32x4__pmin: |
737 | 51 | compileVectorVectorFPMin(Context.Floatx4Ty); |
738 | 51 | break; |
739 | 222 | case OpCode::F32x4__pmax: |
740 | 222 | compileVectorVectorFPMax(Context.Floatx4Ty); |
741 | 222 | break; |
742 | 1.05k | case OpCode::F32x4__ceil: |
743 | 1.05k | compileVectorFCeil(Context.Floatx4Ty); |
744 | 1.05k | break; |
745 | 2.03k | case OpCode::F32x4__floor: |
746 | 2.03k | compileVectorFFloor(Context.Floatx4Ty); |
747 | 2.03k | break; |
748 | 1.93k | case OpCode::F32x4__trunc: |
749 | 1.93k | compileVectorFTrunc(Context.Floatx4Ty); |
750 | 1.93k | break; |
751 | 281 | case OpCode::F32x4__nearest: |
752 | 281 | compileVectorFNearest(Context.Floatx4Ty); |
753 | 281 | break; |
754 | 438 | case OpCode::F64x2__abs: |
755 | 438 | compileVectorFAbs(Context.Doublex2Ty); |
756 | 438 | break; |
757 | 624 | case OpCode::F64x2__neg: |
758 | 624 | compileVectorFNeg(Context.Doublex2Ty); |
759 | 624 | break; |
760 | 112 | case OpCode::F64x2__sqrt: |
761 | 112 | compileVectorFSqrt(Context.Doublex2Ty); |
762 | 112 | break; |
763 | 49 | case OpCode::F64x2__add: |
764 | 49 | compileVectorVectorFAdd(Context.Doublex2Ty); |
765 | 49 | break; |
766 | 210 | case OpCode::F64x2__sub: |
767 | 210 | compileVectorVectorFSub(Context.Doublex2Ty); |
768 | 210 | break; |
769 | 231 | case OpCode::F64x2__mul: |
770 | 231 | compileVectorVectorFMul(Context.Doublex2Ty); |
771 | 231 | break; |
772 | 37 | case OpCode::F64x2__div: |
773 | 37 | compileVectorVectorFDiv(Context.Doublex2Ty); |
774 | 37 | break; |
775 | 169 | case OpCode::F64x2__min: |
776 | 169 | compileVectorVectorFMin(Context.Doublex2Ty); |
777 | 169 | break; |
778 | 150 | case OpCode::F64x2__max: |
779 | 150 | compileVectorVectorFMax(Context.Doublex2Ty); |
780 | 150 | break; |
781 | 281 | case OpCode::F64x2__pmin: |
782 | 281 | compileVectorVectorFPMin(Context.Doublex2Ty); |
783 | 281 | break; |
784 | 103 | case OpCode::F64x2__pmax: |
785 | 103 | compileVectorVectorFPMax(Context.Doublex2Ty); |
786 | 103 | break; |
787 | 667 | case OpCode::F64x2__ceil: |
788 | 667 | compileVectorFCeil(Context.Doublex2Ty); |
789 | 667 | break; |
790 | 798 | case OpCode::F64x2__floor: |
791 | 798 | compileVectorFFloor(Context.Doublex2Ty); |
792 | 798 | break; |
793 | 110 | case OpCode::F64x2__trunc: |
794 | 110 | compileVectorFTrunc(Context.Doublex2Ty); |
795 | 110 | break; |
796 | 153 | case OpCode::F64x2__nearest: |
797 | 153 | compileVectorFNearest(Context.Doublex2Ty); |
798 | 153 | break; |
799 | 186 | case OpCode::I32x4__trunc_sat_f32x4_s: |
800 | 186 | compileVectorTruncSatS32(Context.Floatx4Ty, false); |
801 | 186 | break; |
802 | 3.77k | case OpCode::I32x4__trunc_sat_f32x4_u: |
803 | 3.77k | compileVectorTruncSatU32(Context.Floatx4Ty, false); |
804 | 3.77k | break; |
805 | 346 | case OpCode::F32x4__convert_i32x4_s: |
806 | 346 | compileVectorConvertS(Context.Int32x4Ty, Context.Floatx4Ty, false); |
807 | 346 | break; |
808 | 705 | case OpCode::F32x4__convert_i32x4_u: |
809 | 705 | compileVectorConvertU(Context.Int32x4Ty, Context.Floatx4Ty, false); |
810 | 705 | break; |
811 | 746 | case OpCode::I32x4__trunc_sat_f64x2_s_zero: |
812 | 746 | compileVectorTruncSatS32(Context.Doublex2Ty, true); |
813 | 746 | break; |
814 | 2.16k | case OpCode::I32x4__trunc_sat_f64x2_u_zero: |
815 | 2.16k | compileVectorTruncSatU32(Context.Doublex2Ty, true); |
816 | 2.16k | break; |
817 | 303 | case OpCode::F64x2__convert_low_i32x4_s: |
818 | 303 | compileVectorConvertS(Context.Int32x4Ty, Context.Doublex2Ty, true); |
819 | 303 | break; |
820 | 1.20k | case OpCode::F64x2__convert_low_i32x4_u: |
821 | 1.20k | compileVectorConvertU(Context.Int32x4Ty, Context.Doublex2Ty, true); |
822 | 1.20k | break; |
823 | 737 | case OpCode::F32x4__demote_f64x2_zero: |
824 | 737 | compileVectorDemote(); |
825 | 737 | break; |
826 | 789 | case OpCode::F64x2__promote_low_f32x4: |
827 | 789 | compileVectorPromote(); |
828 | 789 | break; |
829 | | |
830 | | // Relaxed SIMD Instructions |
831 | 16 | case OpCode::I8x16__relaxed_swizzle: |
832 | 16 | compileVectorSwizzle(); |
833 | 16 | break; |
834 | 13 | case OpCode::I32x4__relaxed_trunc_f32x4_s: |
835 | 13 | compileVectorTruncSatS32(Context.Floatx4Ty, false); |
836 | 13 | break; |
837 | 12 | case OpCode::I32x4__relaxed_trunc_f32x4_u: |
838 | 12 | compileVectorTruncSatU32(Context.Floatx4Ty, false); |
839 | 12 | break; |
840 | 10 | case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: |
841 | 10 | compileVectorTruncSatS32(Context.Doublex2Ty, true); |
842 | 10 | break; |
843 | 20 | case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: |
844 | 20 | compileVectorTruncSatU32(Context.Doublex2Ty, true); |
845 | 20 | break; |
846 | 13 | case OpCode::F32x4__relaxed_madd: |
847 | 13 | compileVectorVectorMAdd(Context.Floatx4Ty); |
848 | 13 | break; |
849 | 63 | case OpCode::F32x4__relaxed_nmadd: |
850 | 63 | compileVectorVectorNMAdd(Context.Floatx4Ty); |
851 | 63 | break; |
852 | 14 | case OpCode::F64x2__relaxed_madd: |
853 | 14 | compileVectorVectorMAdd(Context.Doublex2Ty); |
854 | 14 | break; |
855 | 26 | case OpCode::F64x2__relaxed_nmadd: |
856 | 26 | compileVectorVectorNMAdd(Context.Doublex2Ty); |
857 | 26 | break; |
858 | 12 | case OpCode::I8x16__relaxed_laneselect: |
859 | 24 | case OpCode::I16x8__relaxed_laneselect: |
860 | 34 | case OpCode::I32x4__relaxed_laneselect: |
861 | 38 | case OpCode::I64x2__relaxed_laneselect: { |
862 | 38 | auto C = stackPop(); |
863 | 38 | auto V2 = stackPop(); |
864 | 38 | auto V1 = stackPop(); |
865 | 38 | stackPush( |
866 | 38 | Builder.createXor(Builder.createAnd(Builder.createXor(V1, V2), C), V2)); |
867 | 38 | break; |
868 | 34 | } |
869 | 19 | case OpCode::F32x4__relaxed_min: |
870 | 19 | compileVectorVectorFMin(Context.Floatx4Ty); |
871 | 19 | break; |
872 | 10 | case OpCode::F32x4__relaxed_max: |
873 | 10 | compileVectorVectorFMax(Context.Floatx4Ty); |
874 | 10 | break; |
875 | 12 | case OpCode::F64x2__relaxed_min: |
876 | 12 | compileVectorVectorFMin(Context.Doublex2Ty); |
877 | 12 | break; |
878 | 11 | case OpCode::F64x2__relaxed_max: |
879 | 11 | compileVectorVectorFMax(Context.Doublex2Ty); |
880 | 11 | break; |
881 | 20 | case OpCode::I16x8__relaxed_q15mulr_s: |
882 | 20 | compileVectorVectorQ15MulSat(); |
883 | 20 | break; |
884 | 14 | case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: |
885 | 14 | compileVectorRelaxedIntegerDotProduct(); |
886 | 14 | break; |
887 | 12 | case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: |
888 | 12 | compileVectorRelaxedIntegerDotProductAdd(); |
889 | 12 | break; |
890 | | |
891 | | // Atomic Instructions |
892 | 0 | default: |
893 | 0 | assumingUnreachable(); |
894 | 117k | } |
895 | 117k | return {}; |
896 | 117k | } |
897 | | |
898 | | void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy, |
899 | 1.24k | unsigned Index) noexcept { |
900 | 1.24k | auto Vector = Builder.createBitCast(Stack.back(), VectorTy); |
901 | | if constexpr (Endian::native == Endian::big) { |
902 | | Index = VectorTy.getVectorSize() - Index - 1; |
903 | | } |
904 | 1.24k | Stack.back() = |
905 | 1.24k | Builder.createExtractElement(Vector, LLContext.getInt64(Index)); |
906 | 1.24k | } |
907 | | |
908 | | void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy, unsigned Index, |
909 | | LLVM::Type ExtendTy, |
910 | 928 | bool Signed) noexcept { |
911 | 928 | compileExtractLaneOp(VectorTy, Index); |
912 | 928 | if (Signed) { |
913 | 508 | Stack.back() = Builder.createSExt(Stack.back(), ExtendTy); |
914 | 508 | } else { |
915 | 420 | Stack.back() = Builder.createZExt(Stack.back(), ExtendTy); |
916 | 420 | } |
917 | 928 | } |
918 | | |
919 | | void FunctionCompiler::compileLoadLaneOp(unsigned MemoryIndex, uint64_t Offset, |
920 | | unsigned Alignment, unsigned Index, |
921 | | LLVM::Type LoadTy, |
922 | 498 | LLVM::Type VectorTy) noexcept { |
923 | 498 | auto Vector = stackPop(); |
924 | 498 | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy); |
925 | | if constexpr (Endian::native == Endian::big) { |
926 | | Index = VectorTy.getVectorSize() - 1 - Index; |
927 | | } |
928 | 498 | auto Value = Stack.back(); |
929 | 498 | Stack.back() = Builder.createBitCast( |
930 | 498 | Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy), |
931 | 498 | Value, LLContext.getInt64(Index)), |
932 | 498 | Context.Int64x2Ty); |
933 | 498 | } |
934 | | |
935 | | void FunctionCompiler::compileReplaceLaneOp(LLVM::Type VectorTy, |
936 | 805 | unsigned Index) noexcept { |
937 | 805 | auto Value = Builder.createTrunc(stackPop(), VectorTy.getElementType()); |
938 | 805 | auto Vector = Stack.back(); |
939 | | if constexpr (Endian::native == Endian::big) { |
940 | | Index = VectorTy.getVectorSize() - Index - 1; |
941 | | } |
942 | 805 | Stack.back() = Builder.createBitCast( |
943 | 805 | Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy), |
944 | 805 | Value, LLContext.getInt64(Index)), |
945 | 805 | Context.Int64x2Ty); |
946 | 805 | } |
947 | | |
948 | | void FunctionCompiler::compileSplatLoadOp(unsigned MemoryIndex, uint64_t Offset, |
949 | | unsigned Alignment, LLVM::Type LoadTy, |
950 | 550 | LLVM::Type VectorTy) noexcept { |
951 | 550 | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy); |
952 | 550 | compileSplatOp(VectorTy); |
953 | 550 | } |
954 | | |
955 | 47.3k | void FunctionCompiler::compileSplatOp(LLVM::Type VectorTy) noexcept { |
956 | 47.3k | auto Undef = LLVM::Value::getUndef(VectorTy); |
957 | 47.3k | auto Zeros = LLVM::Value::getConstNull( |
958 | 47.3k | LLVM::Type::getVectorType(Context.Int32Ty, VectorTy.getVectorSize())); |
959 | 47.3k | auto Value = Builder.createTrunc(Stack.back(), VectorTy.getElementType()); |
960 | 47.3k | auto Vector = |
961 | 47.3k | Builder.createInsertElement(Undef, Value, LLContext.getInt64(0)); |
962 | 47.3k | Vector = Builder.createShuffleVector(Vector, Undef, Zeros); |
963 | | |
964 | 47.3k | Stack.back() = Builder.createBitCast(Vector, Context.Int64x2Ty); |
965 | 47.3k | } |
966 | | |
967 | | void FunctionCompiler::compileStoreLaneOp(uint32_t MemoryIndex, uint64_t Offset, |
968 | | uint32_t Alignment, uint8_t Index, |
969 | | LLVM::Type LoadTy, |
970 | 390 | LLVM::Type VectorTy) noexcept { |
971 | 390 | auto Vector = Stack.back(); |
972 | | if constexpr (Endian::native == Endian::big) { |
973 | | Index = static_cast<uint8_t>(VectorTy.getVectorSize() - Index - 1); |
974 | | } |
975 | 390 | Stack.back() = Builder.createExtractElement( |
976 | 390 | Builder.createBitCast(Vector, VectorTy), LLContext.getInt64(Index)); |
977 | 390 | compileStoreOp(MemoryIndex, Offset, Alignment, LoadTy); |
978 | 390 | } |
979 | | |
980 | 2.48k | void FunctionCompiler::compileVectorAbs(LLVM::Type VectorTy) noexcept { |
981 | 2.48k | compileVectorOp(VectorTy, [this](auto V) noexcept { |
982 | 2.48k | return Builder.createIntrinsic(LLVM::Core::Abs, {V.getType()}, |
983 | 2.48k | {V, LLContext.getFalse()}); |
984 | 2.48k | }); |
985 | 2.48k | } |
986 | | |
987 | 901 | void FunctionCompiler::compileVectorAllTrue(LLVM::Type VectorTy) noexcept { |
988 | 901 | compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept { |
989 | 901 | const auto Size = VectorTy.getVectorSize(); |
990 | 901 | auto IntType = LLContext.getIntNTy(Size); |
991 | 901 | auto Zero = LLVM::Value::getConstNull(VectorTy); |
992 | 901 | auto Cmp = Builder.createBitCast(Builder.createICmpEQ(V, Zero), IntType); |
993 | 901 | auto CmpZero = LLVM::Value::getConstInt(IntType, 0); |
994 | 901 | return Builder.createICmpEQ(Cmp, CmpZero); |
995 | 901 | }); |
996 | 901 | } |
997 | | |
998 | 131 | void FunctionCompiler::compileVectorAnyTrue() noexcept { |
999 | 131 | compileVectorReduceIOp(Context.Int128x1Ty, [this](auto V) noexcept { |
1000 | 131 | auto Zero = LLVM::Value::getConstNull(Context.Int128x1Ty); |
1001 | 131 | return Builder.createBitCast(Builder.createICmpNE(V, Zero), |
1002 | 131 | LLContext.getInt1Ty()); |
1003 | 131 | }); |
1004 | 131 | } |
1005 | | |
1006 | 1.99k | void FunctionCompiler::compileVectorAShr(LLVM::Type VectorTy) noexcept { |
1007 | 1.99k | compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1008 | 1.99k | return Builder.createAShr(LHS, RHS); |
1009 | 1.99k | }); |
1010 | 1.99k | } |
1011 | | |
1012 | 1.13k | void FunctionCompiler::compileVectorBitMask(LLVM::Type VectorTy) noexcept { |
1013 | 1.13k | compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept { |
1014 | 1.13k | const auto Size = VectorTy.getVectorSize(); |
1015 | 1.13k | auto IntType = LLContext.getIntNTy(Size); |
1016 | 1.13k | auto Zero = LLVM::Value::getConstNull(VectorTy); |
1017 | 1.13k | return Builder.createBitCast(Builder.createICmpSLT(V, Zero), IntType); |
1018 | 1.13k | }); |
1019 | 1.13k | } |
1020 | | |
1021 | | void FunctionCompiler::compileVectorCompareOp( |
1022 | 5.23k | LLVM::Type VectorTy, LLVMIntPredicate Predicate) noexcept { |
1023 | 5.23k | auto RHS = stackPop(); |
1024 | 5.23k | auto LHS = stackPop(); |
1025 | 5.23k | auto Result = Builder.createSExt( |
1026 | 5.23k | Builder.createICmp(Predicate, Builder.createBitCast(LHS, VectorTy), |
1027 | 5.23k | Builder.createBitCast(RHS, VectorTy)), |
1028 | 5.23k | VectorTy); |
1029 | 5.23k | stackPush(Builder.createBitCast(Result, Context.Int64x2Ty)); |
1030 | 5.23k | } |
1031 | | |
1032 | | void FunctionCompiler::compileVectorCompareOp(LLVM::Type VectorTy, |
1033 | | LLVMRealPredicate Predicate, |
1034 | 3.20k | LLVM::Type ResultTy) noexcept { |
1035 | 3.20k | auto RHS = stackPop(); |
1036 | 3.20k | auto LHS = stackPop(); |
1037 | 3.20k | auto Result = Builder.createSExt( |
1038 | 3.20k | Builder.createFCmp(Predicate, Builder.createBitCast(LHS, VectorTy), |
1039 | 3.20k | Builder.createBitCast(RHS, VectorTy)), |
1040 | 3.20k | ResultTy); |
1041 | 3.20k | stackPush(Builder.createBitCast(Result, Context.Int64x2Ty)); |
1042 | 3.20k | } |
1043 | | |
1044 | | void FunctionCompiler::compileVectorConvertS(LLVM::Type VectorTy, |
1045 | | LLVM::Type FPVectorTy, |
1046 | 649 | bool Low) noexcept { |
1047 | 649 | compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept { |
1048 | 649 | if (Low) { |
1049 | 303 | const auto Size = VectorTy.getVectorSize() / 2; |
1050 | 303 | std::vector<uint32_t> Mask(Size); |
1051 | 303 | if constexpr (Endian::native == Endian::little) { |
1052 | 303 | std::iota(Mask.begin(), Mask.end(), 0); |
1053 | | } else { |
1054 | | std::iota(Mask.begin(), Mask.end(), Size); |
1055 | | } |
1056 | 303 | V = Builder.createShuffleVector( |
1057 | 303 | V, LLVM::Value::getUndef(VectorTy), |
1058 | 303 | LLVM::Value::getConstVector32(LLContext, Mask)); |
1059 | 303 | } |
1060 | 649 | return Builder.createSIToFP(V, FPVectorTy); |
1061 | 649 | }); |
1062 | 649 | } |
1063 | | |
1064 | | void FunctionCompiler::compileVectorConvertU(LLVM::Type VectorTy, |
1065 | | LLVM::Type FPVectorTy, |
1066 | 1.90k | bool Low) noexcept { |
1067 | 1.90k | compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept { |
1068 | 1.90k | if (Low) { |
1069 | 1.20k | const auto Size = VectorTy.getVectorSize() / 2; |
1070 | 1.20k | std::vector<uint32_t> Mask(Size); |
1071 | 1.20k | if constexpr (Endian::native == Endian::little) { |
1072 | 1.20k | std::iota(Mask.begin(), Mask.end(), 0); |
1073 | | } else { |
1074 | | std::iota(Mask.begin(), Mask.end(), Size); |
1075 | | } |
1076 | 1.20k | V = Builder.createShuffleVector( |
1077 | 1.20k | V, LLVM::Value::getUndef(VectorTy), |
1078 | 1.20k | LLVM::Value::getConstVector32(LLContext, Mask)); |
1079 | 1.20k | } |
1080 | 1.90k | return Builder.createUIToFP(V, FPVectorTy); |
1081 | 1.90k | }); |
1082 | 1.90k | } |
1083 | | |
1084 | 737 | void FunctionCompiler::compileVectorDemote() noexcept { |
1085 | 737 | compileVectorOp(Context.Doublex2Ty, [this](auto V) noexcept { |
1086 | 737 | auto Demoted = |
1087 | 737 | Builder.createFPTrunc(V, LLVM::Type::getVectorType(Context.FloatTy, 2)); |
1088 | 737 | auto ZeroV = LLVM::Value::getConstNull(Demoted.getType()); |
1089 | 737 | if constexpr (Endian::native == Endian::little) { |
1090 | 737 | return Builder.createShuffleVector( |
1091 | 737 | Demoted, ZeroV, |
1092 | 737 | LLVM::Value::getConstVector32(LLContext, {0u, 1u, 2u, 3u})); |
1093 | | } else { |
1094 | | return Builder.createShuffleVector( |
1095 | | Demoted, ZeroV, |
1096 | | LLVM::Value::getConstVector32(LLContext, {3u, 2u, 1u, 0u})); |
1097 | | } |
1098 | 737 | }); |
1099 | 737 | } |
1100 | | |
1101 | | void FunctionCompiler::compileVectorExtAddPairwise(LLVM::Type VectorTy, |
1102 | 2.85k | bool Signed) noexcept { |
1103 | 2.85k | compileVectorOp( |
1104 | 2.85k | VectorTy, [this, VectorTy, Signed](auto V) noexcept -> LLVM::Value { |
1105 | 2.85k | auto ExtTy = |
1106 | 2.85k | VectorTy.getExtendedElementVectorType().getHalfElementsVectorType(); |
1107 | 2.85k | #if defined(__x86_64__) |
1108 | 2.85k | const auto Count = VectorTy.getVectorSize(); |
1109 | 2.85k | if (Context.SupportXOP) { |
1110 | 0 | const auto ID = [Count, Signed]() noexcept { |
1111 | 0 | switch (Count) { |
1112 | 0 | case 8: |
1113 | 0 | return Signed ? LLVM::Core::X86XOpVPHAddWD |
1114 | 0 | : LLVM::Core::X86XOpVPHAddUWD; |
1115 | 0 | case 16: |
1116 | 0 | return Signed ? LLVM::Core::X86XOpVPHAddBW |
1117 | 0 | : LLVM::Core::X86XOpVPHAddUBW; |
1118 | 0 | default: |
1119 | 0 | assumingUnreachable(); |
1120 | 0 | } |
1121 | 0 | }(); |
1122 | 0 | assuming(ID != LLVM::Core::NotIntrinsic); |
1123 | 0 | return Builder.createUnaryIntrinsic(ID, V); |
1124 | 0 | } |
1125 | 2.85k | if (Context.SupportSSSE3 && Count == 16) { |
1126 | 709 | assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != |
1127 | 709 | LLVM::Core::NotIntrinsic); |
1128 | 709 | if (Signed) { |
1129 | 369 | return Builder.createIntrinsic( |
1130 | 369 | LLVM::Core::X86SSSE3PMAddUbSw128, {}, |
1131 | 369 | {Builder.createVectorSplat(16, LLContext.getInt8(1)), V}); |
1132 | 369 | } else { |
1133 | 340 | return Builder.createIntrinsic( |
1134 | 340 | LLVM::Core::X86SSSE3PMAddUbSw128, {}, |
1135 | 340 | {V, Builder.createVectorSplat(16, LLContext.getInt8(1))}); |
1136 | 340 | } |
1137 | 709 | } |
1138 | 2.14k | if (Context.SupportSSE2 && Count == 8) { |
1139 | 2.14k | assuming(LLVM::Core::X86SSE2PMAddWd != LLVM::Core::NotIntrinsic); |
1140 | 2.14k | if (Signed) { |
1141 | 1.14k | return Builder.createIntrinsic( |
1142 | 1.14k | LLVM::Core::X86SSE2PMAddWd, {}, |
1143 | 1.14k | {V, Builder.createVectorSplat(8, LLContext.getInt16(1))}); |
1144 | 1.14k | } else { |
1145 | 1.00k | V = Builder.createXor( |
1146 | 1.00k | V, Builder.createVectorSplat(8, LLContext.getInt16(0x8000))); |
1147 | 1.00k | V = Builder.createIntrinsic( |
1148 | 1.00k | LLVM::Core::X86SSE2PMAddWd, {}, |
1149 | 1.00k | {V, Builder.createVectorSplat(8, LLContext.getInt16(1))}); |
1150 | 1.00k | return Builder.createAdd( |
1151 | 1.00k | V, Builder.createVectorSplat(4, LLContext.getInt32(0x10000))); |
1152 | 1.00k | } |
1153 | 2.14k | } |
1154 | 0 | #endif |
1155 | | |
1156 | | #if defined(__aarch64__) |
1157 | | if (Context.SupportNEON) { |
1158 | | const auto ID = Signed ? LLVM::Core::AArch64NeonSAddLP |
1159 | | : LLVM::Core::AArch64NeonUAddLP; |
1160 | | assuming(ID != LLVM::Core::NotIntrinsic); |
1161 | | return Builder.createIntrinsic(ID, {ExtTy, VectorTy}, {V}); |
1162 | | } |
1163 | | #endif |
1164 | | |
1165 | | // Fallback case. |
1166 | | // If the XOP, SSSE3, or SSE2 is not supported on the x86_64 platform |
1167 | | // or the NEON is not supported on the aarch64 platform, |
1168 | | // then fallback to this. |
1169 | 0 | auto Width = LLVM::Value::getConstInt( |
1170 | 0 | ExtTy.getElementType(), |
1171 | 0 | VectorTy.getElementType().getIntegerBitWidth()); |
1172 | 0 | Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width); |
1173 | 0 | auto EV = Builder.createBitCast(V, ExtTy); |
1174 | 0 | LLVM::Value L, R; |
1175 | 0 | if (Signed) { |
1176 | 0 | L = Builder.createAShr(EV, Width); |
1177 | 0 | R = Builder.createAShr(Builder.createShl(EV, Width), Width); |
1178 | 0 | } else { |
1179 | 0 | L = Builder.createLShr(EV, Width); |
1180 | 0 | R = Builder.createLShr(Builder.createShl(EV, Width), Width); |
1181 | 0 | } |
1182 | 0 | return Builder.createAdd(L, R); |
1183 | 2.14k | }); |
1184 | 2.85k | } |
1185 | | |
1186 | | void FunctionCompiler::compileVectorExtend(LLVM::Type FromTy, bool Signed, |
1187 | 6.02k | bool Low) noexcept { |
1188 | 6.02k | auto ExtTy = FromTy.getExtendedElementVectorType(); |
1189 | 6.02k | const auto Count = FromTy.getVectorSize(); |
1190 | 6.02k | std::vector<uint32_t> Mask(Count / 2); |
1191 | | if constexpr (Endian::native == Endian::big) { |
1192 | | Low = !Low; |
1193 | | } |
1194 | 6.02k | std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2); |
1195 | 6.02k | auto R = Builder.createBitCast(Stack.back(), FromTy); |
1196 | 6.02k | if (Signed) { |
1197 | 2.80k | R = Builder.createSExt(R, ExtTy); |
1198 | 3.22k | } else { |
1199 | 3.22k | R = Builder.createZExt(R, ExtTy); |
1200 | 3.22k | } |
1201 | 6.02k | R = Builder.createShuffleVector( |
1202 | 6.02k | R, LLVM::Value::getUndef(ExtTy), |
1203 | 6.02k | LLVM::Value::getConstVector32(LLContext, Mask)); |
1204 | 6.02k | Stack.back() = Builder.createBitCast(R, Context.Int64x2Ty); |
1205 | 6.02k | } |
1206 | | |
1207 | | void FunctionCompiler::compileVectorExtMul(LLVM::Type FromTy, bool Signed, |
1208 | 1.92k | bool Low) noexcept { |
1209 | 1.92k | auto ExtTy = FromTy.getExtendedElementVectorType(); |
1210 | 1.92k | const auto Count = FromTy.getVectorSize(); |
1211 | 1.92k | std::vector<uint32_t> Mask(Count / 2); |
1212 | 1.92k | std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2); |
1213 | 3.84k | auto Extend = [this, FromTy, Signed, ExtTy, &Mask](LLVM::Value R) noexcept { |
1214 | 3.84k | R = Builder.createBitCast(R, FromTy); |
1215 | 3.84k | if (Signed) { |
1216 | 1.73k | R = Builder.createSExt(R, ExtTy); |
1217 | 2.10k | } else { |
1218 | 2.10k | R = Builder.createZExt(R, ExtTy); |
1219 | 2.10k | } |
1220 | 3.84k | return Builder.createShuffleVector( |
1221 | 3.84k | R, LLVM::Value::getUndef(ExtTy), |
1222 | 3.84k | LLVM::Value::getConstVector32(LLContext, Mask)); |
1223 | 3.84k | }; |
1224 | 1.92k | auto RHS = Extend(stackPop()); |
1225 | 1.92k | auto LHS = Extend(stackPop()); |
1226 | 1.92k | stackPush( |
1227 | 1.92k | Builder.createBitCast(Builder.createMul(RHS, LHS), Context.Int64x2Ty)); |
1228 | 1.92k | } |
1229 | | |
1230 | 556 | void FunctionCompiler::compileVectorFAbs(LLVM::Type VectorTy) noexcept { |
1231 | 556 | compileVectorOp(VectorTy, [this](auto V) noexcept { |
1232 | 556 | assuming(LLVM::Core::Fabs != LLVM::Core::NotIntrinsic); |
1233 | 556 | return Builder.createUnaryIntrinsic(LLVM::Core::Fabs, V); |
1234 | 556 | }); |
1235 | 556 | } |
1236 | | |
1237 | 1.71k | void FunctionCompiler::compileVectorFCeil(LLVM::Type VectorTy) noexcept { |
1238 | 1.71k | compileVectorOp(VectorTy, [this](auto V) noexcept { |
1239 | 1.71k | assuming(LLVM::Core::Ceil != LLVM::Core::NotIntrinsic); |
1240 | 1.71k | return Builder.createUnaryIntrinsic(LLVM::Core::Ceil, V); |
1241 | 1.71k | }); |
1242 | 1.71k | } |
1243 | | |
1244 | 2.82k | void FunctionCompiler::compileVectorFFloor(LLVM::Type VectorTy) noexcept { |
1245 | 2.82k | compileVectorOp(VectorTy, [this](auto V) noexcept { |
1246 | 2.82k | assuming(LLVM::Core::Floor != LLVM::Core::NotIntrinsic); |
1247 | 2.82k | return Builder.createUnaryIntrinsic(LLVM::Core::Floor, V); |
1248 | 2.82k | }); |
1249 | 2.82k | } |
1250 | | |
1251 | 434 | void FunctionCompiler::compileVectorFNearest(LLVM::Type VectorTy) noexcept { |
1252 | 434 | compileVectorOp(VectorTy, [&](auto V) noexcept { |
1253 | 434 | #if LLVM_VERSION_MAJOR >= 12 && !defined(__s390x__) |
1254 | 434 | assuming(LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic); |
1255 | 434 | if (LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic) { |
1256 | 434 | return Builder.createUnaryIntrinsic(LLVM::Core::Roundeven, V); |
1257 | 434 | } |
1258 | 0 | #endif |
1259 | | |
1260 | 0 | #if defined(__x86_64__) |
1261 | 0 | if (Context.SupportSSE4_1) { |
1262 | 0 | const bool IsFloat = VectorTy.getElementType().isFloatTy(); |
1263 | 0 | auto ID = |
1264 | 0 | IsFloat ? LLVM::Core::X86SSE41RoundPs : LLVM::Core::X86SSE41RoundPd; |
1265 | 0 | assuming(ID != LLVM::Core::NotIntrinsic); |
1266 | 0 | return Builder.createIntrinsic(ID, {}, {V, LLContext.getInt32(8)}); |
1267 | 0 | } |
1268 | 0 | #endif |
1269 | | |
1270 | | #if defined(__aarch64__) |
1271 | | if (Context.SupportNEON && |
1272 | | LLVM::Core::AArch64NeonFRIntN != LLVM::Core::NotIntrinsic) { |
1273 | | return Builder.createUnaryIntrinsic(LLVM::Core::AArch64NeonFRIntN, V); |
1274 | | } |
1275 | | #endif |
1276 | | |
1277 | | // Fallback case. |
1278 | | // If the SSE4.1 is not supported on the x86_64 platform or |
1279 | | // the NEON is not supported on the aarch64 platform, |
1280 | | // then fallback to this. |
1281 | 0 | assuming(LLVM::Core::Nearbyint != LLVM::Core::NotIntrinsic); |
1282 | 0 | return Builder.createUnaryIntrinsic(LLVM::Core::Nearbyint, V); |
1283 | 0 | }); |
1284 | 434 | } |
1285 | | |
1286 | 782 | void FunctionCompiler::compileVectorFNeg(LLVM::Type VectorTy) noexcept { |
1287 | 782 | compileVectorOp(VectorTy, |
1288 | 782 | [this](auto V) noexcept { return Builder.createFNeg(V); }); |
1289 | 782 | } |
1290 | | |
1291 | 279 | void FunctionCompiler::compileVectorFSqrt(LLVM::Type VectorTy) noexcept { |
1292 | 279 | compileVectorOp(VectorTy, [this](auto V) noexcept { |
1293 | 279 | assuming(LLVM::Core::Sqrt != LLVM::Core::NotIntrinsic); |
1294 | 279 | return Builder.createUnaryIntrinsic(LLVM::Core::Sqrt, V); |
1295 | 279 | }); |
1296 | 279 | } |
1297 | | |
1298 | 2.04k | void FunctionCompiler::compileVectorFTrunc(LLVM::Type VectorTy) noexcept { |
1299 | 2.04k | compileVectorOp(VectorTy, [this](auto V) noexcept { |
1300 | 2.04k | assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic); |
1301 | 2.04k | return Builder.createUnaryIntrinsic(LLVM::Core::Trunc, V); |
1302 | 2.04k | }); |
1303 | 2.04k | } |
1304 | | |
1305 | | void FunctionCompiler::compileVectorLoadOp(unsigned MemoryIndex, |
1306 | | uint64_t Offset, unsigned Alignment, |
1307 | 4.87k | LLVM::Type LoadTy) noexcept { |
1308 | 4.87k | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy); |
1309 | 4.87k | Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty); |
1310 | 4.87k | } |
1311 | | |
1312 | | void FunctionCompiler::compileVectorLoadOp(unsigned MemoryIndex, |
1313 | | uint64_t Offset, unsigned Alignment, |
1314 | | LLVM::Type LoadTy, |
1315 | | LLVM::Type ExtendTy, |
1316 | 1.61k | bool Signed) noexcept { |
1317 | 1.61k | compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy, ExtendTy, Signed); |
1318 | 1.61k | Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty); |
1319 | 1.61k | } |
1320 | | |
1321 | 720 | void FunctionCompiler::compileVectorLShr(LLVM::Type VectorTy) noexcept { |
1322 | 720 | compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1323 | 720 | return Builder.createLShr(LHS, RHS); |
1324 | 720 | }); |
1325 | 720 | } |
1326 | | |
1327 | | void FunctionCompiler::compileVectorNarrow(LLVM::Type FromTy, |
1328 | 683 | bool Signed) noexcept { |
1329 | 683 | auto [MinInt, |
1330 | 683 | MaxInt] = [&]() noexcept -> std::tuple<LLVM::Value, LLVM::Value> { |
1331 | 683 | switch (FromTy.getElementType().getIntegerBitWidth()) { |
1332 | 280 | case 16: { |
1333 | 280 | const auto Min = |
1334 | 280 | static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::min() |
1335 | 280 | : std::numeric_limits<uint8_t>::min()); |
1336 | 280 | const auto Max = |
1337 | 280 | static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::max() |
1338 | 280 | : std::numeric_limits<uint8_t>::max()); |
1339 | 280 | return {LLContext.getInt16(static_cast<uint16_t>(Min)), |
1340 | 280 | LLContext.getInt16(static_cast<uint16_t>(Max))}; |
1341 | 0 | } |
1342 | 403 | case 32: { |
1343 | 403 | const auto Min = |
1344 | 403 | static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::min() |
1345 | 403 | : std::numeric_limits<uint16_t>::min()); |
1346 | 403 | const auto Max = |
1347 | 403 | static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::max() |
1348 | 403 | : std::numeric_limits<uint16_t>::max()); |
1349 | 403 | return {LLContext.getInt32(static_cast<uint32_t>(Min)), |
1350 | 403 | LLContext.getInt32(static_cast<uint32_t>(Max))}; |
1351 | 0 | } |
1352 | 0 | default: |
1353 | 0 | assumingUnreachable(); |
1354 | 683 | } |
1355 | 683 | }(); |
1356 | 683 | const auto Count = FromTy.getVectorSize(); |
1357 | 683 | auto VMin = Builder.createVectorSplat(Count, MinInt); |
1358 | 683 | auto VMax = Builder.createVectorSplat(Count, MaxInt); |
1359 | | |
1360 | 683 | auto TruncTy = FromTy.getTruncatedElementVectorType(); |
1361 | | |
1362 | 683 | auto F2 = Builder.createBitCast(stackPop(), FromTy); |
1363 | 683 | F2 = Builder.createSelect(Builder.createICmpSLT(F2, VMin), VMin, F2); |
1364 | 683 | F2 = Builder.createSelect(Builder.createICmpSGT(F2, VMax), VMax, F2); |
1365 | 683 | F2 = Builder.createTrunc(F2, TruncTy); |
1366 | | |
1367 | 683 | auto F1 = Builder.createBitCast(stackPop(), FromTy); |
1368 | 683 | F1 = Builder.createSelect(Builder.createICmpSLT(F1, VMin), VMin, F1); |
1369 | 683 | F1 = Builder.createSelect(Builder.createICmpSGT(F1, VMax), VMax, F1); |
1370 | 683 | F1 = Builder.createTrunc(F1, TruncTy); |
1371 | | |
1372 | 683 | std::vector<uint32_t> Mask(Count * 2); |
1373 | 683 | std::iota(Mask.begin(), Mask.end(), 0); |
1374 | 683 | auto V = Endian::native == Endian::little |
1375 | 683 | ? Builder.createShuffleVector( |
1376 | 683 | F1, F2, LLVM::Value::getConstVector32(LLContext, Mask)) |
1377 | 683 | : Builder.createShuffleVector( |
1378 | 0 | F2, F1, LLVM::Value::getConstVector32(LLContext, Mask)); |
1379 | 683 | stackPush(Builder.createBitCast(V, Context.Int64x2Ty)); |
1380 | 683 | } |
1381 | | |
1382 | 3.19k | void FunctionCompiler::compileVectorNeg(LLVM::Type VectorTy) noexcept { |
1383 | 3.19k | compileVectorOp(VectorTy, |
1384 | 3.19k | [this](auto V) noexcept { return Builder.createNeg(V); }); |
1385 | 3.19k | } |
1386 | | |
1387 | 140 | void FunctionCompiler::compileVectorPopcnt() noexcept { |
1388 | 140 | compileVectorOp(Context.Int8x16Ty, [this](auto V) noexcept { |
1389 | 140 | assuming(LLVM::Core::Ctpop != LLVM::Core::NotIntrinsic); |
1390 | 140 | return Builder.createUnaryIntrinsic(LLVM::Core::Ctpop, V); |
1391 | 140 | }); |
1392 | 140 | } |
1393 | | |
1394 | 789 | void FunctionCompiler::compileVectorPromote() noexcept { |
1395 | 789 | compileVectorOp(Context.Floatx4Ty, [this](auto V) noexcept { |
1396 | 789 | auto UndefV = LLVM::Value::getUndef(V.getType()); |
1397 | 789 | auto Low = Builder.createShuffleVector( |
1398 | 789 | V, UndefV, LLVM::Value::getConstVector32(LLContext, {0u, 1u})); |
1399 | 789 | return Builder.createFPExt(Low, |
1400 | 789 | LLVM::Type::getVectorType(Context.DoubleTy, 2)); |
1401 | 789 | }); |
1402 | 789 | } |
1403 | | |
1404 | 14 | void FunctionCompiler::compileVectorRelaxedIntegerDotProduct() noexcept { |
1405 | 14 | auto OriTy = Context.Int8x16Ty; |
1406 | 14 | auto ExtTy = Context.Int16x8Ty; |
1407 | 14 | auto RHS = Builder.createBitCast(stackPop(), OriTy); |
1408 | 14 | auto LHS = Builder.createBitCast(stackPop(), OriTy); |
1409 | 14 | #if defined(__x86_64__) |
1410 | 14 | if (Context.SupportSSSE3) { |
1411 | 14 | assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic); |
1412 | | // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS) |
1413 | | // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both |
1414 | | // side to match the WebAssembly spec |
1415 | 14 | return stackPush(Builder.createBitCast( |
1416 | 14 | Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {}, |
1417 | 14 | {RHS, LHS}), |
1418 | 14 | Context.Int64x2Ty)); |
1419 | 14 | } |
1420 | 0 | #endif |
1421 | 0 | auto Width = LLVM::Value::getConstInt( |
1422 | 0 | ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth()); |
1423 | 0 | Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width); |
1424 | 0 | auto EA = Builder.createBitCast(LHS, ExtTy); |
1425 | 0 | auto EB = Builder.createBitCast(RHS, ExtTy); |
1426 | |
|
1427 | 0 | LLVM::Value AL, AR, BL, BR; |
1428 | 0 | AL = Builder.createAShr(EA, Width); |
1429 | 0 | AR = Builder.createAShr(Builder.createShl(EA, Width), Width); |
1430 | 0 | BL = Builder.createAShr(EB, Width); |
1431 | 0 | BR = Builder.createAShr(Builder.createShl(EB, Width), Width); |
1432 | |
|
1433 | 0 | return stackPush(Builder.createBitCast( |
1434 | 0 | Builder.createAdd(Builder.createMul(AL, BL), Builder.createMul(AR, BR)), |
1435 | 0 | Context.Int64x2Ty)); |
1436 | 14 | } |
1437 | | |
1438 | 12 | void FunctionCompiler::compileVectorRelaxedIntegerDotProductAdd() noexcept { |
1439 | 12 | auto OriTy = Context.Int8x16Ty; |
1440 | 12 | auto ExtTy = Context.Int16x8Ty; |
1441 | 12 | auto FinTy = Context.Int32x4Ty; |
1442 | 12 | auto VC = Builder.createBitCast(stackPop(), FinTy); |
1443 | 12 | auto RHS = Builder.createBitCast(stackPop(), OriTy); |
1444 | 12 | auto LHS = Builder.createBitCast(stackPop(), OriTy); |
1445 | 12 | LLVM::Value IM; |
1446 | 12 | #if defined(__x86_64__) |
1447 | 12 | if (Context.SupportSSSE3) { |
1448 | 12 | assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic); |
1449 | | // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS) |
1450 | | // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both |
1451 | | // side to match the WebAssembly spec |
1452 | 12 | IM = Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {}, |
1453 | 12 | {RHS, LHS}); |
1454 | 12 | } else |
1455 | 0 | #endif |
1456 | 0 | { |
1457 | 0 | auto Width = LLVM::Value::getConstInt( |
1458 | 0 | ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth()); |
1459 | 0 | Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width); |
1460 | 0 | auto EA = Builder.createBitCast(LHS, ExtTy); |
1461 | 0 | auto EB = Builder.createBitCast(RHS, ExtTy); |
1462 | |
|
1463 | 0 | LLVM::Value AL, AR, BL, BR; |
1464 | 0 | AL = Builder.createAShr(EA, Width); |
1465 | 0 | AR = Builder.createAShr(Builder.createShl(EA, Width), Width); |
1466 | 0 | BL = Builder.createAShr(EB, Width); |
1467 | 0 | BR = Builder.createAShr(Builder.createShl(EB, Width), Width); |
1468 | 0 | IM = |
1469 | 0 | Builder.createAdd(Builder.createMul(AL, BL), Builder.createMul(AR, BR)); |
1470 | 0 | } |
1471 | | |
1472 | 12 | auto Width = LLVM::Value::getConstInt( |
1473 | 12 | FinTy.getElementType(), ExtTy.getElementType().getIntegerBitWidth()); |
1474 | 12 | Width = Builder.createVectorSplat(FinTy.getVectorSize(), Width); |
1475 | 12 | auto IME = Builder.createBitCast(IM, FinTy); |
1476 | 12 | auto L = Builder.createAShr(IME, Width); |
1477 | 12 | auto R = Builder.createAShr(Builder.createShl(IME, Width), Width); |
1478 | | |
1479 | 12 | return stackPush(Builder.createBitCast( |
1480 | 12 | Builder.createAdd(Builder.createAdd(L, R), VC), Context.Int64x2Ty)); |
1481 | 12 | } |
1482 | | |
1483 | 1.42k | void FunctionCompiler::compileVectorShl(LLVM::Type VectorTy) noexcept { |
1484 | 1.42k | compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1485 | 1.42k | return Builder.createShl(LHS, RHS); |
1486 | 1.42k | }); |
1487 | 1.42k | } |
1488 | | |
1489 | 105 | void FunctionCompiler::compileVectorSwizzle() noexcept { |
1490 | 105 | auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty); |
1491 | 105 | auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty); |
1492 | | |
1493 | 105 | #if defined(__x86_64__) |
1494 | 105 | if (Context.SupportSSSE3) { |
1495 | 105 | auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112)); |
1496 | 105 | auto Added = Builder.createAdd(Index, Magic); |
1497 | 105 | auto NewIndex = Builder.createSelect( |
1498 | 105 | Builder.createICmpUGT(Index, Added), |
1499 | 105 | LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added); |
1500 | 105 | assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic); |
1501 | 105 | stackPush(Builder.createBitCast( |
1502 | 105 | Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {}, |
1503 | 105 | {Vector, NewIndex}), |
1504 | 105 | Context.Int64x2Ty)); |
1505 | 105 | return; |
1506 | 105 | } |
1507 | 0 | #endif |
1508 | | |
1509 | | #if defined(__aarch64__) |
1510 | | if (Context.SupportNEON) { |
1511 | | assuming(LLVM::Core::AArch64NeonTbl1 != LLVM::Core::NotIntrinsic); |
1512 | | stackPush(Builder.createBitCast( |
1513 | | Builder.createIntrinsic(LLVM::Core::AArch64NeonTbl1, |
1514 | | {Context.Int8x16Ty}, {Vector, Index}), |
1515 | | Context.Int64x2Ty)); |
1516 | | return; |
1517 | | } |
1518 | | #endif |
1519 | | |
1520 | 0 | auto Mask = Builder.createVectorSplat(16, LLContext.getInt8(15)); |
1521 | 0 | auto Zero = Builder.createVectorSplat(16, LLContext.getInt8(0)); |
1522 | |
|
1523 | | #if defined(__s390x__) |
1524 | | assuming(LLVM::Core::S390VPerm != LLVM::Core::NotIntrinsic); |
1525 | | auto Exceed = Builder.createICmpULE(Index, Mask); |
1526 | | Index = Builder.createSub(Mask, Index); |
1527 | | auto Result = |
1528 | | Builder.createIntrinsic(LLVM::Core::S390VPerm, {}, {Vector, Zero, Index}); |
1529 | | Result = Builder.createSelect(Exceed, Result, Zero); |
1530 | | stackPush(Builder.createBitCast(Result, Context.Int64x2Ty)); |
1531 | | return; |
1532 | | #endif |
1533 | | |
1534 | | // Fallback case. |
1535 | | // If the SSSE3 is not supported on the x86_64 platform or |
1536 | | // the NEON is not supported on the aarch64 platform, |
1537 | | // then fallback to this. |
1538 | 0 | auto IsOver = Builder.createICmpUGT(Index, Mask); |
1539 | 0 | auto InboundIndex = Builder.createAnd(Index, Mask); |
1540 | 0 | auto Array = Builder.createArray(16, 1); |
1541 | 0 | for (size_t I = 0; I < 16; ++I) { |
1542 | 0 | Builder.createStore( |
1543 | 0 | Builder.createExtractElement(Vector, LLContext.getInt64(I)), |
1544 | 0 | Builder.createInBoundsGEP1(Context.Int8Ty, Array, |
1545 | 0 | LLContext.getInt64(I))); |
1546 | 0 | } |
1547 | 0 | LLVM::Value Ret = LLVM::Value::getUndef(Context.Int8x16Ty); |
1548 | 0 | for (size_t I = 0; I < 16; ++I) { |
1549 | 0 | auto Idx = |
1550 | 0 | Builder.createExtractElement(InboundIndex, LLContext.getInt64(I)); |
1551 | 0 | auto Value = Builder.createLoad( |
1552 | 0 | Context.Int8Ty, Builder.createInBoundsGEP1(Context.Int8Ty, Array, Idx)); |
1553 | 0 | Ret = Builder.createInsertElement(Ret, Value, LLContext.getInt64(I)); |
1554 | 0 | } |
1555 | 0 | Ret = Builder.createSelect(IsOver, Zero, Ret); |
1556 | 0 | stackPush(Builder.createBitCast(Ret, Context.Int64x2Ty)); |
1557 | 0 | } |
1558 | | |
1559 | | void FunctionCompiler::compileVectorTruncSatS32(LLVM::Type VectorTy, |
1560 | 955 | bool PadZero) noexcept { |
1561 | 955 | compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept { |
1562 | 955 | const auto Size = VectorTy.getVectorSize(); |
1563 | 955 | auto FPTy = VectorTy.getElementType(); |
1564 | 955 | auto IntMin = LLContext.getInt32( |
1565 | 955 | static_cast<uint32_t>(std::numeric_limits<int32_t>::min())); |
1566 | 955 | auto IntMax = LLContext.getInt32( |
1567 | 955 | static_cast<uint32_t>(std::numeric_limits<int32_t>::max())); |
1568 | 955 | auto IntMinV = Builder.createVectorSplat(Size, IntMin); |
1569 | 955 | auto IntMaxV = Builder.createVectorSplat(Size, IntMax); |
1570 | 955 | auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType()); |
1571 | 955 | auto FPMin = Builder.createSIToFP(IntMin, FPTy); |
1572 | 955 | auto FPMax = Builder.createSIToFP(IntMax, FPTy); |
1573 | 955 | auto FPMinV = Builder.createVectorSplat(Size, FPMin); |
1574 | 955 | auto FPMaxV = Builder.createVectorSplat(Size, FPMax); |
1575 | | |
1576 | 955 | auto Normal = Builder.createFCmpORD(V, V); |
1577 | 955 | auto NotUnder = Builder.createFCmpUGE(V, FPMinV); |
1578 | 955 | auto NotOver = Builder.createFCmpULT(V, FPMaxV); |
1579 | 955 | V = Builder.createFPToSI( |
1580 | 955 | V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size)); |
1581 | 955 | V = Builder.createSelect(Normal, V, IntZeroV); |
1582 | 955 | V = Builder.createSelect(NotUnder, V, IntMinV); |
1583 | 955 | V = Builder.createSelect(NotOver, V, IntMaxV); |
1584 | 955 | if (PadZero) { |
1585 | 756 | std::vector<uint32_t> Mask(Size * 2); |
1586 | 756 | std::iota(Mask.begin(), Mask.end(), 0); |
1587 | 756 | if constexpr (Endian::native == Endian::little) { |
1588 | 756 | V = Builder.createShuffleVector( |
1589 | 756 | V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask)); |
1590 | | } else { |
1591 | | V = Builder.createShuffleVector( |
1592 | | IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask)); |
1593 | | } |
1594 | 756 | } |
1595 | 955 | return V; |
1596 | 955 | }); |
1597 | 955 | } |
1598 | | |
1599 | | void FunctionCompiler::compileVectorTruncSatU32(LLVM::Type VectorTy, |
1600 | 5.97k | bool PadZero) noexcept { |
1601 | 5.97k | compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept { |
1602 | 5.97k | const auto Size = VectorTy.getVectorSize(); |
1603 | 5.97k | auto FPTy = VectorTy.getElementType(); |
1604 | 5.97k | auto IntMin = LLContext.getInt32(std::numeric_limits<uint32_t>::min()); |
1605 | 5.97k | auto IntMax = LLContext.getInt32(std::numeric_limits<uint32_t>::max()); |
1606 | 5.97k | auto IntMinV = Builder.createVectorSplat(Size, IntMin); |
1607 | 5.97k | auto IntMaxV = Builder.createVectorSplat(Size, IntMax); |
1608 | 5.97k | auto FPMin = Builder.createUIToFP(IntMin, FPTy); |
1609 | 5.97k | auto FPMax = Builder.createUIToFP(IntMax, FPTy); |
1610 | 5.97k | auto FPMinV = Builder.createVectorSplat(Size, FPMin); |
1611 | 5.97k | auto FPMaxV = Builder.createVectorSplat(Size, FPMax); |
1612 | | |
1613 | 5.97k | auto NotUnder = Builder.createFCmpOGE(V, FPMinV); |
1614 | 5.97k | auto NotOver = Builder.createFCmpULT(V, FPMaxV); |
1615 | 5.97k | V = Builder.createFPToUI( |
1616 | 5.97k | V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size)); |
1617 | 5.97k | V = Builder.createSelect(NotUnder, V, IntMinV); |
1618 | 5.97k | V = Builder.createSelect(NotOver, V, IntMaxV); |
1619 | 5.97k | if (PadZero) { |
1620 | 2.18k | auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType()); |
1621 | 2.18k | std::vector<uint32_t> Mask(Size * 2); |
1622 | 2.18k | std::iota(Mask.begin(), Mask.end(), 0); |
1623 | 2.18k | if constexpr (Endian::native == Endian::little) { |
1624 | 2.18k | V = Builder.createShuffleVector( |
1625 | 2.18k | V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask)); |
1626 | | } else { |
1627 | | V = Builder.createShuffleVector( |
1628 | | IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask)); |
1629 | | } |
1630 | 2.18k | } |
1631 | 5.97k | return V; |
1632 | 5.97k | }); |
1633 | 5.97k | } |
1634 | | |
1635 | 406 | void FunctionCompiler::compileVectorVectorAdd(LLVM::Type VectorTy) noexcept { |
1636 | 406 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1637 | 406 | return Builder.createAdd(LHS, RHS); |
1638 | 406 | }); |
1639 | 406 | } |
1640 | | |
1641 | | void FunctionCompiler::compileVectorVectorAddSat(LLVM::Type VectorTy, |
1642 | 991 | bool Signed) noexcept { |
1643 | 991 | auto ID = Signed ? LLVM::Core::SAddSat : LLVM::Core::UAddSat; |
1644 | 991 | assuming(ID != LLVM::Core::NotIntrinsic); |
1645 | 991 | compileVectorVectorOp( |
1646 | 991 | VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept { |
1647 | 991 | return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS}); |
1648 | 991 | }); |
1649 | 991 | } |
1650 | | |
1651 | 171 | void FunctionCompiler::compileVectorVectorFAdd(LLVM::Type VectorTy) noexcept { |
1652 | 171 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1653 | 171 | return Builder.createFAdd(LHS, RHS); |
1654 | 171 | }); |
1655 | 171 | } |
1656 | | |
1657 | 198 | void FunctionCompiler::compileVectorVectorFDiv(LLVM::Type VectorTy) noexcept { |
1658 | 198 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1659 | 198 | return Builder.createFDiv(LHS, RHS); |
1660 | 198 | }); |
1661 | 198 | } |
1662 | | |
1663 | 209 | void FunctionCompiler::compileVectorVectorFMax(LLVM::Type VectorTy) noexcept { |
1664 | 209 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1665 | 209 | auto LNaN = Builder.createFCmpUNO(LHS, LHS); |
1666 | 209 | auto RNaN = Builder.createFCmpUNO(RHS, RHS); |
1667 | 209 | auto OLT = Builder.createFCmpOLT(LHS, RHS); |
1668 | 209 | auto OGT = Builder.createFCmpOGT(LHS, RHS); |
1669 | 209 | auto Ret = Builder.createBitCast( |
1670 | 209 | Builder.createAnd(Builder.createBitCast(LHS, Context.Int64x2Ty), |
1671 | 209 | Builder.createBitCast(RHS, Context.Int64x2Ty)), |
1672 | 209 | LHS.getType()); |
1673 | 209 | Ret = Builder.createSelect(OLT, RHS, Ret); |
1674 | 209 | Ret = Builder.createSelect(OGT, LHS, Ret); |
1675 | 209 | Ret = Builder.createSelect(LNaN, LHS, Ret); |
1676 | 209 | Ret = Builder.createSelect(RNaN, RHS, Ret); |
1677 | 209 | return Ret; |
1678 | 209 | }); |
1679 | 209 | } |
1680 | | |
1681 | 344 | void FunctionCompiler::compileVectorVectorFMin(LLVM::Type VectorTy) noexcept { |
1682 | 344 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1683 | 344 | auto LNaN = Builder.createFCmpUNO(LHS, LHS); |
1684 | 344 | auto RNaN = Builder.createFCmpUNO(RHS, RHS); |
1685 | 344 | auto OLT = Builder.createFCmpOLT(LHS, RHS); |
1686 | 344 | auto OGT = Builder.createFCmpOGT(LHS, RHS); |
1687 | 344 | auto Ret = Builder.createBitCast( |
1688 | 344 | Builder.createOr(Builder.createBitCast(LHS, Context.Int64x2Ty), |
1689 | 344 | Builder.createBitCast(RHS, Context.Int64x2Ty)), |
1690 | 344 | LHS.getType()); |
1691 | 344 | Ret = Builder.createSelect(OGT, RHS, Ret); |
1692 | 344 | Ret = Builder.createSelect(OLT, LHS, Ret); |
1693 | 344 | Ret = Builder.createSelect(LNaN, LHS, Ret); |
1694 | 344 | Ret = Builder.createSelect(RNaN, RHS, Ret); |
1695 | 344 | return Ret; |
1696 | 344 | }); |
1697 | 344 | } |
1698 | | |
1699 | 269 | void FunctionCompiler::compileVectorVectorFMul(LLVM::Type VectorTy) noexcept { |
1700 | 269 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1701 | 269 | return Builder.createFMul(LHS, RHS); |
1702 | 269 | }); |
1703 | 269 | } |
1704 | | |
1705 | 325 | void FunctionCompiler::compileVectorVectorFPMax(LLVM::Type VectorTy) noexcept { |
1706 | 325 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1707 | 325 | auto Cmp = Builder.createFCmpOGT(RHS, LHS); |
1708 | 325 | return Builder.createSelect(Cmp, RHS, LHS); |
1709 | 325 | }); |
1710 | 325 | } |
1711 | | |
1712 | 332 | void FunctionCompiler::compileVectorVectorFPMin(LLVM::Type VectorTy) noexcept { |
1713 | 332 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1714 | 332 | auto Cmp = Builder.createFCmpOLT(RHS, LHS); |
1715 | 332 | return Builder.createSelect(Cmp, RHS, LHS); |
1716 | 332 | }); |
1717 | 332 | } |
1718 | | |
1719 | 467 | void FunctionCompiler::compileVectorVectorFSub(LLVM::Type VectorTy) noexcept { |
1720 | 467 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1721 | 467 | return Builder.createFSub(LHS, RHS); |
1722 | 467 | }); |
1723 | 467 | } |
1724 | | |
1725 | 27 | void FunctionCompiler::compileVectorVectorMAdd(LLVM::Type VectorTy) noexcept { |
1726 | 27 | auto C = Builder.createBitCast(stackPop(), VectorTy); |
1727 | 27 | auto RHS = Builder.createBitCast(stackPop(), VectorTy); |
1728 | 27 | auto LHS = Builder.createBitCast(stackPop(), VectorTy); |
1729 | 27 | stackPush(Builder.createBitCast( |
1730 | 27 | Builder.createFAdd(Builder.createFMul(LHS, RHS), C), Context.Int64x2Ty)); |
1731 | 27 | } |
1732 | | |
1733 | 362 | void FunctionCompiler::compileVectorVectorMul(LLVM::Type VectorTy) noexcept { |
1734 | 362 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1735 | 362 | return Builder.createMul(LHS, RHS); |
1736 | 362 | }); |
1737 | 362 | } |
1738 | | |
1739 | 89 | void FunctionCompiler::compileVectorVectorNMAdd(LLVM::Type VectorTy) noexcept { |
1740 | 89 | auto C = Builder.createBitCast(stackPop(), VectorTy); |
1741 | 89 | auto RHS = Builder.createBitCast(stackPop(), VectorTy); |
1742 | 89 | auto LHS = Builder.createBitCast(stackPop(), VectorTy); |
1743 | 89 | stackPush(Builder.createBitCast( |
1744 | 89 | Builder.createFAdd(Builder.createFMul(Builder.createFNeg(LHS), RHS), C), |
1745 | 89 | Context.Int64x2Ty)); |
1746 | 89 | } |
1747 | | |
1748 | 162 | void FunctionCompiler::compileVectorVectorQ15MulSat() noexcept { |
1749 | 162 | compileVectorVectorOp( |
1750 | 162 | Context.Int16x8Ty, [this](auto LHS, auto RHS) noexcept -> LLVM::Value { |
1751 | 162 | #if defined(__x86_64__) |
1752 | 162 | if (Context.SupportSSSE3) { |
1753 | 162 | assuming(LLVM::Core::X86SSSE3PMulHrSw128 != LLVM::Core::NotIntrinsic); |
1754 | 162 | auto Result = Builder.createIntrinsic(LLVM::Core::X86SSSE3PMulHrSw128, |
1755 | 162 | {}, {LHS, RHS}); |
1756 | 162 | auto IntMaxV = Builder.createVectorSplat( |
1757 | 162 | 8, LLContext.getInt16(UINT16_C(0x8000))); |
1758 | 162 | auto NotOver = Builder.createSExt( |
1759 | 162 | Builder.createICmpEQ(Result, IntMaxV), Context.Int16x8Ty); |
1760 | 162 | return Builder.createXor(Result, NotOver); |
1761 | 162 | } |
1762 | 0 | #endif |
1763 | | |
1764 | | #if defined(__aarch64__) |
1765 | | if (Context.SupportNEON) { |
1766 | | assuming(LLVM::Core::AArch64NeonSQRDMulH != LLVM::Core::NotIntrinsic); |
1767 | | return Builder.createBinaryIntrinsic(LLVM::Core::AArch64NeonSQRDMulH, |
1768 | | LHS, RHS); |
1769 | | } |
1770 | | #endif |
1771 | | |
1772 | | // Fallback case. |
1773 | | // If the SSSE3 is not supported on the x86_64 platform or |
1774 | | // the NEON is not supported on the aarch64 platform, |
1775 | | // then fallback to this. |
1776 | 0 | auto ExtTy = Context.Int16x8Ty.getExtendedElementVectorType(); |
1777 | 0 | auto Offset = |
1778 | 0 | Builder.createVectorSplat(8, LLContext.getInt32(UINT32_C(0x4000))); |
1779 | 0 | auto Shift = |
1780 | 0 | Builder.createVectorSplat(8, LLContext.getInt32(UINT32_C(15))); |
1781 | 0 | auto ExtLHS = Builder.createSExt(LHS, ExtTy); |
1782 | 0 | auto ExtRHS = Builder.createSExt(RHS, ExtTy); |
1783 | 0 | auto Result = Builder.createTrunc( |
1784 | 0 | Builder.createAShr( |
1785 | 0 | Builder.createAdd(Builder.createMul(ExtLHS, ExtRHS), Offset), |
1786 | 0 | Shift), |
1787 | 0 | Context.Int16x8Ty); |
1788 | 0 | auto IntMaxV = |
1789 | 0 | Builder.createVectorSplat(8, LLContext.getInt16(UINT16_C(0x8000))); |
1790 | 0 | auto NotOver = Builder.createSExt(Builder.createICmpEQ(Result, IntMaxV), |
1791 | 0 | Context.Int16x8Ty); |
1792 | 0 | return Builder.createXor(Result, NotOver); |
1793 | 162 | }); |
1794 | 162 | } |
1795 | | |
1796 | 497 | void FunctionCompiler::compileVectorVectorSMax(LLVM::Type VectorTy) noexcept { |
1797 | 497 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1798 | 497 | return Builder.createIntrinsic(LLVM::Core::SMax, {LHS.getType()}, |
1799 | 497 | {LHS, RHS}); |
1800 | 497 | }); |
1801 | 497 | } |
1802 | | |
1803 | 321 | void FunctionCompiler::compileVectorVectorSMin(LLVM::Type VectorTy) noexcept { |
1804 | 321 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1805 | 321 | return Builder.createIntrinsic(LLVM::Core::SMin, {LHS.getType()}, |
1806 | 321 | {LHS, RHS}); |
1807 | 321 | }); |
1808 | 321 | } |
1809 | | |
1810 | 705 | void FunctionCompiler::compileVectorVectorSub(LLVM::Type VectorTy) noexcept { |
1811 | 705 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1812 | 705 | return Builder.createSub(LHS, RHS); |
1813 | 705 | }); |
1814 | 705 | } |
1815 | | |
1816 | | void FunctionCompiler::compileVectorVectorSubSat(LLVM::Type VectorTy, |
1817 | 392 | bool Signed) noexcept { |
1818 | 392 | auto ID = Signed ? LLVM::Core::SSubSat : LLVM::Core::USubSat; |
1819 | 392 | assuming(ID != LLVM::Core::NotIntrinsic); |
1820 | 392 | compileVectorVectorOp( |
1821 | 392 | VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept { |
1822 | 392 | return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS}); |
1823 | 392 | }); |
1824 | 392 | } |
1825 | | |
1826 | 261 | void FunctionCompiler::compileVectorVectorUAvgr(LLVM::Type VectorTy) noexcept { |
1827 | 261 | auto ExtendTy = VectorTy.getExtendedElementVectorType(); |
1828 | 261 | compileVectorVectorOp( |
1829 | 261 | VectorTy, |
1830 | 261 | [this, VectorTy, ExtendTy](auto LHS, auto RHS) noexcept -> LLVM::Value { |
1831 | 261 | #if defined(__x86_64__) |
1832 | 261 | if (Context.SupportSSE2) { |
1833 | 261 | const auto ID = [VectorTy]() noexcept { |
1834 | 261 | switch (VectorTy.getElementType().getIntegerBitWidth()) { |
1835 | 151 | case 8: |
1836 | 151 | return LLVM::Core::X86SSE2PAvgB; |
1837 | 110 | case 16: |
1838 | 110 | return LLVM::Core::X86SSE2PAvgW; |
1839 | 0 | default: |
1840 | 0 | assumingUnreachable(); |
1841 | 261 | } |
1842 | 261 | }(); |
1843 | 261 | assuming(ID != LLVM::Core::NotIntrinsic); |
1844 | 261 | return Builder.createIntrinsic(ID, {}, {LHS, RHS}); |
1845 | 261 | } |
1846 | 0 | #endif |
1847 | | |
1848 | | #if defined(__aarch64__) |
1849 | | if (Context.SupportNEON) { |
1850 | | assuming(LLVM::Core::AArch64NeonURHAdd != LLVM::Core::NotIntrinsic); |
1851 | | return Builder.createBinaryIntrinsic(LLVM::Core::AArch64NeonURHAdd, |
1852 | | LHS, RHS); |
1853 | | } |
1854 | | #endif |
1855 | | |
1856 | | // Fallback case. |
1857 | | // If the SSE2 is not supported on the x86_64 platform or |
1858 | | // the NEON is not supported on the aarch64 platform, |
1859 | | // then fallback to this. |
1860 | 0 | auto EL = Builder.createZExt(LHS, ExtendTy); |
1861 | 0 | auto ER = Builder.createZExt(RHS, ExtendTy); |
1862 | 0 | auto One = Builder.createZExt( |
1863 | 0 | Builder.createVectorSplat(ExtendTy.getVectorSize(), |
1864 | 0 | LLContext.getTrue()), |
1865 | 0 | ExtendTy); |
1866 | 0 | return Builder.createTrunc( |
1867 | 0 | Builder.createLShr( |
1868 | 0 | Builder.createAdd(Builder.createAdd(EL, ER), One), One), |
1869 | 0 | VectorTy); |
1870 | 261 | }); |
1871 | 261 | } |
1872 | | |
1873 | 706 | void FunctionCompiler::compileVectorVectorUMax(LLVM::Type VectorTy) noexcept { |
1874 | 706 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1875 | 706 | return Builder.createIntrinsic(LLVM::Core::UMax, {LHS.getType()}, |
1876 | 706 | {LHS, RHS}); |
1877 | 706 | }); |
1878 | 706 | } |
1879 | | |
1880 | 281 | void FunctionCompiler::compileVectorVectorUMin(LLVM::Type VectorTy) noexcept { |
1881 | 281 | compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept { |
1882 | 281 | return Builder.createIntrinsic(LLVM::Core::UMin, {LHS.getType()}, |
1883 | 281 | {LHS, RHS}); |
1884 | 281 | }); |
1885 | 281 | } |
1886 | | |
1887 | | } // namespace WasmEdge |