Coverage Report

Created: 2026-08-08 06:32

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