Coverage Report

Created: 2026-08-14 06:41

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
123k
FunctionCompiler::compileVectorOp(const AST::Instruction &Instr) noexcept {
14
123k
  switch (Instr.getOpCode()) {
15
4.94k
  case OpCode::V128__load:
16
4.94k
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
17
4.94k
                        Instr.getMemoryAlign(), Context.Int128x1Ty);
18
4.94k
    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
327
  case OpCode::V128__load16x4_s:
30
327
    compileVectorLoadOp(
31
327
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
32
327
        LLVM::Type::getVectorType(Context.Int16Ty, 4), Context.Int32x4Ty, true);
33
327
    break;
34
519
  case OpCode::V128__load16x4_u:
35
519
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
36
519
                        Instr.getMemoryAlign(),
37
519
                        LLVM::Type::getVectorType(Context.Int16Ty, 4),
38
519
                        Context.Int32x4Ty, false);
39
519
    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
81
  case OpCode::V128__load8_splat:
52
81
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
53
81
                       Instr.getMemoryAlign(), Context.Int8Ty,
54
81
                       Context.Int8x16Ty);
55
81
    break;
56
155
  case OpCode::V128__load16_splat:
57
155
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
58
155
                       Instr.getMemoryAlign(), Context.Int16Ty,
59
155
                       Context.Int16x8Ty);
60
155
    break;
61
221
  case OpCode::V128__load32_splat:
62
221
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
63
221
                       Instr.getMemoryAlign(), Context.Int32Ty,
64
221
                       Context.Int32x4Ty);
65
221
    break;
66
157
  case OpCode::V128__load64_splat:
67
157
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
68
157
                       Instr.getMemoryAlign(), Context.Int64Ty,
69
157
                       Context.Int64x2Ty);
70
157
    break;
71
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
140
  case OpCode::V128__load64_zero:
77
140
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
78
140
                        Instr.getMemoryAlign(), Context.Int64Ty,
79
140
                        Context.Int128Ty, false);
80
140
    break;
81
235
  case OpCode::V128__store:
82
235
    compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
83
235
                   Instr.getMemoryAlign(), Context.Int128x1Ty, false, true);
84
235
    break;
85
190
  case OpCode::V128__load8_lane:
86
190
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
87
190
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
88
190
                      Context.Int8Ty, Context.Int8x16Ty);
89
190
    break;
90
138
  case OpCode::V128__load16_lane:
91
138
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
92
138
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
93
138
                      Context.Int16Ty, Context.Int16x8Ty);
94
138
    break;
95
130
  case OpCode::V128__load32_lane:
96
130
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
97
130
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
98
130
                      Context.Int32Ty, Context.Int32x4Ty);
99
130
    break;
100
23
  case OpCode::V128__load64_lane:
101
23
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
102
23
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
103
23
                      Context.Int64Ty, Context.Int64x2Ty);
104
23
    break;
105
169
  case OpCode::V128__store8_lane:
106
169
    compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
107
169
                       Instr.getMemoryAlign(), Instr.getMemoryLane(),
108
169
                       Context.Int8Ty, Context.Int8x16Ty);
109
169
    break;
110
80
  case OpCode::V128__store16_lane:
111
80
    compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
112
80
                       Instr.getMemoryAlign(), Instr.getMemoryLane(),
113
80
                       Context.Int16Ty, Context.Int16x8Ty);
114
80
    break;
115
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
353
  case OpCode::V128__const: {
128
353
    const auto Value = Instr.getNum().get<uint64x2_t>();
129
353
    auto Vector =
130
353
        LLVM::Value::getConstVector64(LLContext, {Value[0], Value[1]});
131
353
    stackPush(Builder.createBitCast(Vector, Context.Int64x2Ty));
132
353
    break;
133
0
  }
134
135
  // SIMD Shuffle Instructions
136
18
  case OpCode::I8x16__shuffle: {
137
18
    auto V2 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
138
18
    auto V1 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
139
18
    const auto V3 = Instr.getNum().get<uint128_t>();
140
18
    std::array<uint8_t, 16> Mask;
141
306
    for (size_t I = 0; I < 16; ++I) {
142
288
      auto Num = static_cast<uint8_t>(V3 >> (I * 8));
143
288
      if constexpr (Endian::native == Endian::little) {
144
288
        Mask[I] = Num;
145
      } else {
146
        Mask[15 - I] = Num < 16 ? 15 - Num : 47 - Num;
147
      }
148
288
    }
149
18
    stackPush(Builder.createBitCast(
150
18
        Builder.createShuffleVector(
151
18
            V1, V2, LLVM::Value::getConstVector8(LLContext, Mask)),
152
18
        Context.Int64x2Ty));
153
18
    break;
154
0
  }
155
156
  // SIMD Lane Instructions
157
73
  case OpCode::I8x16__extract_lane_s:
158
73
    compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
159
73
                         Context.Int32Ty, true);
160
73
    break;
161
30
  case OpCode::I8x16__extract_lane_u:
162
30
    compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
163
30
                         Context.Int32Ty, false);
164
30
    break;
165
245
  case OpCode::I8x16__replace_lane:
166
245
    compileReplaceLaneOp(Context.Int8x16Ty, Instr.getMemoryLane());
167
245
    break;
168
450
  case OpCode::I16x8__extract_lane_s:
169
450
    compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
170
450
                         Context.Int32Ty, true);
171
450
    break;
172
409
  case OpCode::I16x8__extract_lane_u:
173
409
    compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
174
409
                         Context.Int32Ty, false);
175
409
    break;
176
334
  case OpCode::I16x8__replace_lane:
177
334
    compileReplaceLaneOp(Context.Int16x8Ty, Instr.getMemoryLane());
178
334
    break;
179
69
  case OpCode::I32x4__extract_lane:
180
69
    compileExtractLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
181
69
    break;
182
225
  case OpCode::I32x4__replace_lane:
183
225
    compileReplaceLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
184
225
    break;
185
133
  case OpCode::I64x2__extract_lane:
186
133
    compileExtractLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
187
133
    break;
188
20
  case OpCode::I64x2__replace_lane:
189
20
    compileReplaceLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
190
20
    break;
191
59
  case OpCode::F32x4__extract_lane:
192
59
    compileExtractLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
193
59
    break;
194
26
  case OpCode::F32x4__replace_lane:
195
26
    compileReplaceLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
196
26
    break;
197
75
  case OpCode::F64x2__extract_lane:
198
75
    compileExtractLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
199
75
    break;
200
14
  case OpCode::F64x2__replace_lane:
201
14
    compileReplaceLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
202
14
    break;
203
204
  // SIMD Numeric Instructions
205
151
  case OpCode::I8x16__swizzle:
206
151
    compileVectorSwizzle();
207
151
    break;
208
38.0k
  case OpCode::I8x16__splat:
209
38.0k
    compileSplatOp(Context.Int8x16Ty);
210
38.0k
    break;
211
9.01k
  case OpCode::I16x8__splat:
212
9.01k
    compileSplatOp(Context.Int16x8Ty);
213
9.01k
    break;
214
1.25k
  case OpCode::I32x4__splat:
215
1.25k
    compileSplatOp(Context.Int32x4Ty);
216
1.25k
    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
59
  case OpCode::F64x2__splat:
224
59
    compileSplatOp(Context.Doublex2Ty);
225
59
    break;
226
99
  case OpCode::I8x16__eq:
227
99
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntEQ);
228
99
    break;
229
461
  case OpCode::I8x16__ne:
230
461
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntNE);
231
461
    break;
232
63
  case OpCode::I8x16__lt_s:
233
63
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLT);
234
63
    break;
235
67
  case OpCode::I8x16__lt_u:
236
67
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULT);
237
67
    break;
238
316
  case OpCode::I8x16__gt_s:
239
316
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGT);
240
316
    break;
241
211
  case OpCode::I8x16__gt_u:
242
211
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGT);
243
211
    break;
244
137
  case OpCode::I8x16__le_s:
245
137
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLE);
246
137
    break;
247
149
  case OpCode::I8x16__le_u:
248
149
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULE);
249
149
    break;
250
530
  case OpCode::I8x16__ge_s:
251
530
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGE);
252
530
    break;
253
93
  case OpCode::I8x16__ge_u:
254
93
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGE);
255
93
    break;
256
252
  case OpCode::I16x8__eq:
257
252
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntEQ);
258
252
    break;
259
175
  case OpCode::I16x8__ne:
260
175
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntNE);
261
175
    break;
262
49
  case OpCode::I16x8__lt_s:
263
49
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLT);
264
49
    break;
265
233
  case OpCode::I16x8__lt_u:
266
233
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULT);
267
233
    break;
268
248
  case OpCode::I16x8__gt_s:
269
248
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGT);
270
248
    break;
271
129
  case OpCode::I16x8__gt_u:
272
129
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGT);
273
129
    break;
274
76
  case OpCode::I16x8__le_s:
275
76
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLE);
276
76
    break;
277
84
  case OpCode::I16x8__le_u:
278
84
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULE);
279
84
    break;
280
146
  case OpCode::I16x8__ge_s:
281
146
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGE);
282
146
    break;
283
70
  case OpCode::I16x8__ge_u:
284
70
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGE);
285
70
    break;
286
65
  case OpCode::I32x4__eq:
287
65
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntEQ);
288
65
    break;
289
98
  case OpCode::I32x4__ne:
290
98
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntNE);
291
98
    break;
292
48
  case OpCode::I32x4__lt_s:
293
48
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLT);
294
48
    break;
295
134
  case OpCode::I32x4__lt_u:
296
134
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULT);
297
134
    break;
298
195
  case OpCode::I32x4__gt_s:
299
195
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGT);
300
195
    break;
301
215
  case OpCode::I32x4__gt_u:
302
215
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGT);
303
215
    break;
304
280
  case OpCode::I32x4__le_s:
305
280
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLE);
306
280
    break;
307
245
  case OpCode::I32x4__le_u:
308
245
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULE);
309
245
    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
49
  case OpCode::I64x2__ne:
320
49
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntNE);
321
49
    break;
322
47
  case OpCode::I64x2__lt_s:
323
47
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLT);
324
47
    break;
325
164
  case OpCode::I64x2__gt_s:
326
164
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGT);
327
164
    break;
328
50
  case OpCode::I64x2__le_s:
329
50
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLE);
330
50
    break;
331
74
  case OpCode::I64x2__ge_s:
332
74
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGE);
333
74
    break;
334
1.36k
  case OpCode::F32x4__eq:
335
1.36k
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOEQ, Context.Int32x4Ty);
336
1.36k
    break;
337
54
  case OpCode::F32x4__ne:
338
54
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealUNE, Context.Int32x4Ty);
339
54
    break;
340
700
  case OpCode::F32x4__lt:
341
700
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLT, Context.Int32x4Ty);
342
700
    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
56
  case OpCode::F64x2__eq:
353
56
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOEQ, Context.Int64x2Ty);
354
56
    break;
355
101
  case OpCode::F64x2__ne:
356
101
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealUNE, Context.Int64x2Ty);
357
101
    break;
358
126
  case OpCode::F64x2__lt:
359
126
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLT, Context.Int64x2Ty);
360
126
    break;
361
57
  case OpCode::F64x2__gt:
362
57
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGT, Context.Int64x2Ty);
363
57
    break;
364
178
  case OpCode::F64x2__le:
365
178
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLE, Context.Int64x2Ty);
366
178
    break;
367
82
  case OpCode::F64x2__ge:
368
82
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGE, Context.Int64x2Ty);
369
82
    break;
370
554
  case OpCode::V128__not:
371
554
    Stack.back() = Builder.createNot(Stack.back());
372
554
    break;
373
136
  case OpCode::V128__and: {
374
136
    auto RHS = stackPop();
375
136
    auto LHS = stackPop();
376
136
    stackPush(Builder.createAnd(LHS, RHS));
377
136
    break;
378
0
  }
379
111
  case OpCode::V128__andnot: {
380
111
    auto RHS = stackPop();
381
111
    auto LHS = stackPop();
382
111
    stackPush(Builder.createAnd(LHS, Builder.createNot(RHS)));
383
111
    break;
384
0
  }
385
123
  case OpCode::V128__or: {
386
123
    auto RHS = stackPop();
387
123
    auto LHS = stackPop();
388
123
    stackPush(Builder.createOr(LHS, RHS));
389
123
    break;
390
0
  }
391
60
  case OpCode::V128__xor: {
392
60
    auto RHS = stackPop();
393
60
    auto LHS = stackPop();
394
60
    stackPush(Builder.createXor(LHS, RHS));
395
60
    break;
396
0
  }
397
131
  case OpCode::V128__bitselect: {
398
131
    auto C = stackPop();
399
131
    auto V2 = stackPop();
400
131
    auto V1 = stackPop();
401
131
    stackPush(
402
131
        Builder.createXor(Builder.createAnd(Builder.createXor(V1, V2), C), V2));
403
131
    break;
404
0
  }
405
162
  case OpCode::V128__any_true:
406
162
    compileVectorAnyTrue();
407
162
    break;
408
1.58k
  case OpCode::I8x16__abs:
409
1.58k
    compileVectorAbs(Context.Int8x16Ty);
410
1.58k
    break;
411
2.65k
  case OpCode::I8x16__neg:
412
2.65k
    compileVectorNeg(Context.Int8x16Ty);
413
2.65k
    break;
414
126
  case OpCode::I8x16__popcnt:
415
126
    compileVectorPopcnt();
416
126
    break;
417
287
  case OpCode::I8x16__all_true:
418
287
    compileVectorAllTrue(Context.Int8x16Ty);
419
287
    break;
420
665
  case OpCode::I8x16__bitmask:
421
665
    compileVectorBitMask(Context.Int8x16Ty);
422
665
    break;
423
94
  case OpCode::I8x16__narrow_i16x8_s:
424
94
    compileVectorNarrow(Context.Int16x8Ty, true);
425
94
    break;
426
199
  case OpCode::I8x16__narrow_i16x8_u:
427
199
    compileVectorNarrow(Context.Int16x8Ty, false);
428
199
    break;
429
111
  case OpCode::I8x16__shl:
430
111
    compileVectorShl(Context.Int8x16Ty);
431
111
    break;
432
1.14k
  case OpCode::I8x16__shr_s:
433
1.14k
    compileVectorAShr(Context.Int8x16Ty);
434
1.14k
    break;
435
86
  case OpCode::I8x16__shr_u:
436
86
    compileVectorLShr(Context.Int8x16Ty);
437
86
    break;
438
45
  case OpCode::I8x16__add:
439
45
    compileVectorVectorAdd(Context.Int8x16Ty);
440
45
    break;
441
494
  case OpCode::I8x16__add_sat_s:
442
494
    compileVectorVectorAddSat(Context.Int8x16Ty, true);
443
494
    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
205
  case OpCode::I8x16__sub_sat_s:
451
205
    compileVectorVectorSubSat(Context.Int8x16Ty, true);
452
205
    break;
453
74
  case OpCode::I8x16__sub_sat_u:
454
74
    compileVectorVectorSubSat(Context.Int8x16Ty, false);
455
74
    break;
456
78
  case OpCode::I8x16__min_s:
457
78
    compileVectorVectorSMin(Context.Int8x16Ty);
458
78
    break;
459
88
  case OpCode::I8x16__min_u:
460
88
    compileVectorVectorUMin(Context.Int8x16Ty);
461
88
    break;
462
314
  case OpCode::I8x16__max_s:
463
314
    compileVectorVectorSMax(Context.Int8x16Ty);
464
314
    break;
465
90
  case OpCode::I8x16__max_u:
466
90
    compileVectorVectorUMax(Context.Int8x16Ty);
467
90
    break;
468
145
  case OpCode::I8x16__avgr_u:
469
145
    compileVectorVectorUAvgr(Context.Int8x16Ty);
470
145
    break;
471
215
  case OpCode::I16x8__abs:
472
215
    compileVectorAbs(Context.Int16x8Ty);
473
215
    break;
474
189
  case OpCode::I16x8__neg:
475
189
    compileVectorNeg(Context.Int16x8Ty);
476
189
    break;
477
151
  case OpCode::I16x8__all_true:
478
151
    compileVectorAllTrue(Context.Int16x8Ty);
479
151
    break;
480
97
  case OpCode::I16x8__bitmask:
481
97
    compileVectorBitMask(Context.Int16x8Ty);
482
97
    break;
483
42
  case OpCode::I16x8__narrow_i32x4_s:
484
42
    compileVectorNarrow(Context.Int32x4Ty, true);
485
42
    break;
486
428
  case OpCode::I16x8__narrow_i32x4_u:
487
428
    compileVectorNarrow(Context.Int32x4Ty, false);
488
428
    break;
489
973
  case OpCode::I16x8__extend_low_i8x16_s:
490
973
    compileVectorExtend(Context.Int8x16Ty, true, true);
491
973
    break;
492
107
  case OpCode::I16x8__extend_high_i8x16_s:
493
107
    compileVectorExtend(Context.Int8x16Ty, true, false);
494
107
    break;
495
361
  case OpCode::I16x8__extend_low_i8x16_u:
496
361
    compileVectorExtend(Context.Int8x16Ty, false, true);
497
361
    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
316
  case OpCode::I16x8__shr_s:
505
316
    compileVectorAShr(Context.Int16x8Ty);
506
316
    break;
507
155
  case OpCode::I16x8__shr_u:
508
155
    compileVectorLShr(Context.Int16x8Ty);
509
155
    break;
510
142
  case OpCode::I16x8__add:
511
142
    compileVectorVectorAdd(Context.Int16x8Ty);
512
142
    break;
513
18
  case OpCode::I16x8__add_sat_s:
514
18
    compileVectorVectorAddSat(Context.Int16x8Ty, true);
515
18
    break;
516
390
  case OpCode::I16x8__add_sat_u:
517
390
    compileVectorVectorAddSat(Context.Int16x8Ty, false);
518
390
    break;
519
328
  case OpCode::I16x8__sub:
520
328
    compileVectorVectorSub(Context.Int16x8Ty);
521
328
    break;
522
33
  case OpCode::I16x8__sub_sat_s:
523
33
    compileVectorVectorSubSat(Context.Int16x8Ty, true);
524
33
    break;
525
90
  case OpCode::I16x8__sub_sat_u:
526
90
    compileVectorVectorSubSat(Context.Int16x8Ty, false);
527
90
    break;
528
177
  case OpCode::I16x8__mul:
529
177
    compileVectorVectorMul(Context.Int16x8Ty);
530
177
    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
91
  case OpCode::I16x8__max_s:
538
91
    compileVectorVectorSMax(Context.Int16x8Ty);
539
91
    break;
540
599
  case OpCode::I16x8__max_u:
541
599
    compileVectorVectorUMax(Context.Int16x8Ty);
542
599
    break;
543
125
  case OpCode::I16x8__avgr_u:
544
125
    compileVectorVectorUAvgr(Context.Int16x8Ty);
545
125
    break;
546
81
  case OpCode::I16x8__extmul_low_i8x16_s:
547
81
    compileVectorExtMul(Context.Int8x16Ty, true, true);
548
81
    break;
549
200
  case OpCode::I16x8__extmul_high_i8x16_s:
550
200
    compileVectorExtMul(Context.Int8x16Ty, true, false);
551
200
    break;
552
154
  case OpCode::I16x8__extmul_low_i8x16_u:
553
154
    compileVectorExtMul(Context.Int8x16Ty, false, true);
554
154
    break;
555
483
  case OpCode::I16x8__extmul_high_i8x16_u:
556
483
    compileVectorExtMul(Context.Int8x16Ty, false, false);
557
483
    break;
558
141
  case OpCode::I16x8__q15mulr_sat_s:
559
141
    compileVectorVectorQ15MulSat();
560
141
    break;
561
391
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
562
391
    compileVectorExtAddPairwise(Context.Int8x16Ty, true);
563
391
    break;
564
353
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
565
353
    compileVectorExtAddPairwise(Context.Int8x16Ty, false);
566
353
    break;
567
56
  case OpCode::I32x4__abs:
568
56
    compileVectorAbs(Context.Int32x4Ty);
569
56
    break;
570
205
  case OpCode::I32x4__neg:
571
205
    compileVectorNeg(Context.Int32x4Ty);
572
205
    break;
573
184
  case OpCode::I32x4__all_true:
574
184
    compileVectorAllTrue(Context.Int32x4Ty);
575
184
    break;
576
86
  case OpCode::I32x4__bitmask:
577
86
    compileVectorBitMask(Context.Int32x4Ty);
578
86
    break;
579
106
  case OpCode::I32x4__extend_low_i16x8_s:
580
106
    compileVectorExtend(Context.Int16x8Ty, true, true);
581
106
    break;
582
536
  case OpCode::I32x4__extend_high_i16x8_s:
583
536
    compileVectorExtend(Context.Int16x8Ty, true, false);
584
536
    break;
585
1.96k
  case OpCode::I32x4__extend_low_i16x8_u:
586
1.96k
    compileVectorExtend(Context.Int16x8Ty, false, true);
587
1.96k
    break;
588
165
  case OpCode::I32x4__extend_high_i16x8_u:
589
165
    compileVectorExtend(Context.Int16x8Ty, false, false);
590
165
    break;
591
1.04k
  case OpCode::I32x4__shl:
592
1.04k
    compileVectorShl(Context.Int32x4Ty);
593
1.04k
    break;
594
215
  case OpCode::I32x4__shr_s:
595
215
    compileVectorAShr(Context.Int32x4Ty);
596
215
    break;
597
600
  case OpCode::I32x4__shr_u:
598
600
    compileVectorLShr(Context.Int32x4Ty);
599
600
    break;
600
202
  case OpCode::I32x4__add:
601
202
    compileVectorVectorAdd(Context.Int32x4Ty);
602
202
    break;
603
141
  case OpCode::I32x4__sub:
604
141
    compileVectorVectorSub(Context.Int32x4Ty);
605
141
    break;
606
217
  case OpCode::I32x4__mul:
607
217
    compileVectorVectorMul(Context.Int32x4Ty);
608
217
    break;
609
84
  case OpCode::I32x4__min_s:
610
84
    compileVectorVectorSMin(Context.Int32x4Ty);
611
84
    break;
612
59
  case OpCode::I32x4__min_u:
613
59
    compileVectorVectorUMin(Context.Int32x4Ty);
614
59
    break;
615
122
  case OpCode::I32x4__max_s:
616
122
    compileVectorVectorSMax(Context.Int32x4Ty);
617
122
    break;
618
75
  case OpCode::I32x4__max_u:
619
75
    compileVectorVectorUMax(Context.Int32x4Ty);
620
75
    break;
621
94
  case OpCode::I32x4__extmul_low_i16x8_s:
622
94
    compileVectorExtMul(Context.Int16x8Ty, true, true);
623
94
    break;
624
77
  case OpCode::I32x4__extmul_high_i16x8_s:
625
77
    compileVectorExtMul(Context.Int16x8Ty, true, false);
626
77
    break;
627
251
  case OpCode::I32x4__extmul_low_i16x8_u:
628
251
    compileVectorExtMul(Context.Int16x8Ty, false, true);
629
251
    break;
630
144
  case OpCode::I32x4__extmul_high_i16x8_u:
631
144
    compileVectorExtMul(Context.Int16x8Ty, false, false);
632
144
    break;
633
1.15k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
634
1.15k
    compileVectorExtAddPairwise(Context.Int16x8Ty, true);
635
1.15k
    break;
636
1.27k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
637
1.27k
    compileVectorExtAddPairwise(Context.Int16x8Ty, false);
638
1.27k
    break;
639
121
  case OpCode::I32x4__dot_i16x8_s: {
640
121
    auto ExtendTy = Context.Int16x8Ty.getExtendedElementVectorType();
641
121
    auto Undef = LLVM::Value::getUndef(ExtendTy);
642
121
    auto LHS = Builder.createSExt(
643
121
        Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy);
644
121
    auto RHS = Builder.createSExt(
645
121
        Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy);
646
121
    auto M = Builder.createMul(LHS, RHS);
647
121
    auto L = Builder.createShuffleVector(
648
121
        M, Undef, LLVM::Value::getConstVector32(LLContext, {0U, 2U, 4U, 6U}));
649
121
    auto R = Builder.createShuffleVector(
650
121
        M, Undef, LLVM::Value::getConstVector32(LLContext, {1U, 3U, 5U, 7U}));
651
121
    auto V = Builder.createAdd(L, R);
652
121
    stackPush(Builder.createBitCast(V, Context.Int64x2Ty));
653
121
    break;
654
0
  }
655
951
  case OpCode::I64x2__abs:
656
951
    compileVectorAbs(Context.Int64x2Ty);
657
951
    break;
658
536
  case OpCode::I64x2__neg:
659
536
    compileVectorNeg(Context.Int64x2Ty);
660
536
    break;
661
275
  case OpCode::I64x2__all_true:
662
275
    compileVectorAllTrue(Context.Int64x2Ty);
663
275
    break;
664
289
  case OpCode::I64x2__bitmask:
665
289
    compileVectorBitMask(Context.Int64x2Ty);
666
289
    break;
667
369
  case OpCode::I64x2__extend_low_i32x4_s:
668
369
    compileVectorExtend(Context.Int32x4Ty, true, true);
669
369
    break;
670
756
  case OpCode::I64x2__extend_high_i32x4_s:
671
756
    compileVectorExtend(Context.Int32x4Ty, true, false);
672
756
    break;
673
210
  case OpCode::I64x2__extend_low_i32x4_u:
674
210
    compileVectorExtend(Context.Int32x4Ty, false, true);
675
210
    break;
676
575
  case OpCode::I64x2__extend_high_i32x4_u:
677
575
    compileVectorExtend(Context.Int32x4Ty, false, false);
678
575
    break;
679
114
  case OpCode::I64x2__shl:
680
114
    compileVectorShl(Context.Int64x2Ty);
681
114
    break;
682
338
  case OpCode::I64x2__shr_s:
683
338
    compileVectorAShr(Context.Int64x2Ty);
684
338
    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
237
  case OpCode::I64x2__sub:
692
237
    compileVectorVectorSub(Context.Int64x2Ty);
693
237
    break;
694
81
  case OpCode::I64x2__mul:
695
81
    compileVectorVectorMul(Context.Int64x2Ty);
696
81
    break;
697
37
  case OpCode::I64x2__extmul_low_i32x4_s:
698
37
    compileVectorExtMul(Context.Int32x4Ty, true, true);
699
37
    break;
700
400
  case OpCode::I64x2__extmul_high_i32x4_s:
701
400
    compileVectorExtMul(Context.Int32x4Ty, true, false);
702
400
    break;
703
29
  case OpCode::I64x2__extmul_low_i32x4_u:
704
29
    compileVectorExtMul(Context.Int32x4Ty, false, true);
705
29
    break;
706
209
  case OpCode::I64x2__extmul_high_i32x4_u:
707
209
    compileVectorExtMul(Context.Int32x4Ty, false, false);
708
209
    break;
709
117
  case OpCode::F32x4__abs:
710
117
    compileVectorFAbs(Context.Floatx4Ty);
711
117
    break;
712
166
  case OpCode::F32x4__neg:
713
166
    compileVectorFNeg(Context.Floatx4Ty);
714
166
    break;
715
170
  case OpCode::F32x4__sqrt:
716
170
    compileVectorFSqrt(Context.Floatx4Ty);
717
170
    break;
718
128
  case OpCode::F32x4__add:
719
128
    compileVectorVectorFAdd(Context.Floatx4Ty);
720
128
    break;
721
256
  case OpCode::F32x4__sub:
722
256
    compileVectorVectorFSub(Context.Floatx4Ty);
723
256
    break;
724
38
  case OpCode::F32x4__mul:
725
38
    compileVectorVectorFMul(Context.Floatx4Ty);
726
38
    break;
727
160
  case OpCode::F32x4__div:
728
160
    compileVectorVectorFDiv(Context.Floatx4Ty);
729
160
    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
51
  case OpCode::F32x4__pmin:
737
51
    compileVectorVectorFPMin(Context.Floatx4Ty);
738
51
    break;
739
219
  case OpCode::F32x4__pmax:
740
219
    compileVectorVectorFPMax(Context.Floatx4Ty);
741
219
    break;
742
1.13k
  case OpCode::F32x4__ceil:
743
1.13k
    compileVectorFCeil(Context.Floatx4Ty);
744
1.13k
    break;
745
2.10k
  case OpCode::F32x4__floor:
746
2.10k
    compileVectorFFloor(Context.Floatx4Ty);
747
2.10k
    break;
748
1.93k
  case OpCode::F32x4__trunc:
749
1.93k
    compileVectorFTrunc(Context.Floatx4Ty);
750
1.93k
    break;
751
284
  case OpCode::F32x4__nearest:
752
284
    compileVectorFNearest(Context.Floatx4Ty);
753
284
    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
207
  case OpCode::F64x2__sub:
767
207
    compileVectorVectorFSub(Context.Doublex2Ty);
768
207
    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
166
  case OpCode::F64x2__min:
776
166
    compileVectorVectorFMin(Context.Doublex2Ty);
777
166
    break;
778
155
  case OpCode::F64x2__max:
779
155
    compileVectorVectorFMax(Context.Doublex2Ty);
780
155
    break;
781
277
  case OpCode::F64x2__pmin:
782
277
    compileVectorVectorFPMin(Context.Doublex2Ty);
783
277
    break;
784
103
  case OpCode::F64x2__pmax:
785
103
    compileVectorVectorFPMax(Context.Doublex2Ty);
786
103
    break;
787
673
  case OpCode::F64x2__ceil:
788
673
    compileVectorFCeil(Context.Doublex2Ty);
789
673
    break;
790
802
  case OpCode::F64x2__floor:
791
802
    compileVectorFFloor(Context.Doublex2Ty);
792
802
    break;
793
110
  case OpCode::F64x2__trunc:
794
110
    compileVectorFTrunc(Context.Doublex2Ty);
795
110
    break;
796
153
  case OpCode::F64x2__nearest:
797
153
    compileVectorFNearest(Context.Doublex2Ty);
798
153
    break;
799
159
  case OpCode::I32x4__trunc_sat_f32x4_s:
800
159
    compileVectorTruncSatS32(Context.Floatx4Ty, false);
801
159
    break;
802
3.82k
  case OpCode::I32x4__trunc_sat_f32x4_u:
803
3.82k
    compileVectorTruncSatU32(Context.Floatx4Ty, false);
804
3.82k
    break;
805
345
  case OpCode::F32x4__convert_i32x4_s:
806
345
    compileVectorConvertS(Context.Int32x4Ty, Context.Floatx4Ty, false);
807
345
    break;
808
734
  case OpCode::F32x4__convert_i32x4_u:
809
734
    compileVectorConvertU(Context.Int32x4Ty, Context.Floatx4Ty, false);
810
734
    break;
811
758
  case OpCode::I32x4__trunc_sat_f64x2_s_zero:
812
758
    compileVectorTruncSatS32(Context.Doublex2Ty, true);
813
758
    break;
814
2.20k
  case OpCode::I32x4__trunc_sat_f64x2_u_zero:
815
2.20k
    compileVectorTruncSatU32(Context.Doublex2Ty, true);
816
2.20k
    break;
817
340
  case OpCode::F64x2__convert_low_i32x4_s:
818
340
    compileVectorConvertS(Context.Int32x4Ty, Context.Doublex2Ty, true);
819
340
    break;
820
1.24k
  case OpCode::F64x2__convert_low_i32x4_u:
821
1.24k
    compileVectorConvertU(Context.Int32x4Ty, Context.Doublex2Ty, true);
822
1.24k
    break;
823
744
  case OpCode::F32x4__demote_f64x2_zero:
824
744
    compileVectorDemote();
825
744
    break;
826
813
  case OpCode::F64x2__promote_low_f32x4:
827
813
    compileVectorPromote();
828
813
    break;
829
830
  // Relaxed SIMD Instructions
831
16
  case OpCode::I8x16__relaxed_swizzle:
832
16
    compileVectorSwizzle();
833
16
    break;
834
13
  case OpCode::I32x4__relaxed_trunc_f32x4_s:
835
13
    compileVectorTruncSatS32(Context.Floatx4Ty, false);
836
13
    break;
837
12
  case OpCode::I32x4__relaxed_trunc_f32x4_u:
838
12
    compileVectorTruncSatU32(Context.Floatx4Ty, false);
839
12
    break;
840
10
  case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
841
10
    compileVectorTruncSatS32(Context.Doublex2Ty, true);
842
10
    break;
843
20
  case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
844
20
    compileVectorTruncSatU32(Context.Doublex2Ty, true);
845
20
    break;
846
13
  case OpCode::F32x4__relaxed_madd:
847
13
    compileVectorVectorMAdd(Context.Floatx4Ty);
848
13
    break;
849
63
  case OpCode::F32x4__relaxed_nmadd:
850
63
    compileVectorVectorNMAdd(Context.Floatx4Ty);
851
63
    break;
852
14
  case OpCode::F64x2__relaxed_madd:
853
14
    compileVectorVectorMAdd(Context.Doublex2Ty);
854
14
    break;
855
26
  case OpCode::F64x2__relaxed_nmadd:
856
26
    compileVectorVectorNMAdd(Context.Doublex2Ty);
857
26
    break;
858
12
  case OpCode::I8x16__relaxed_laneselect:
859
24
  case OpCode::I16x8__relaxed_laneselect:
860
34
  case OpCode::I32x4__relaxed_laneselect:
861
38
  case OpCode::I64x2__relaxed_laneselect: {
862
38
    auto C = stackPop();
863
38
    auto V2 = stackPop();
864
38
    auto V1 = stackPop();
865
38
    stackPush(
866
38
        Builder.createXor(Builder.createAnd(Builder.createXor(V1, V2), C), V2));
867
38
    break;
868
34
  }
869
19
  case OpCode::F32x4__relaxed_min:
870
19
    compileVectorVectorFMin(Context.Floatx4Ty);
871
19
    break;
872
10
  case OpCode::F32x4__relaxed_max:
873
10
    compileVectorVectorFMax(Context.Floatx4Ty);
874
10
    break;
875
12
  case OpCode::F64x2__relaxed_min:
876
12
    compileVectorVectorFMin(Context.Doublex2Ty);
877
12
    break;
878
11
  case OpCode::F64x2__relaxed_max:
879
11
    compileVectorVectorFMax(Context.Doublex2Ty);
880
11
    break;
881
19
  case OpCode::I16x8__relaxed_q15mulr_s:
882
19
    compileVectorVectorQ15MulSat();
883
19
    break;
884
15
  case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
885
15
    compileVectorRelaxedIntegerDotProduct();
886
15
    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
123k
  }
895
123k
  return {};
896
123k
}
897
898
void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy,
899
1.29k
                                            unsigned Index) noexcept {
900
1.29k
  auto Vector = Builder.createBitCast(Stack.back(), VectorTy);
901
  if constexpr (Endian::native == Endian::big) {
902
    Index = VectorTy.getVectorSize() - Index - 1;
903
  }
904
1.29k
  Stack.back() =
905
1.29k
      Builder.createExtractElement(Vector, LLContext.getInt64(Index));
906
1.29k
}
907
908
void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy, unsigned Index,
909
                                            LLVM::Type ExtendTy,
910
962
                                            bool Signed) noexcept {
911
962
  compileExtractLaneOp(VectorTy, Index);
912
962
  if (Signed) {
913
523
    Stack.back() = Builder.createSExt(Stack.back(), ExtendTy);
914
523
  } else {
915
439
    Stack.back() = Builder.createZExt(Stack.back(), ExtendTy);
916
439
  }
917
962
}
918
919
void FunctionCompiler::compileLoadLaneOp(unsigned MemoryIndex, uint64_t Offset,
920
                                         unsigned Alignment, unsigned Index,
921
                                         LLVM::Type LoadTy,
922
481
                                         LLVM::Type VectorTy) noexcept {
923
481
  auto Vector = stackPop();
924
481
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
925
  if constexpr (Endian::native == Endian::big) {
926
    Index = VectorTy.getVectorSize() - 1 - Index;
927
  }
928
481
  auto Value = Stack.back();
929
481
  Stack.back() = Builder.createBitCast(
930
481
      Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
931
481
                                  Value, LLContext.getInt64(Index)),
932
481
      Context.Int64x2Ty);
933
481
}
934
935
void FunctionCompiler::compileReplaceLaneOp(LLVM::Type VectorTy,
936
864
                                            unsigned Index) noexcept {
937
864
  auto Value = Builder.createTrunc(stackPop(), VectorTy.getElementType());
938
864
  auto Vector = Stack.back();
939
  if constexpr (Endian::native == Endian::big) {
940
    Index = VectorTy.getVectorSize() - Index - 1;
941
  }
942
864
  Stack.back() = Builder.createBitCast(
943
864
      Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
944
864
                                  Value, LLContext.getInt64(Index)),
945
864
      Context.Int64x2Ty);
946
864
}
947
948
void FunctionCompiler::compileSplatLoadOp(unsigned MemoryIndex, uint64_t Offset,
949
                                          unsigned Alignment, LLVM::Type LoadTy,
950
614
                                          LLVM::Type VectorTy) noexcept {
951
614
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
952
614
  compileSplatOp(VectorTy);
953
614
}
954
955
49.8k
void FunctionCompiler::compileSplatOp(LLVM::Type VectorTy) noexcept {
956
49.8k
  auto Undef = LLVM::Value::getUndef(VectorTy);
957
49.8k
  auto Zeros = LLVM::Value::getConstNull(
958
49.8k
      LLVM::Type::getVectorType(Context.Int32Ty, VectorTy.getVectorSize()));
959
49.8k
  auto Value = Builder.createTrunc(Stack.back(), VectorTy.getElementType());
960
49.8k
  auto Vector =
961
49.8k
      Builder.createInsertElement(Undef, Value, LLContext.getInt64(0));
962
49.8k
  Vector = Builder.createShuffleVector(Vector, Undef, Zeros);
963
964
49.8k
  Stack.back() = Builder.createBitCast(Vector, Context.Int64x2Ty);
965
49.8k
}
966
967
void FunctionCompiler::compileStoreLaneOp(uint32_t MemoryIndex, uint64_t Offset,
968
                                          uint32_t Alignment, uint8_t Index,
969
                                          LLVM::Type LoadTy,
970
375
                                          LLVM::Type VectorTy) noexcept {
971
375
  auto Vector = Stack.back();
972
  if constexpr (Endian::native == Endian::big) {
973
    Index = static_cast<uint8_t>(VectorTy.getVectorSize() - Index - 1);
974
  }
975
375
  Stack.back() = Builder.createExtractElement(
976
375
      Builder.createBitCast(Vector, VectorTy), LLContext.getInt64(Index));
977
375
  compileStoreOp(MemoryIndex, Offset, Alignment, LoadTy);
978
375
}
979
980
2.80k
void FunctionCompiler::compileVectorAbs(LLVM::Type VectorTy) noexcept {
981
2.80k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
982
2.80k
    return Builder.createIntrinsic(LLVM::Core::Abs, {V.getType()},
983
2.80k
                                   {V, LLContext.getFalse()});
984
2.80k
  });
985
2.80k
}
986
987
897
void FunctionCompiler::compileVectorAllTrue(LLVM::Type VectorTy) noexcept {
988
897
  compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept {
989
897
    const auto Size = VectorTy.getVectorSize();
990
897
    auto IntType = LLContext.getIntNTy(Size);
991
897
    auto Zero = LLVM::Value::getConstNull(VectorTy);
992
897
    auto Cmp = Builder.createBitCast(Builder.createICmpEQ(V, Zero), IntType);
993
897
    auto CmpZero = LLVM::Value::getConstInt(IntType, 0);
994
897
    return Builder.createICmpEQ(Cmp, CmpZero);
995
897
  });
996
897
}
997
998
162
void FunctionCompiler::compileVectorAnyTrue() noexcept {
999
162
  compileVectorReduceIOp(Context.Int128x1Ty, [this](auto V) noexcept {
1000
162
    auto Zero = LLVM::Value::getConstNull(Context.Int128x1Ty);
1001
162
    return Builder.createBitCast(Builder.createICmpNE(V, Zero),
1002
162
                                 LLContext.getInt1Ty());
1003
162
  });
1004
162
}
1005
1006
2.01k
void FunctionCompiler::compileVectorAShr(LLVM::Type VectorTy) noexcept {
1007
2.01k
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1008
2.01k
    return Builder.createAShr(LHS, RHS);
1009
2.01k
  });
1010
2.01k
}
1011
1012
1.13k
void FunctionCompiler::compileVectorBitMask(LLVM::Type VectorTy) noexcept {
1013
1.13k
  compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept {
1014
1.13k
    const auto Size = VectorTy.getVectorSize();
1015
1.13k
    auto IntType = LLContext.getIntNTy(Size);
1016
1.13k
    auto Zero = LLVM::Value::getConstNull(VectorTy);
1017
1.13k
    return Builder.createBitCast(Builder.createICmpSLT(V, Zero), IntType);
1018
1.13k
  });
1019
1.13k
}
1020
1021
void FunctionCompiler::compileVectorCompareOp(
1022
5.59k
    LLVM::Type VectorTy, LLVMIntPredicate Predicate) noexcept {
1023
5.59k
  auto RHS = stackPop();
1024
5.59k
  auto LHS = stackPop();
1025
5.59k
  auto Result = Builder.createSExt(
1026
5.59k
      Builder.createICmp(Predicate, Builder.createBitCast(LHS, VectorTy),
1027
5.59k
                         Builder.createBitCast(RHS, VectorTy)),
1028
5.59k
      VectorTy);
1029
5.59k
  stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
1030
5.59k
}
1031
1032
void FunctionCompiler::compileVectorCompareOp(LLVM::Type VectorTy,
1033
                                              LLVMRealPredicate Predicate,
1034
3.23k
                                              LLVM::Type ResultTy) noexcept {
1035
3.23k
  auto RHS = stackPop();
1036
3.23k
  auto LHS = stackPop();
1037
3.23k
  auto Result = Builder.createSExt(
1038
3.23k
      Builder.createFCmp(Predicate, Builder.createBitCast(LHS, VectorTy),
1039
3.23k
                         Builder.createBitCast(RHS, VectorTy)),
1040
3.23k
      ResultTy);
1041
3.23k
  stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
1042
3.23k
}
1043
1044
void FunctionCompiler::compileVectorConvertS(LLVM::Type VectorTy,
1045
                                             LLVM::Type FPVectorTy,
1046
685
                                             bool Low) noexcept {
1047
685
  compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
1048
685
    if (Low) {
1049
340
      const auto Size = VectorTy.getVectorSize() / 2;
1050
340
      std::vector<uint32_t> Mask(Size);
1051
340
      if constexpr (Endian::native == Endian::little) {
1052
340
        std::iota(Mask.begin(), Mask.end(), 0);
1053
      } else {
1054
        std::iota(Mask.begin(), Mask.end(), Size);
1055
      }
1056
340
      V = Builder.createShuffleVector(
1057
340
          V, LLVM::Value::getUndef(VectorTy),
1058
340
          LLVM::Value::getConstVector32(LLContext, Mask));
1059
340
    }
1060
685
    return Builder.createSIToFP(V, FPVectorTy);
1061
685
  });
1062
685
}
1063
1064
void FunctionCompiler::compileVectorConvertU(LLVM::Type VectorTy,
1065
                                             LLVM::Type FPVectorTy,
1066
1.97k
                                             bool Low) noexcept {
1067
1.97k
  compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
1068
1.97k
    if (Low) {
1069
1.24k
      const auto Size = VectorTy.getVectorSize() / 2;
1070
1.24k
      std::vector<uint32_t> Mask(Size);
1071
1.24k
      if constexpr (Endian::native == Endian::little) {
1072
1.24k
        std::iota(Mask.begin(), Mask.end(), 0);
1073
      } else {
1074
        std::iota(Mask.begin(), Mask.end(), Size);
1075
      }
1076
1.24k
      V = Builder.createShuffleVector(
1077
1.24k
          V, LLVM::Value::getUndef(VectorTy),
1078
1.24k
          LLVM::Value::getConstVector32(LLContext, Mask));
1079
1.24k
    }
1080
1.97k
    return Builder.createUIToFP(V, FPVectorTy);
1081
1.97k
  });
1082
1.97k
}
1083
1084
744
void FunctionCompiler::compileVectorDemote() noexcept {
1085
744
  compileVectorOp(Context.Doublex2Ty, [this](auto V) noexcept {
1086
744
    auto Demoted =
1087
744
        Builder.createFPTrunc(V, LLVM::Type::getVectorType(Context.FloatTy, 2));
1088
744
    auto ZeroV = LLVM::Value::getConstNull(Demoted.getType());
1089
744
    if constexpr (Endian::native == Endian::little) {
1090
744
      return Builder.createShuffleVector(
1091
744
          Demoted, ZeroV,
1092
744
          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
744
  });
1099
744
}
1100
1101
void FunctionCompiler::compileVectorExtAddPairwise(LLVM::Type VectorTy,
1102
3.16k
                                                   bool Signed) noexcept {
1103
3.16k
  compileVectorOp(
1104
3.16k
      VectorTy, [this, VectorTy, Signed](auto V) noexcept -> LLVM::Value {
1105
3.16k
        auto ExtTy =
1106
3.16k
            VectorTy.getExtendedElementVectorType().getHalfElementsVectorType();
1107
3.16k
#if defined(__x86_64__)
1108
3.16k
        const auto Count = VectorTy.getVectorSize();
1109
3.16k
        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
3.16k
        if (Context.SupportSSSE3 && Count == 16) {
1126
744
          assuming(LLVM::Core::X86SSSE3PMAddUbSw128 !=
1127
744
                   LLVM::Core::NotIntrinsic);
1128
744
          if (Signed) {
1129
391
            return Builder.createIntrinsic(
1130
391
                LLVM::Core::X86SSSE3PMAddUbSw128, {},
1131
391
                {Builder.createVectorSplat(16, LLContext.getInt8(1)), V});
1132
391
          } else {
1133
353
            return Builder.createIntrinsic(
1134
353
                LLVM::Core::X86SSSE3PMAddUbSw128, {},
1135
353
                {V, Builder.createVectorSplat(16, LLContext.getInt8(1))});
1136
353
          }
1137
744
        }
1138
2.42k
        if (Context.SupportSSE2 && Count == 8) {
1139
2.42k
          assuming(LLVM::Core::X86SSE2PMAddWd != LLVM::Core::NotIntrinsic);
1140
2.42k
          if (Signed) {
1141
1.15k
            return Builder.createIntrinsic(
1142
1.15k
                LLVM::Core::X86SSE2PMAddWd, {},
1143
1.15k
                {V, Builder.createVectorSplat(8, LLContext.getInt16(1))});
1144
1.27k
          } else {
1145
1.27k
            V = Builder.createXor(
1146
1.27k
                V, Builder.createVectorSplat(8, LLContext.getInt16(0x8000)));
1147
1.27k
            V = Builder.createIntrinsic(
1148
1.27k
                LLVM::Core::X86SSE2PMAddWd, {},
1149
1.27k
                {V, Builder.createVectorSplat(8, LLContext.getInt16(1))});
1150
1.27k
            return Builder.createAdd(
1151
1.27k
                V, Builder.createVectorSplat(4, LLContext.getInt32(0x10000)));
1152
1.27k
          }
1153
2.42k
        }
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.42k
      });
1184
3.16k
}
1185
1186
void FunctionCompiler::compileVectorExtend(LLVM::Type FromTy, bool Signed,
1187
6.13k
                                           bool Low) noexcept {
1188
6.13k
  auto ExtTy = FromTy.getExtendedElementVectorType();
1189
6.13k
  const auto Count = FromTy.getVectorSize();
1190
6.13k
  std::vector<uint32_t> Mask(Count / 2);
1191
  if constexpr (Endian::native == Endian::big) {
1192
    Low = !Low;
1193
  }
1194
6.13k
  std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
1195
6.13k
  auto R = Builder.createBitCast(Stack.back(), FromTy);
1196
6.13k
  if (Signed) {
1197
2.84k
    R = Builder.createSExt(R, ExtTy);
1198
3.28k
  } else {
1199
3.28k
    R = Builder.createZExt(R, ExtTy);
1200
3.28k
  }
1201
6.13k
  R = Builder.createShuffleVector(
1202
6.13k
      R, LLVM::Value::getUndef(ExtTy),
1203
6.13k
      LLVM::Value::getConstVector32(LLContext, Mask));
1204
6.13k
  Stack.back() = Builder.createBitCast(R, Context.Int64x2Ty);
1205
6.13k
}
1206
1207
void FunctionCompiler::compileVectorExtMul(LLVM::Type FromTy, bool Signed,
1208
2.15k
                                           bool Low) noexcept {
1209
2.15k
  auto ExtTy = FromTy.getExtendedElementVectorType();
1210
2.15k
  const auto Count = FromTy.getVectorSize();
1211
2.15k
  std::vector<uint32_t> Mask(Count / 2);
1212
2.15k
  std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
1213
4.31k
  auto Extend = [this, FromTy, Signed, ExtTy, &Mask](LLVM::Value R) noexcept {
1214
4.31k
    R = Builder.createBitCast(R, FromTy);
1215
4.31k
    if (Signed) {
1216
1.77k
      R = Builder.createSExt(R, ExtTy);
1217
2.54k
    } else {
1218
2.54k
      R = Builder.createZExt(R, ExtTy);
1219
2.54k
    }
1220
4.31k
    return Builder.createShuffleVector(
1221
4.31k
        R, LLVM::Value::getUndef(ExtTy),
1222
4.31k
        LLVM::Value::getConstVector32(LLContext, Mask));
1223
4.31k
  };
1224
2.15k
  auto RHS = Extend(stackPop());
1225
2.15k
  auto LHS = Extend(stackPop());
1226
2.15k
  stackPush(
1227
2.15k
      Builder.createBitCast(Builder.createMul(RHS, LHS), Context.Int64x2Ty));
1228
2.15k
}
1229
1230
556
void FunctionCompiler::compileVectorFAbs(LLVM::Type VectorTy) noexcept {
1231
556
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1232
556
    assuming(LLVM::Core::Fabs != LLVM::Core::NotIntrinsic);
1233
556
    return Builder.createUnaryIntrinsic(LLVM::Core::Fabs, V);
1234
556
  });
1235
556
}
1236
1237
1.81k
void FunctionCompiler::compileVectorFCeil(LLVM::Type VectorTy) noexcept {
1238
1.81k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1239
1.81k
    assuming(LLVM::Core::Ceil != LLVM::Core::NotIntrinsic);
1240
1.81k
    return Builder.createUnaryIntrinsic(LLVM::Core::Ceil, V);
1241
1.81k
  });
1242
1.81k
}
1243
1244
2.90k
void FunctionCompiler::compileVectorFFloor(LLVM::Type VectorTy) noexcept {
1245
2.90k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1246
2.90k
    assuming(LLVM::Core::Floor != LLVM::Core::NotIntrinsic);
1247
2.90k
    return Builder.createUnaryIntrinsic(LLVM::Core::Floor, V);
1248
2.90k
  });
1249
2.90k
}
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
792
void FunctionCompiler::compileVectorFNeg(LLVM::Type VectorTy) noexcept {
1287
792
  compileVectorOp(VectorTy,
1288
792
                  [this](auto V) noexcept { return Builder.createFNeg(V); });
1289
792
}
1290
1291
268
void FunctionCompiler::compileVectorFSqrt(LLVM::Type VectorTy) noexcept {
1292
268
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1293
268
    assuming(LLVM::Core::Sqrt != LLVM::Core::NotIntrinsic);
1294
268
    return Builder.createUnaryIntrinsic(LLVM::Core::Sqrt, V);
1295
268
  });
1296
268
}
1297
1298
2.04k
void FunctionCompiler::compileVectorFTrunc(LLVM::Type VectorTy) noexcept {
1299
2.04k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1300
2.04k
    assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
1301
2.04k
    return Builder.createUnaryIntrinsic(LLVM::Core::Trunc, V);
1302
2.04k
  });
1303
2.04k
}
1304
1305
void FunctionCompiler::compileVectorLoadOp(unsigned MemoryIndex,
1306
                                           uint64_t Offset, unsigned Alignment,
1307
4.94k
                                           LLVM::Type LoadTy) noexcept {
1308
4.94k
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
1309
4.94k
  Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
1310
4.94k
}
1311
1312
void FunctionCompiler::compileVectorLoadOp(unsigned MemoryIndex,
1313
                                           uint64_t Offset, unsigned Alignment,
1314
                                           LLVM::Type LoadTy,
1315
                                           LLVM::Type ExtendTy,
1316
1.66k
                                           bool Signed) noexcept {
1317
1.66k
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy, ExtendTy, Signed);
1318
1.66k
  Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
1319
1.66k
}
1320
1321
911
void FunctionCompiler::compileVectorLShr(LLVM::Type VectorTy) noexcept {
1322
911
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1323
911
    return Builder.createLShr(LHS, RHS);
1324
911
  });
1325
911
}
1326
1327
void FunctionCompiler::compileVectorNarrow(LLVM::Type FromTy,
1328
763
                                           bool Signed) noexcept {
1329
763
  auto [MinInt,
1330
763
        MaxInt] = [&]() noexcept -> std::tuple<LLVM::Value, LLVM::Value> {
1331
763
    switch (FromTy.getElementType().getIntegerBitWidth()) {
1332
293
    case 16: {
1333
293
      const auto Min =
1334
293
          static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::min()
1335
293
                                      : std::numeric_limits<uint8_t>::min());
1336
293
      const auto Max =
1337
293
          static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::max()
1338
293
                                      : std::numeric_limits<uint8_t>::max());
1339
293
      return {LLContext.getInt16(static_cast<uint16_t>(Min)),
1340
293
              LLContext.getInt16(static_cast<uint16_t>(Max))};
1341
0
    }
1342
470
    case 32: {
1343
470
      const auto Min =
1344
470
          static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::min()
1345
470
                                      : std::numeric_limits<uint16_t>::min());
1346
470
      const auto Max =
1347
470
          static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::max()
1348
470
                                      : std::numeric_limits<uint16_t>::max());
1349
470
      return {LLContext.getInt32(static_cast<uint32_t>(Min)),
1350
470
              LLContext.getInt32(static_cast<uint32_t>(Max))};
1351
0
    }
1352
0
    default:
1353
0
      assumingUnreachable();
1354
763
    }
1355
763
  }();
1356
763
  const auto Count = FromTy.getVectorSize();
1357
763
  auto VMin = Builder.createVectorSplat(Count, MinInt);
1358
763
  auto VMax = Builder.createVectorSplat(Count, MaxInt);
1359
1360
763
  auto TruncTy = FromTy.getTruncatedElementVectorType();
1361
1362
763
  auto F2 = Builder.createBitCast(stackPop(), FromTy);
1363
763
  F2 = Builder.createSelect(Builder.createICmpSLT(F2, VMin), VMin, F2);
1364
763
  F2 = Builder.createSelect(Builder.createICmpSGT(F2, VMax), VMax, F2);
1365
763
  F2 = Builder.createTrunc(F2, TruncTy);
1366
1367
763
  auto F1 = Builder.createBitCast(stackPop(), FromTy);
1368
763
  F1 = Builder.createSelect(Builder.createICmpSLT(F1, VMin), VMin, F1);
1369
763
  F1 = Builder.createSelect(Builder.createICmpSGT(F1, VMax), VMax, F1);
1370
763
  F1 = Builder.createTrunc(F1, TruncTy);
1371
1372
763
  std::vector<uint32_t> Mask(Count * 2);
1373
763
  std::iota(Mask.begin(), Mask.end(), 0);
1374
763
  auto V = Endian::native == Endian::little
1375
763
               ? Builder.createShuffleVector(
1376
763
                     F1, F2, LLVM::Value::getConstVector32(LLContext, Mask))
1377
763
               : Builder.createShuffleVector(
1378
0
                     F2, F1, LLVM::Value::getConstVector32(LLContext, Mask));
1379
763
  stackPush(Builder.createBitCast(V, Context.Int64x2Ty));
1380
763
}
1381
1382
3.58k
void FunctionCompiler::compileVectorNeg(LLVM::Type VectorTy) noexcept {
1383
3.58k
  compileVectorOp(VectorTy,
1384
3.58k
                  [this](auto V) noexcept { return Builder.createNeg(V); });
1385
3.58k
}
1386
1387
126
void FunctionCompiler::compileVectorPopcnt() noexcept {
1388
126
  compileVectorOp(Context.Int8x16Ty, [this](auto V) noexcept {
1389
126
    assuming(LLVM::Core::Ctpop != LLVM::Core::NotIntrinsic);
1390
126
    return Builder.createUnaryIntrinsic(LLVM::Core::Ctpop, V);
1391
126
  });
1392
126
}
1393
1394
813
void FunctionCompiler::compileVectorPromote() noexcept {
1395
813
  compileVectorOp(Context.Floatx4Ty, [this](auto V) noexcept {
1396
813
    auto UndefV = LLVM::Value::getUndef(V.getType());
1397
813
    auto Low = Builder.createShuffleVector(
1398
813
        V, UndefV, LLVM::Value::getConstVector32(LLContext, {0u, 1u}));
1399
813
    return Builder.createFPExt(Low,
1400
813
                               LLVM::Type::getVectorType(Context.DoubleTy, 2));
1401
813
  });
1402
813
}
1403
1404
15
void FunctionCompiler::compileVectorRelaxedIntegerDotProduct() noexcept {
1405
15
  auto OriTy = Context.Int8x16Ty;
1406
15
  auto ExtTy = Context.Int16x8Ty;
1407
15
  auto RHS = Builder.createBitCast(stackPop(), OriTy);
1408
15
  auto LHS = Builder.createBitCast(stackPop(), OriTy);
1409
15
#if defined(__x86_64__)
1410
15
  if (Context.SupportSSSE3) {
1411
15
    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
15
    return stackPush(Builder.createBitCast(
1416
15
        Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {},
1417
15
                                {RHS, LHS}),
1418
15
        Context.Int64x2Ty));
1419
15
  }
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
15
}
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.37k
void FunctionCompiler::compileVectorShl(LLVM::Type VectorTy) noexcept {
1484
1.37k
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1485
1.37k
    return Builder.createShl(LHS, RHS);
1486
1.37k
  });
1487
1.37k
}
1488
1489
167
void FunctionCompiler::compileVectorSwizzle() noexcept {
1490
167
  auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
1491
167
  auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
1492
1493
167
#if defined(__x86_64__)
1494
167
  if (Context.SupportSSSE3) {
1495
167
    auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112));
1496
167
    auto Added = Builder.createAdd(Index, Magic);
1497
167
    auto NewIndex = Builder.createSelect(
1498
167
        Builder.createICmpUGT(Index, Added),
1499
167
        LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added);
1500
167
    assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic);
1501
167
    stackPush(Builder.createBitCast(
1502
167
        Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {},
1503
167
                                {Vector, NewIndex}),
1504
167
        Context.Int64x2Ty));
1505
167
    return;
1506
167
  }
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
940
                                                bool PadZero) noexcept {
1561
940
  compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
1562
940
    const auto Size = VectorTy.getVectorSize();
1563
940
    auto FPTy = VectorTy.getElementType();
1564
940
    auto IntMin = LLContext.getInt32(
1565
940
        static_cast<uint32_t>(std::numeric_limits<int32_t>::min()));
1566
940
    auto IntMax = LLContext.getInt32(
1567
940
        static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
1568
940
    auto IntMinV = Builder.createVectorSplat(Size, IntMin);
1569
940
    auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
1570
940
    auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType());
1571
940
    auto FPMin = Builder.createSIToFP(IntMin, FPTy);
1572
940
    auto FPMax = Builder.createSIToFP(IntMax, FPTy);
1573
940
    auto FPMinV = Builder.createVectorSplat(Size, FPMin);
1574
940
    auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
1575
1576
940
    auto Normal = Builder.createFCmpORD(V, V);
1577
940
    auto NotUnder = Builder.createFCmpUGE(V, FPMinV);
1578
940
    auto NotOver = Builder.createFCmpULT(V, FPMaxV);
1579
940
    V = Builder.createFPToSI(
1580
940
        V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
1581
940
    V = Builder.createSelect(Normal, V, IntZeroV);
1582
940
    V = Builder.createSelect(NotUnder, V, IntMinV);
1583
940
    V = Builder.createSelect(NotOver, V, IntMaxV);
1584
940
    if (PadZero) {
1585
768
      std::vector<uint32_t> Mask(Size * 2);
1586
768
      std::iota(Mask.begin(), Mask.end(), 0);
1587
768
      if constexpr (Endian::native == Endian::little) {
1588
768
        V = Builder.createShuffleVector(
1589
768
            V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask));
1590
      } else {
1591
        V = Builder.createShuffleVector(
1592
            IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask));
1593
      }
1594
768
    }
1595
940
    return V;
1596
940
  });
1597
940
}
1598
1599
void FunctionCompiler::compileVectorTruncSatU32(LLVM::Type VectorTy,
1600
6.05k
                                                bool PadZero) noexcept {
1601
6.05k
  compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
1602
6.05k
    const auto Size = VectorTy.getVectorSize();
1603
6.05k
    auto FPTy = VectorTy.getElementType();
1604
6.05k
    auto IntMin = LLContext.getInt32(std::numeric_limits<uint32_t>::min());
1605
6.05k
    auto IntMax = LLContext.getInt32(std::numeric_limits<uint32_t>::max());
1606
6.05k
    auto IntMinV = Builder.createVectorSplat(Size, IntMin);
1607
6.05k
    auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
1608
6.05k
    auto FPMin = Builder.createUIToFP(IntMin, FPTy);
1609
6.05k
    auto FPMax = Builder.createUIToFP(IntMax, FPTy);
1610
6.05k
    auto FPMinV = Builder.createVectorSplat(Size, FPMin);
1611
6.05k
    auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
1612
1613
6.05k
    auto NotUnder = Builder.createFCmpOGE(V, FPMinV);
1614
6.05k
    auto NotOver = Builder.createFCmpULT(V, FPMaxV);
1615
6.05k
    V = Builder.createFPToUI(
1616
6.05k
        V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
1617
6.05k
    V = Builder.createSelect(NotUnder, V, IntMinV);
1618
6.05k
    V = Builder.createSelect(NotOver, V, IntMaxV);
1619
6.05k
    if (PadZero) {
1620
2.22k
      auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType());
1621
2.22k
      std::vector<uint32_t> Mask(Size * 2);
1622
2.22k
      std::iota(Mask.begin(), Mask.end(), 0);
1623
2.22k
      if constexpr (Endian::native == Endian::little) {
1624
2.22k
        V = Builder.createShuffleVector(
1625
2.22k
            V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask));
1626
      } else {
1627
        V = Builder.createShuffleVector(
1628
            IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask));
1629
      }
1630
2.22k
    }
1631
6.05k
    return V;
1632
6.05k
  });
1633
6.05k
}
1634
1635
440
void FunctionCompiler::compileVectorVectorAdd(LLVM::Type VectorTy) noexcept {
1636
440
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1637
440
    return Builder.createAdd(LHS, RHS);
1638
440
  });
1639
440
}
1640
1641
void FunctionCompiler::compileVectorVectorAddSat(LLVM::Type VectorTy,
1642
967
                                                 bool Signed) noexcept {
1643
967
  auto ID = Signed ? LLVM::Core::SAddSat : LLVM::Core::UAddSat;
1644
967
  assuming(ID != LLVM::Core::NotIntrinsic);
1645
967
  compileVectorVectorOp(
1646
967
      VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
1647
967
        return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
1648
967
      });
1649
967
}
1650
1651
177
void FunctionCompiler::compileVectorVectorFAdd(LLVM::Type VectorTy) noexcept {
1652
177
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1653
177
    return Builder.createFAdd(LHS, RHS);
1654
177
  });
1655
177
}
1656
1657
197
void FunctionCompiler::compileVectorVectorFDiv(LLVM::Type VectorTy) noexcept {
1658
197
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1659
197
    return Builder.createFDiv(LHS, RHS);
1660
197
  });
1661
197
}
1662
1663
214
void FunctionCompiler::compileVectorVectorFMax(LLVM::Type VectorTy) noexcept {
1664
214
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1665
214
    auto LNaN = Builder.createFCmpUNO(LHS, LHS);
1666
214
    auto RNaN = Builder.createFCmpUNO(RHS, RHS);
1667
214
    auto OLT = Builder.createFCmpOLT(LHS, RHS);
1668
214
    auto OGT = Builder.createFCmpOGT(LHS, RHS);
1669
214
    auto Ret = Builder.createBitCast(
1670
214
        Builder.createAnd(Builder.createBitCast(LHS, Context.Int64x2Ty),
1671
214
                          Builder.createBitCast(RHS, Context.Int64x2Ty)),
1672
214
        LHS.getType());
1673
214
    Ret = Builder.createSelect(OLT, RHS, Ret);
1674
214
    Ret = Builder.createSelect(OGT, LHS, Ret);
1675
214
    Ret = Builder.createSelect(LNaN, LHS, Ret);
1676
214
    Ret = Builder.createSelect(RNaN, RHS, Ret);
1677
214
    return Ret;
1678
214
  });
1679
214
}
1680
1681
340
void FunctionCompiler::compileVectorVectorFMin(LLVM::Type VectorTy) noexcept {
1682
340
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1683
340
    auto LNaN = Builder.createFCmpUNO(LHS, LHS);
1684
340
    auto RNaN = Builder.createFCmpUNO(RHS, RHS);
1685
340
    auto OLT = Builder.createFCmpOLT(LHS, RHS);
1686
340
    auto OGT = Builder.createFCmpOGT(LHS, RHS);
1687
340
    auto Ret = Builder.createBitCast(
1688
340
        Builder.createOr(Builder.createBitCast(LHS, Context.Int64x2Ty),
1689
340
                         Builder.createBitCast(RHS, Context.Int64x2Ty)),
1690
340
        LHS.getType());
1691
340
    Ret = Builder.createSelect(OGT, RHS, Ret);
1692
340
    Ret = Builder.createSelect(OLT, LHS, Ret);
1693
340
    Ret = Builder.createSelect(LNaN, LHS, Ret);
1694
340
    Ret = Builder.createSelect(RNaN, RHS, Ret);
1695
340
    return Ret;
1696
340
  });
1697
340
}
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
322
void FunctionCompiler::compileVectorVectorFPMax(LLVM::Type VectorTy) noexcept {
1706
322
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1707
322
    auto Cmp = Builder.createFCmpOGT(RHS, LHS);
1708
322
    return Builder.createSelect(Cmp, RHS, LHS);
1709
322
  });
1710
322
}
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
463
void FunctionCompiler::compileVectorVectorFSub(LLVM::Type VectorTy) noexcept {
1720
463
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1721
463
    return Builder.createFSub(LHS, RHS);
1722
463
  });
1723
463
}
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
475
void FunctionCompiler::compileVectorVectorMul(LLVM::Type VectorTy) noexcept {
1734
475
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1735
475
    return Builder.createMul(LHS, RHS);
1736
475
  });
1737
475
}
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
527
void FunctionCompiler::compileVectorVectorSMax(LLVM::Type VectorTy) noexcept {
1797
527
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1798
527
    return Builder.createIntrinsic(LLVM::Core::SMax, {LHS.getType()},
1799
527
                                   {LHS, RHS});
1800
527
  });
1801
527
}
1802
1803
318
void FunctionCompiler::compileVectorVectorSMin(LLVM::Type VectorTy) noexcept {
1804
318
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1805
318
    return Builder.createIntrinsic(LLVM::Core::SMin, {LHS.getType()},
1806
318
                                   {LHS, RHS});
1807
318
  });
1808
318
}
1809
1810
772
void FunctionCompiler::compileVectorVectorSub(LLVM::Type VectorTy) noexcept {
1811
772
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1812
772
    return Builder.createSub(LHS, RHS);
1813
772
  });
1814
772
}
1815
1816
void FunctionCompiler::compileVectorVectorSubSat(LLVM::Type VectorTy,
1817
402
                                                 bool Signed) noexcept {
1818
402
  auto ID = Signed ? LLVM::Core::SSubSat : LLVM::Core::USubSat;
1819
402
  assuming(ID != LLVM::Core::NotIntrinsic);
1820
402
  compileVectorVectorOp(
1821
402
      VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
1822
402
        return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
1823
402
      });
1824
402
}
1825
1826
270
void FunctionCompiler::compileVectorVectorUAvgr(LLVM::Type VectorTy) noexcept {
1827
270
  auto ExtendTy = VectorTy.getExtendedElementVectorType();
1828
270
  compileVectorVectorOp(
1829
270
      VectorTy,
1830
270
      [this, VectorTy, ExtendTy](auto LHS, auto RHS) noexcept -> LLVM::Value {
1831
270
#if defined(__x86_64__)
1832
270
        if (Context.SupportSSE2) {
1833
270
          const auto ID = [VectorTy]() noexcept {
1834
270
            switch (VectorTy.getElementType().getIntegerBitWidth()) {
1835
145
            case 8:
1836
145
              return LLVM::Core::X86SSE2PAvgB;
1837
125
            case 16:
1838
125
              return LLVM::Core::X86SSE2PAvgW;
1839
0
            default:
1840
0
              assumingUnreachable();
1841
270
            }
1842
270
          }();
1843
270
          assuming(ID != LLVM::Core::NotIntrinsic);
1844
270
          return Builder.createIntrinsic(ID, {}, {LHS, RHS});
1845
270
        }
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
270
      });
1871
270
}
1872
1873
764
void FunctionCompiler::compileVectorVectorUMax(LLVM::Type VectorTy) noexcept {
1874
764
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1875
764
    return Builder.createIntrinsic(LLVM::Core::UMax, {LHS.getType()},
1876
764
                                   {LHS, RHS});
1877
764
  });
1878
764
}
1879
1880
266
void FunctionCompiler::compileVectorVectorUMin(LLVM::Type VectorTy) noexcept {
1881
266
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1882
266
    return Builder.createIntrinsic(LLVM::Core::UMin, {LHS.getType()},
1883
266
                                   {LHS, RHS});
1884
266
  });
1885
266
}
1886
1887
} // namespace WasmEdge