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