Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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