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