Coverage Report

Created: 2026-07-16 07:09

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
117k
FunctionCompiler::compileVectorOp(const AST::Instruction &Instr) noexcept {
14
117k
  switch (Instr.getOpCode()) {
15
4.87k
  case OpCode::V128__load:
16
4.87k
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
17
4.87k
                        Instr.getMemoryAlign(), Context.Int128x1Ty);
18
4.87k
    break;
19
221
  case OpCode::V128__load8x8_s:
20
221
    compileVectorLoadOp(
21
221
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
22
221
        LLVM::Type::getVectorType(Context.Int8Ty, 8), Context.Int16x8Ty, true);
23
221
    break;
24
46
  case OpCode::V128__load8x8_u:
25
46
    compileVectorLoadOp(
26
46
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
27
46
        LLVM::Type::getVectorType(Context.Int8Ty, 8), Context.Int16x8Ty, false);
28
46
    break;
29
310
  case OpCode::V128__load16x4_s:
30
310
    compileVectorLoadOp(
31
310
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
32
310
        LLVM::Type::getVectorType(Context.Int16Ty, 4), Context.Int32x4Ty, true);
33
310
    break;
34
501
  case OpCode::V128__load16x4_u:
35
501
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
36
501
                        Instr.getMemoryAlign(),
37
501
                        LLVM::Type::getVectorType(Context.Int16Ty, 4),
38
501
                        Context.Int32x4Ty, false);
39
501
    break;
40
136
  case OpCode::V128__load32x2_s:
41
136
    compileVectorLoadOp(
42
136
        Instr.getTargetIndex(), Instr.getMemoryOffset(), Instr.getMemoryAlign(),
43
136
        LLVM::Type::getVectorType(Context.Int32Ty, 2), Context.Int64x2Ty, true);
44
136
    break;
45
182
  case OpCode::V128__load32x2_u:
46
182
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
47
182
                        Instr.getMemoryAlign(),
48
182
                        LLVM::Type::getVectorType(Context.Int32Ty, 2),
49
182
                        Context.Int64x2Ty, false);
50
182
    break;
51
75
  case OpCode::V128__load8_splat:
52
75
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
53
75
                       Instr.getMemoryAlign(), Context.Int8Ty,
54
75
                       Context.Int8x16Ty);
55
75
    break;
56
136
  case OpCode::V128__load16_splat:
57
136
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
58
136
                       Instr.getMemoryAlign(), Context.Int16Ty,
59
136
                       Context.Int16x8Ty);
60
136
    break;
61
182
  case OpCode::V128__load32_splat:
62
182
    compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
63
182
                       Instr.getMemoryAlign(), Context.Int32Ty,
64
182
                       Context.Int32x4Ty);
65
182
    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
80
  case OpCode::V128__load32_zero:
72
80
    compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
73
80
                        Instr.getMemoryAlign(), Context.Int32Ty,
74
80
                        Context.Int128Ty, false);
75
80
    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
216
  case OpCode::V128__load8_lane:
86
216
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
87
216
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
88
216
                      Context.Int8Ty, Context.Int8x16Ty);
89
216
    break;
90
148
  case OpCode::V128__load16_lane:
91
148
    compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
92
148
                      Instr.getMemoryAlign(), Instr.getMemoryLane(),
93
148
                      Context.Int16Ty, Context.Int16x8Ty);
94
148
    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
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
106
  case OpCode::V128__store32_lane:
116
106
    compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
117
106
                       Instr.getMemoryAlign(), Instr.getMemoryLane(),
118
106
                       Context.Int32Ty, Context.Int32x4Ty);
119
106
    break;
120
35
  case OpCode::V128__store64_lane:
121
35
    compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
122
35
                       Instr.getMemoryAlign(), Instr.getMemoryLane(),
123
35
                       Context.Int64Ty, Context.Int64x2Ty);
124
35
    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
13
  case OpCode::I8x16__shuffle: {
137
13
    auto V2 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
138
13
    auto V1 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
139
13
    const auto V3 = Instr.getNum().get<uint128_t>();
140
13
    std::array<uint8_t, 16> Mask;
141
221
    for (size_t I = 0; I < 16; ++I) {
142
208
      auto Num = static_cast<uint8_t>(V3 >> (I * 8));
143
208
      if constexpr (Endian::native == Endian::little) {
144
208
        Mask[I] = Num;
145
      } else {
146
        Mask[15 - I] = Num < 16 ? 15 - Num : 47 - Num;
147
      }
148
208
    }
149
13
    stackPush(Builder.createBitCast(
150
13
        Builder.createShuffleVector(
151
13
            V1, V2, LLVM::Value::getConstVector8(LLContext, Mask)),
152
13
        Context.Int64x2Ty));
153
13
    break;
154
0
  }
155
156
  // SIMD Lane Instructions
157
61
  case OpCode::I8x16__extract_lane_s:
158
61
    compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
159
61
                         Context.Int32Ty, true);
160
61
    break;
161
28
  case OpCode::I8x16__extract_lane_u:
162
28
    compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
163
28
                         Context.Int32Ty, false);
164
28
    break;
165
203
  case OpCode::I8x16__replace_lane:
166
203
    compileReplaceLaneOp(Context.Int8x16Ty, Instr.getMemoryLane());
167
203
    break;
168
447
  case OpCode::I16x8__extract_lane_s:
169
447
    compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
170
447
                         Context.Int32Ty, true);
171
447
    break;
172
392
  case OpCode::I16x8__extract_lane_u:
173
392
    compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
174
392
                         Context.Int32Ty, false);
175
392
    break;
176
367
  case OpCode::I16x8__replace_lane:
177
367
    compileReplaceLaneOp(Context.Int16x8Ty, Instr.getMemoryLane());
178
367
    break;
179
62
  case OpCode::I32x4__extract_lane:
180
62
    compileExtractLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
181
62
    break;
182
197
  case OpCode::I32x4__replace_lane:
183
197
    compileReplaceLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
184
197
    break;
185
126
  case OpCode::I64x2__extract_lane:
186
126
    compileExtractLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
187
126
    break;
188
11
  case OpCode::I64x2__replace_lane:
189
11
    compileReplaceLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
190
11
    break;
191
56
  case OpCode::F32x4__extract_lane:
192
56
    compileExtractLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
193
56
    break;
194
20
  case OpCode::F32x4__replace_lane:
195
20
    compileReplaceLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
196
20
    break;
197
68
  case OpCode::F64x2__extract_lane:
198
68
    compileExtractLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
199
68
    break;
200
7
  case OpCode::F64x2__replace_lane:
201
7
    compileReplaceLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
202
7
    break;
203
204
  // SIMD Numeric Instructions
205
89
  case OpCode::I8x16__swizzle:
206
89
    compileVectorSwizzle();
207
89
    break;
208
36.2k
  case OpCode::I8x16__splat:
209
36.2k
    compileSplatOp(Context.Int8x16Ty);
210
36.2k
    break;
211
8.37k
  case OpCode::I16x8__splat:
212
8.37k
    compileSplatOp(Context.Int16x8Ty);
213
8.37k
    break;
214
1.24k
  case OpCode::I32x4__splat:
215
1.24k
    compileSplatOp(Context.Int32x4Ty);
216
1.24k
    break;
217
526
  case OpCode::I64x2__splat:
218
526
    compileSplatOp(Context.Int64x2Ty);
219
526
    break;
220
339
  case OpCode::F32x4__splat:
221
339
    compileSplatOp(Context.Floatx4Ty);
222
339
    break;
223
60
  case OpCode::F64x2__splat:
224
60
    compileSplatOp(Context.Doublex2Ty);
225
60
    break;
226
99
  case OpCode::I8x16__eq:
227
99
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntEQ);
228
99
    break;
229
410
  case OpCode::I8x16__ne:
230
410
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntNE);
231
410
    break;
232
63
  case OpCode::I8x16__lt_s:
233
63
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLT);
234
63
    break;
235
65
  case OpCode::I8x16__lt_u:
236
65
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULT);
237
65
    break;
238
221
  case OpCode::I8x16__gt_s:
239
221
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGT);
240
221
    break;
241
212
  case OpCode::I8x16__gt_u:
242
212
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGT);
243
212
    break;
244
110
  case OpCode::I8x16__le_s:
245
110
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLE);
246
110
    break;
247
133
  case OpCode::I8x16__le_u:
248
133
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULE);
249
133
    break;
250
530
  case OpCode::I8x16__ge_s:
251
530
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGE);
252
530
    break;
253
92
  case OpCode::I8x16__ge_u:
254
92
    compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGE);
255
92
    break;
256
167
  case OpCode::I16x8__eq:
257
167
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntEQ);
258
167
    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
226
  case OpCode::I16x8__lt_u:
266
226
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULT);
267
226
    break;
268
229
  case OpCode::I16x8__gt_s:
269
229
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGT);
270
229
    break;
271
129
  case OpCode::I16x8__gt_u:
272
129
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGT);
273
129
    break;
274
74
  case OpCode::I16x8__le_s:
275
74
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLE);
276
74
    break;
277
81
  case OpCode::I16x8__le_u:
278
81
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULE);
279
81
    break;
280
136
  case OpCode::I16x8__ge_s:
281
136
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGE);
282
136
    break;
283
67
  case OpCode::I16x8__ge_u:
284
67
    compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGE);
285
67
    break;
286
60
  case OpCode::I32x4__eq:
287
60
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntEQ);
288
60
    break;
289
91
  case OpCode::I32x4__ne:
290
91
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntNE);
291
91
    break;
292
48
  case OpCode::I32x4__lt_s:
293
48
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLT);
294
48
    break;
295
128
  case OpCode::I32x4__lt_u:
296
128
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULT);
297
128
    break;
298
201
  case OpCode::I32x4__gt_s:
299
201
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGT);
300
201
    break;
301
221
  case OpCode::I32x4__gt_u:
302
221
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGT);
303
221
    break;
304
258
  case OpCode::I32x4__le_s:
305
258
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLE);
306
258
    break;
307
239
  case OpCode::I32x4__le_u:
308
239
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULE);
309
239
    break;
310
65
  case OpCode::I32x4__ge_s:
311
65
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGE);
312
65
    break;
313
158
  case OpCode::I32x4__ge_u:
314
158
    compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGE);
315
158
    break;
316
122
  case OpCode::I64x2__eq:
317
122
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntEQ);
318
122
    break;
319
48
  case OpCode::I64x2__ne:
320
48
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntNE);
321
48
    break;
322
46
  case OpCode::I64x2__lt_s:
323
46
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLT);
324
46
    break;
325
162
  case OpCode::I64x2__gt_s:
326
162
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGT);
327
162
    break;
328
49
  case OpCode::I64x2__le_s:
329
49
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLE);
330
49
    break;
331
73
  case OpCode::I64x2__ge_s:
332
73
    compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGE);
333
73
    break;
334
1.34k
  case OpCode::F32x4__eq:
335
1.34k
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOEQ, Context.Int32x4Ty);
336
1.34k
    break;
337
53
  case OpCode::F32x4__ne:
338
53
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealUNE, Context.Int32x4Ty);
339
53
    break;
340
710
  case OpCode::F32x4__lt:
341
710
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLT, Context.Int32x4Ty);
342
710
    break;
343
82
  case OpCode::F32x4__gt:
344
82
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOGT, Context.Int32x4Ty);
345
82
    break;
346
362
  case OpCode::F32x4__le:
347
362
    compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLE, Context.Int32x4Ty);
348
362
    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
134
  case OpCode::F64x2__lt:
359
134
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLT, Context.Int64x2Ty);
360
134
    break;
361
57
  case OpCode::F64x2__gt:
362
57
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGT, Context.Int64x2Ty);
363
57
    break;
364
148
  case OpCode::F64x2__le:
365
148
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLE, Context.Int64x2Ty);
366
148
    break;
367
82
  case OpCode::F64x2__ge:
368
82
    compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGE, Context.Int64x2Ty);
369
82
    break;
370
360
  case OpCode::V128__not:
371
360
    Stack.back() = Builder.createNot(Stack.back());
372
360
    break;
373
107
  case OpCode::V128__and: {
374
107
    auto RHS = stackPop();
375
107
    auto LHS = stackPop();
376
107
    stackPush(Builder.createAnd(LHS, RHS));
377
107
    break;
378
0
  }
379
85
  case OpCode::V128__andnot: {
380
85
    auto RHS = stackPop();
381
85
    auto LHS = stackPop();
382
85
    stackPush(Builder.createAnd(LHS, Builder.createNot(RHS)));
383
85
    break;
384
0
  }
385
122
  case OpCode::V128__or: {
386
122
    auto RHS = stackPop();
387
122
    auto LHS = stackPop();
388
122
    stackPush(Builder.createOr(LHS, RHS));
389
122
    break;
390
0
  }
391
59
  case OpCode::V128__xor: {
392
59
    auto RHS = stackPop();
393
59
    auto LHS = stackPop();
394
59
    stackPush(Builder.createXor(LHS, RHS));
395
59
    break;
396
0
  }
397
130
  case OpCode::V128__bitselect: {
398
130
    auto C = stackPop();
399
130
    auto V2 = stackPop();
400
130
    auto V1 = stackPop();
401
130
    stackPush(
402
130
        Builder.createXor(Builder.createAnd(Builder.createXor(V1, V2), C), V2));
403
130
    break;
404
0
  }
405
131
  case OpCode::V128__any_true:
406
131
    compileVectorAnyTrue();
407
131
    break;
408
1.31k
  case OpCode::I8x16__abs:
409
1.31k
    compileVectorAbs(Context.Int8x16Ty);
410
1.31k
    break;
411
2.28k
  case OpCode::I8x16__neg:
412
2.28k
    compileVectorNeg(Context.Int8x16Ty);
413
2.28k
    break;
414
140
  case OpCode::I8x16__popcnt:
415
140
    compileVectorPopcnt();
416
140
    break;
417
294
  case OpCode::I8x16__all_true:
418
294
    compileVectorAllTrue(Context.Int8x16Ty);
419
294
    break;
420
685
  case OpCode::I8x16__bitmask:
421
685
    compileVectorBitMask(Context.Int8x16Ty);
422
685
    break;
423
92
  case OpCode::I8x16__narrow_i16x8_s:
424
92
    compileVectorNarrow(Context.Int16x8Ty, true);
425
92
    break;
426
188
  case OpCode::I8x16__narrow_i16x8_u:
427
188
    compileVectorNarrow(Context.Int16x8Ty, false);
428
188
    break;
429
111
  case OpCode::I8x16__shl:
430
111
    compileVectorShl(Context.Int8x16Ty);
431
111
    break;
432
1.09k
  case OpCode::I8x16__shr_s:
433
1.09k
    compileVectorAShr(Context.Int8x16Ty);
434
1.09k
    break;
435
86
  case OpCode::I8x16__shr_u:
436
86
    compileVectorLShr(Context.Int8x16Ty);
437
86
    break;
438
41
  case OpCode::I8x16__add:
439
41
    compileVectorVectorAdd(Context.Int8x16Ty);
440
41
    break;
441
527
  case OpCode::I8x16__add_sat_s:
442
527
    compileVectorVectorAddSat(Context.Int8x16Ty, true);
443
527
    break;
444
64
  case OpCode::I8x16__add_sat_u:
445
64
    compileVectorVectorAddSat(Context.Int8x16Ty, false);
446
64
    break;
447
66
  case OpCode::I8x16__sub:
448
66
    compileVectorVectorSub(Context.Int8x16Ty);
449
66
    break;
450
191
  case OpCode::I8x16__sub_sat_s:
451
191
    compileVectorVectorSubSat(Context.Int8x16Ty, true);
452
191
    break;
453
82
  case OpCode::I8x16__sub_sat_u:
454
82
    compileVectorVectorSubSat(Context.Int8x16Ty, false);
455
82
    break;
456
84
  case OpCode::I8x16__min_s:
457
84
    compileVectorVectorSMin(Context.Int8x16Ty);
458
84
    break;
459
105
  case OpCode::I8x16__min_u:
460
105
    compileVectorVectorUMin(Context.Int8x16Ty);
461
105
    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
151
  case OpCode::I8x16__avgr_u:
469
151
    compileVectorVectorUAvgr(Context.Int8x16Ty);
470
151
    break;
471
206
  case OpCode::I16x8__abs:
472
206
    compileVectorAbs(Context.Int16x8Ty);
473
206
    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
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
361
  case OpCode::I16x8__narrow_i32x4_u:
487
361
    compileVectorNarrow(Context.Int32x4Ty, false);
488
361
    break;
489
976
  case OpCode::I16x8__extend_low_i8x16_s:
490
976
    compileVectorExtend(Context.Int8x16Ty, true, true);
491
976
    break;
492
107
  case OpCode::I16x8__extend_high_i8x16_s:
493
107
    compileVectorExtend(Context.Int8x16Ty, true, false);
494
107
    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
332
  case OpCode::I16x8__shr_s:
505
332
    compileVectorAShr(Context.Int16x8Ty);
506
332
    break;
507
124
  case OpCode::I16x8__shr_u:
508
124
    compileVectorLShr(Context.Int16x8Ty);
509
124
    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
279
  case OpCode::I16x8__sub:
520
279
    compileVectorVectorSub(Context.Int16x8Ty);
521
279
    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
104
  case OpCode::I16x8__mul:
529
104
    compileVectorVectorMul(Context.Int16x8Ty);
530
104
    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
82
  case OpCode::I16x8__max_s:
538
82
    compileVectorVectorSMax(Context.Int16x8Ty);
539
82
    break;
540
527
  case OpCode::I16x8__max_u:
541
527
    compileVectorVectorUMax(Context.Int16x8Ty);
542
527
    break;
543
110
  case OpCode::I16x8__avgr_u:
544
110
    compileVectorVectorUAvgr(Context.Int16x8Ty);
545
110
    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
108
  case OpCode::I16x8__extmul_low_i8x16_u:
553
108
    compileVectorExtMul(Context.Int8x16Ty, false, true);
554
108
    break;
555
389
  case OpCode::I16x8__extmul_high_i8x16_u:
556
389
    compileVectorExtMul(Context.Int8x16Ty, false, false);
557
389
    break;
558
142
  case OpCode::I16x8__q15mulr_sat_s:
559
142
    compileVectorVectorQ15MulSat();
560
142
    break;
561
369
  case OpCode::I16x8__extadd_pairwise_i8x16_s:
562
369
    compileVectorExtAddPairwise(Context.Int8x16Ty, true);
563
369
    break;
564
340
  case OpCode::I16x8__extadd_pairwise_i8x16_u:
565
340
    compileVectorExtAddPairwise(Context.Int8x16Ty, false);
566
340
    break;
567
56
  case OpCode::I32x4__abs:
568
56
    compileVectorAbs(Context.Int32x4Ty);
569
56
    break;
570
192
  case OpCode::I32x4__neg:
571
192
    compileVectorNeg(Context.Int32x4Ty);
572
192
    break;
573
182
  case OpCode::I32x4__all_true:
574
182
    compileVectorAllTrue(Context.Int32x4Ty);
575
182
    break;
576
84
  case OpCode::I32x4__bitmask:
577
84
    compileVectorBitMask(Context.Int32x4Ty);
578
84
    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.08k
  case OpCode::I32x4__shl:
592
1.08k
    compileVectorShl(Context.Int32x4Ty);
593
1.08k
    break;
594
244
  case OpCode::I32x4__shr_s:
595
244
    compileVectorAShr(Context.Int32x4Ty);
596
244
    break;
597
439
  case OpCode::I32x4__shr_u:
598
439
    compileVectorLShr(Context.Int32x4Ty);
599
439
    break;
600
173
  case OpCode::I32x4__add:
601
173
    compileVectorVectorAdd(Context.Int32x4Ty);
602
173
    break;
603
111
  case OpCode::I32x4__sub:
604
111
    compileVectorVectorSub(Context.Int32x4Ty);
605
111
    break;
606
178
  case OpCode::I32x4__mul:
607
178
    compileVectorVectorMul(Context.Int32x4Ty);
608
178
    break;
609
81
  case OpCode::I32x4__min_s:
610
81
    compileVectorVectorSMin(Context.Int32x4Ty);
611
81
    break;
612
57
  case OpCode::I32x4__min_u:
613
57
    compileVectorVectorUMin(Context.Int32x4Ty);
614
57
    break;
615
89
  case OpCode::I32x4__max_s:
616
89
    compileVectorVectorSMax(Context.Int32x4Ty);
617
89
    break;
618
75
  case OpCode::I32x4__max_u:
619
75
    compileVectorVectorUMax(Context.Int32x4Ty);
620
75
    break;
621
96
  case OpCode::I32x4__extmul_low_i16x8_s:
622
96
    compileVectorExtMul(Context.Int16x8Ty, true, true);
623
96
    break;
624
69
  case OpCode::I32x4__extmul_high_i16x8_s:
625
69
    compileVectorExtMul(Context.Int16x8Ty, true, false);
626
69
    break;
627
241
  case OpCode::I32x4__extmul_low_i16x8_u:
628
241
    compileVectorExtMul(Context.Int16x8Ty, false, true);
629
241
    break;
630
115
  case OpCode::I32x4__extmul_high_i16x8_u:
631
115
    compileVectorExtMul(Context.Int16x8Ty, false, false);
632
115
    break;
633
1.14k
  case OpCode::I32x4__extadd_pairwise_i16x8_s:
634
1.14k
    compileVectorExtAddPairwise(Context.Int16x8Ty, true);
635
1.14k
    break;
636
1.00k
  case OpCode::I32x4__extadd_pairwise_i16x8_u:
637
1.00k
    compileVectorExtAddPairwise(Context.Int16x8Ty, false);
638
1.00k
    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
914
  case OpCode::I64x2__abs:
656
914
    compileVectorAbs(Context.Int64x2Ty);
657
914
    break;
658
528
  case OpCode::I64x2__neg:
659
528
    compileVectorNeg(Context.Int64x2Ty);
660
528
    break;
661
281
  case OpCode::I64x2__all_true:
662
281
    compileVectorAllTrue(Context.Int64x2Ty);
663
281
    break;
664
264
  case OpCode::I64x2__bitmask:
665
264
    compileVectorBitMask(Context.Int64x2Ty);
666
264
    break;
667
370
  case OpCode::I64x2__extend_low_i32x4_s:
668
370
    compileVectorExtend(Context.Int32x4Ty, true, true);
669
370
    break;
670
712
  case OpCode::I64x2__extend_high_i32x4_s:
671
712
    compileVectorExtend(Context.Int32x4Ty, true, false);
672
712
    break;
673
212
  case OpCode::I64x2__extend_low_i32x4_u:
674
212
    compileVectorExtend(Context.Int32x4Ty, false, true);
675
212
    break;
676
565
  case OpCode::I64x2__extend_high_i32x4_u:
677
565
    compileVectorExtend(Context.Int32x4Ty, false, false);
678
565
    break;
679
117
  case OpCode::I64x2__shl:
680
117
    compileVectorShl(Context.Int64x2Ty);
681
117
    break;
682
325
  case OpCode::I64x2__shr_s:
683
325
    compileVectorAShr(Context.Int64x2Ty);
684
325
    break;
685
71
  case OpCode::I64x2__shr_u:
686
71
    compileVectorLShr(Context.Int64x2Ty);
687
71
    break;
688
50
  case OpCode::I64x2__add:
689
50
    compileVectorVectorAdd(Context.Int64x2Ty);
690
50
    break;
691
249
  case OpCode::I64x2__sub:
692
249
    compileVectorVectorSub(Context.Int64x2Ty);
693
249
    break;
694
80
  case OpCode::I64x2__mul:
695
80
    compileVectorVectorMul(Context.Int64x2Ty);
696
80
    break;
697
37
  case OpCode::I64x2__extmul_low_i32x4_s:
698
37
    compileVectorExtMul(Context.Int32x4Ty, true, true);
699
37
    break;
700
403
  case OpCode::I64x2__extmul_high_i32x4_s:
701
403
    compileVectorExtMul(Context.Int32x4Ty, true, false);
702
403
    break;
703
30
  case OpCode::I64x2__extmul_low_i32x4_u:
704
30
    compileVectorExtMul(Context.Int32x4Ty, false, true);
705
30
    break;
706
169
  case OpCode::I64x2__extmul_high_i32x4_u:
707
169
    compileVectorExtMul(Context.Int32x4Ty, false, false);
708
169
    break;
709
118
  case OpCode::F32x4__abs:
710
118
    compileVectorFAbs(Context.Floatx4Ty);
711
118
    break;
712
158
  case OpCode::F32x4__neg:
713
158
    compileVectorFNeg(Context.Floatx4Ty);
714
158
    break;
715
167
  case OpCode::F32x4__sqrt:
716
167
    compileVectorFSqrt(Context.Floatx4Ty);
717
167
    break;
718
122
  case OpCode::F32x4__add:
719
122
    compileVectorVectorFAdd(Context.Floatx4Ty);
720
122
    break;
721
257
  case OpCode::F32x4__sub:
722
257
    compileVectorVectorFSub(Context.Floatx4Ty);
723
257
    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
144
  case OpCode::F32x4__min:
731
144
    compileVectorVectorFMin(Context.Floatx4Ty);
732
144
    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
222
  case OpCode::F32x4__pmax:
740
222
    compileVectorVectorFPMax(Context.Floatx4Ty);
741
222
    break;
742
1.05k
  case OpCode::F32x4__ceil:
743
1.05k
    compileVectorFCeil(Context.Floatx4Ty);
744
1.05k
    break;
745
2.03k
  case OpCode::F32x4__floor:
746
2.03k
    compileVectorFFloor(Context.Floatx4Ty);
747
2.03k
    break;
748
1.93k
  case OpCode::F32x4__trunc:
749
1.93k
    compileVectorFTrunc(Context.Floatx4Ty);
750
1.93k
    break;
751
281
  case OpCode::F32x4__nearest:
752
281
    compileVectorFNearest(Context.Floatx4Ty);
753
281
    break;
754
438
  case OpCode::F64x2__abs:
755
438
    compileVectorFAbs(Context.Doublex2Ty);
756
438
    break;
757
624
  case OpCode::F64x2__neg:
758
624
    compileVectorFNeg(Context.Doublex2Ty);
759
624
    break;
760
112
  case OpCode::F64x2__sqrt:
761
112
    compileVectorFSqrt(Context.Doublex2Ty);
762
112
    break;
763
49
  case OpCode::F64x2__add:
764
49
    compileVectorVectorFAdd(Context.Doublex2Ty);
765
49
    break;
766
210
  case OpCode::F64x2__sub:
767
210
    compileVectorVectorFSub(Context.Doublex2Ty);
768
210
    break;
769
231
  case OpCode::F64x2__mul:
770
231
    compileVectorVectorFMul(Context.Doublex2Ty);
771
231
    break;
772
37
  case OpCode::F64x2__div:
773
37
    compileVectorVectorFDiv(Context.Doublex2Ty);
774
37
    break;
775
169
  case OpCode::F64x2__min:
776
169
    compileVectorVectorFMin(Context.Doublex2Ty);
777
169
    break;
778
150
  case OpCode::F64x2__max:
779
150
    compileVectorVectorFMax(Context.Doublex2Ty);
780
150
    break;
781
281
  case OpCode::F64x2__pmin:
782
281
    compileVectorVectorFPMin(Context.Doublex2Ty);
783
281
    break;
784
103
  case OpCode::F64x2__pmax:
785
103
    compileVectorVectorFPMax(Context.Doublex2Ty);
786
103
    break;
787
667
  case OpCode::F64x2__ceil:
788
667
    compileVectorFCeil(Context.Doublex2Ty);
789
667
    break;
790
798
  case OpCode::F64x2__floor:
791
798
    compileVectorFFloor(Context.Doublex2Ty);
792
798
    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
186
  case OpCode::I32x4__trunc_sat_f32x4_s:
800
186
    compileVectorTruncSatS32(Context.Floatx4Ty, false);
801
186
    break;
802
3.77k
  case OpCode::I32x4__trunc_sat_f32x4_u:
803
3.77k
    compileVectorTruncSatU32(Context.Floatx4Ty, false);
804
3.77k
    break;
805
346
  case OpCode::F32x4__convert_i32x4_s:
806
346
    compileVectorConvertS(Context.Int32x4Ty, Context.Floatx4Ty, false);
807
346
    break;
808
705
  case OpCode::F32x4__convert_i32x4_u:
809
705
    compileVectorConvertU(Context.Int32x4Ty, Context.Floatx4Ty, false);
810
705
    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
303
  case OpCode::F64x2__convert_low_i32x4_s:
818
303
    compileVectorConvertS(Context.Int32x4Ty, Context.Doublex2Ty, true);
819
303
    break;
820
1.20k
  case OpCode::F64x2__convert_low_i32x4_u:
821
1.20k
    compileVectorConvertU(Context.Int32x4Ty, Context.Doublex2Ty, true);
822
1.20k
    break;
823
737
  case OpCode::F32x4__demote_f64x2_zero:
824
737
    compileVectorDemote();
825
737
    break;
826
789
  case OpCode::F64x2__promote_low_f32x4:
827
789
    compileVectorPromote();
828
789
    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
20
  case OpCode::I16x8__relaxed_q15mulr_s:
882
20
    compileVectorVectorQ15MulSat();
883
20
    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
117k
  }
895
117k
  return {};
896
117k
}
897
898
void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy,
899
1.24k
                                            unsigned Index) noexcept {
900
1.24k
  auto Vector = Builder.createBitCast(Stack.back(), VectorTy);
901
  if constexpr (Endian::native == Endian::big) {
902
    Index = VectorTy.getVectorSize() - Index - 1;
903
  }
904
1.24k
  Stack.back() =
905
1.24k
      Builder.createExtractElement(Vector, LLContext.getInt64(Index));
906
1.24k
}
907
908
void FunctionCompiler::compileExtractLaneOp(LLVM::Type VectorTy, unsigned Index,
909
                                            LLVM::Type ExtendTy,
910
928
                                            bool Signed) noexcept {
911
928
  compileExtractLaneOp(VectorTy, Index);
912
928
  if (Signed) {
913
508
    Stack.back() = Builder.createSExt(Stack.back(), ExtendTy);
914
508
  } else {
915
420
    Stack.back() = Builder.createZExt(Stack.back(), ExtendTy);
916
420
  }
917
928
}
918
919
void FunctionCompiler::compileLoadLaneOp(unsigned MemoryIndex, uint64_t Offset,
920
                                         unsigned Alignment, unsigned Index,
921
                                         LLVM::Type LoadTy,
922
498
                                         LLVM::Type VectorTy) noexcept {
923
498
  auto Vector = stackPop();
924
498
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
925
  if constexpr (Endian::native == Endian::big) {
926
    Index = VectorTy.getVectorSize() - 1 - Index;
927
  }
928
498
  auto Value = Stack.back();
929
498
  Stack.back() = Builder.createBitCast(
930
498
      Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
931
498
                                  Value, LLContext.getInt64(Index)),
932
498
      Context.Int64x2Ty);
933
498
}
934
935
void FunctionCompiler::compileReplaceLaneOp(LLVM::Type VectorTy,
936
805
                                            unsigned Index) noexcept {
937
805
  auto Value = Builder.createTrunc(stackPop(), VectorTy.getElementType());
938
805
  auto Vector = Stack.back();
939
  if constexpr (Endian::native == Endian::big) {
940
    Index = VectorTy.getVectorSize() - Index - 1;
941
  }
942
805
  Stack.back() = Builder.createBitCast(
943
805
      Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
944
805
                                  Value, LLContext.getInt64(Index)),
945
805
      Context.Int64x2Ty);
946
805
}
947
948
void FunctionCompiler::compileSplatLoadOp(unsigned MemoryIndex, uint64_t Offset,
949
                                          unsigned Alignment, LLVM::Type LoadTy,
950
550
                                          LLVM::Type VectorTy) noexcept {
951
550
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
952
550
  compileSplatOp(VectorTy);
953
550
}
954
955
47.3k
void FunctionCompiler::compileSplatOp(LLVM::Type VectorTy) noexcept {
956
47.3k
  auto Undef = LLVM::Value::getUndef(VectorTy);
957
47.3k
  auto Zeros = LLVM::Value::getConstNull(
958
47.3k
      LLVM::Type::getVectorType(Context.Int32Ty, VectorTy.getVectorSize()));
959
47.3k
  auto Value = Builder.createTrunc(Stack.back(), VectorTy.getElementType());
960
47.3k
  auto Vector =
961
47.3k
      Builder.createInsertElement(Undef, Value, LLContext.getInt64(0));
962
47.3k
  Vector = Builder.createShuffleVector(Vector, Undef, Zeros);
963
964
47.3k
  Stack.back() = Builder.createBitCast(Vector, Context.Int64x2Ty);
965
47.3k
}
966
967
void FunctionCompiler::compileStoreLaneOp(uint32_t MemoryIndex, uint64_t Offset,
968
                                          uint32_t Alignment, uint8_t Index,
969
                                          LLVM::Type LoadTy,
970
390
                                          LLVM::Type VectorTy) noexcept {
971
390
  auto Vector = Stack.back();
972
  if constexpr (Endian::native == Endian::big) {
973
    Index = static_cast<uint8_t>(VectorTy.getVectorSize() - Index - 1);
974
  }
975
390
  Stack.back() = Builder.createExtractElement(
976
390
      Builder.createBitCast(Vector, VectorTy), LLContext.getInt64(Index));
977
390
  compileStoreOp(MemoryIndex, Offset, Alignment, LoadTy);
978
390
}
979
980
2.48k
void FunctionCompiler::compileVectorAbs(LLVM::Type VectorTy) noexcept {
981
2.48k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
982
2.48k
    return Builder.createIntrinsic(LLVM::Core::Abs, {V.getType()},
983
2.48k
                                   {V, LLContext.getFalse()});
984
2.48k
  });
985
2.48k
}
986
987
901
void FunctionCompiler::compileVectorAllTrue(LLVM::Type VectorTy) noexcept {
988
901
  compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept {
989
901
    const auto Size = VectorTy.getVectorSize();
990
901
    auto IntType = LLContext.getIntNTy(Size);
991
901
    auto Zero = LLVM::Value::getConstNull(VectorTy);
992
901
    auto Cmp = Builder.createBitCast(Builder.createICmpEQ(V, Zero), IntType);
993
901
    auto CmpZero = LLVM::Value::getConstInt(IntType, 0);
994
901
    return Builder.createICmpEQ(Cmp, CmpZero);
995
901
  });
996
901
}
997
998
131
void FunctionCompiler::compileVectorAnyTrue() noexcept {
999
131
  compileVectorReduceIOp(Context.Int128x1Ty, [this](auto V) noexcept {
1000
131
    auto Zero = LLVM::Value::getConstNull(Context.Int128x1Ty);
1001
131
    return Builder.createBitCast(Builder.createICmpNE(V, Zero),
1002
131
                                 LLContext.getInt1Ty());
1003
131
  });
1004
131
}
1005
1006
1.99k
void FunctionCompiler::compileVectorAShr(LLVM::Type VectorTy) noexcept {
1007
1.99k
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1008
1.99k
    return Builder.createAShr(LHS, RHS);
1009
1.99k
  });
1010
1.99k
}
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.23k
    LLVM::Type VectorTy, LLVMIntPredicate Predicate) noexcept {
1023
5.23k
  auto RHS = stackPop();
1024
5.23k
  auto LHS = stackPop();
1025
5.23k
  auto Result = Builder.createSExt(
1026
5.23k
      Builder.createICmp(Predicate, Builder.createBitCast(LHS, VectorTy),
1027
5.23k
                         Builder.createBitCast(RHS, VectorTy)),
1028
5.23k
      VectorTy);
1029
5.23k
  stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
1030
5.23k
}
1031
1032
void FunctionCompiler::compileVectorCompareOp(LLVM::Type VectorTy,
1033
                                              LLVMRealPredicate Predicate,
1034
3.20k
                                              LLVM::Type ResultTy) noexcept {
1035
3.20k
  auto RHS = stackPop();
1036
3.20k
  auto LHS = stackPop();
1037
3.20k
  auto Result = Builder.createSExt(
1038
3.20k
      Builder.createFCmp(Predicate, Builder.createBitCast(LHS, VectorTy),
1039
3.20k
                         Builder.createBitCast(RHS, VectorTy)),
1040
3.20k
      ResultTy);
1041
3.20k
  stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
1042
3.20k
}
1043
1044
void FunctionCompiler::compileVectorConvertS(LLVM::Type VectorTy,
1045
                                             LLVM::Type FPVectorTy,
1046
649
                                             bool Low) noexcept {
1047
649
  compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
1048
649
    if (Low) {
1049
303
      const auto Size = VectorTy.getVectorSize() / 2;
1050
303
      std::vector<uint32_t> Mask(Size);
1051
303
      if constexpr (Endian::native == Endian::little) {
1052
303
        std::iota(Mask.begin(), Mask.end(), 0);
1053
      } else {
1054
        std::iota(Mask.begin(), Mask.end(), Size);
1055
      }
1056
303
      V = Builder.createShuffleVector(
1057
303
          V, LLVM::Value::getUndef(VectorTy),
1058
303
          LLVM::Value::getConstVector32(LLContext, Mask));
1059
303
    }
1060
649
    return Builder.createSIToFP(V, FPVectorTy);
1061
649
  });
1062
649
}
1063
1064
void FunctionCompiler::compileVectorConvertU(LLVM::Type VectorTy,
1065
                                             LLVM::Type FPVectorTy,
1066
1.90k
                                             bool Low) noexcept {
1067
1.90k
  compileVectorOp(VectorTy, [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
1068
1.90k
    if (Low) {
1069
1.20k
      const auto Size = VectorTy.getVectorSize() / 2;
1070
1.20k
      std::vector<uint32_t> Mask(Size);
1071
1.20k
      if constexpr (Endian::native == Endian::little) {
1072
1.20k
        std::iota(Mask.begin(), Mask.end(), 0);
1073
      } else {
1074
        std::iota(Mask.begin(), Mask.end(), Size);
1075
      }
1076
1.20k
      V = Builder.createShuffleVector(
1077
1.20k
          V, LLVM::Value::getUndef(VectorTy),
1078
1.20k
          LLVM::Value::getConstVector32(LLContext, Mask));
1079
1.20k
    }
1080
1.90k
    return Builder.createUIToFP(V, FPVectorTy);
1081
1.90k
  });
1082
1.90k
}
1083
1084
737
void FunctionCompiler::compileVectorDemote() noexcept {
1085
737
  compileVectorOp(Context.Doublex2Ty, [this](auto V) noexcept {
1086
737
    auto Demoted =
1087
737
        Builder.createFPTrunc(V, LLVM::Type::getVectorType(Context.FloatTy, 2));
1088
737
    auto ZeroV = LLVM::Value::getConstNull(Demoted.getType());
1089
737
    if constexpr (Endian::native == Endian::little) {
1090
737
      return Builder.createShuffleVector(
1091
737
          Demoted, ZeroV,
1092
737
          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
737
  });
1099
737
}
1100
1101
void FunctionCompiler::compileVectorExtAddPairwise(LLVM::Type VectorTy,
1102
2.85k
                                                   bool Signed) noexcept {
1103
2.85k
  compileVectorOp(
1104
2.85k
      VectorTy, [this, VectorTy, Signed](auto V) noexcept -> LLVM::Value {
1105
2.85k
        auto ExtTy =
1106
2.85k
            VectorTy.getExtendedElementVectorType().getHalfElementsVectorType();
1107
2.85k
#if defined(__x86_64__)
1108
2.85k
        const auto Count = VectorTy.getVectorSize();
1109
2.85k
        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.85k
        if (Context.SupportSSSE3 && Count == 16) {
1126
709
          assuming(LLVM::Core::X86SSSE3PMAddUbSw128 !=
1127
709
                   LLVM::Core::NotIntrinsic);
1128
709
          if (Signed) {
1129
369
            return Builder.createIntrinsic(
1130
369
                LLVM::Core::X86SSSE3PMAddUbSw128, {},
1131
369
                {Builder.createVectorSplat(16, LLContext.getInt8(1)), V});
1132
369
          } else {
1133
340
            return Builder.createIntrinsic(
1134
340
                LLVM::Core::X86SSSE3PMAddUbSw128, {},
1135
340
                {V, Builder.createVectorSplat(16, LLContext.getInt8(1))});
1136
340
          }
1137
709
        }
1138
2.14k
        if (Context.SupportSSE2 && Count == 8) {
1139
2.14k
          assuming(LLVM::Core::X86SSE2PMAddWd != LLVM::Core::NotIntrinsic);
1140
2.14k
          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.00k
            V = Builder.createXor(
1146
1.00k
                V, Builder.createVectorSplat(8, LLContext.getInt16(0x8000)));
1147
1.00k
            V = Builder.createIntrinsic(
1148
1.00k
                LLVM::Core::X86SSE2PMAddWd, {},
1149
1.00k
                {V, Builder.createVectorSplat(8, LLContext.getInt16(1))});
1150
1.00k
            return Builder.createAdd(
1151
1.00k
                V, Builder.createVectorSplat(4, LLContext.getInt32(0x10000)));
1152
1.00k
          }
1153
2.14k
        }
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.14k
      });
1184
2.85k
}
1185
1186
void FunctionCompiler::compileVectorExtend(LLVM::Type FromTy, bool Signed,
1187
6.02k
                                           bool Low) noexcept {
1188
6.02k
  auto ExtTy = FromTy.getExtendedElementVectorType();
1189
6.02k
  const auto Count = FromTy.getVectorSize();
1190
6.02k
  std::vector<uint32_t> Mask(Count / 2);
1191
  if constexpr (Endian::native == Endian::big) {
1192
    Low = !Low;
1193
  }
1194
6.02k
  std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
1195
6.02k
  auto R = Builder.createBitCast(Stack.back(), FromTy);
1196
6.02k
  if (Signed) {
1197
2.80k
    R = Builder.createSExt(R, ExtTy);
1198
3.22k
  } else {
1199
3.22k
    R = Builder.createZExt(R, ExtTy);
1200
3.22k
  }
1201
6.02k
  R = Builder.createShuffleVector(
1202
6.02k
      R, LLVM::Value::getUndef(ExtTy),
1203
6.02k
      LLVM::Value::getConstVector32(LLContext, Mask));
1204
6.02k
  Stack.back() = Builder.createBitCast(R, Context.Int64x2Ty);
1205
6.02k
}
1206
1207
void FunctionCompiler::compileVectorExtMul(LLVM::Type FromTy, bool Signed,
1208
1.92k
                                           bool Low) noexcept {
1209
1.92k
  auto ExtTy = FromTy.getExtendedElementVectorType();
1210
1.92k
  const auto Count = FromTy.getVectorSize();
1211
1.92k
  std::vector<uint32_t> Mask(Count / 2);
1212
1.92k
  std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
1213
3.84k
  auto Extend = [this, FromTy, Signed, ExtTy, &Mask](LLVM::Value R) noexcept {
1214
3.84k
    R = Builder.createBitCast(R, FromTy);
1215
3.84k
    if (Signed) {
1216
1.73k
      R = Builder.createSExt(R, ExtTy);
1217
2.10k
    } else {
1218
2.10k
      R = Builder.createZExt(R, ExtTy);
1219
2.10k
    }
1220
3.84k
    return Builder.createShuffleVector(
1221
3.84k
        R, LLVM::Value::getUndef(ExtTy),
1222
3.84k
        LLVM::Value::getConstVector32(LLContext, Mask));
1223
3.84k
  };
1224
1.92k
  auto RHS = Extend(stackPop());
1225
1.92k
  auto LHS = Extend(stackPop());
1226
1.92k
  stackPush(
1227
1.92k
      Builder.createBitCast(Builder.createMul(RHS, LHS), Context.Int64x2Ty));
1228
1.92k
}
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.71k
void FunctionCompiler::compileVectorFCeil(LLVM::Type VectorTy) noexcept {
1238
1.71k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1239
1.71k
    assuming(LLVM::Core::Ceil != LLVM::Core::NotIntrinsic);
1240
1.71k
    return Builder.createUnaryIntrinsic(LLVM::Core::Ceil, V);
1241
1.71k
  });
1242
1.71k
}
1243
1244
2.82k
void FunctionCompiler::compileVectorFFloor(LLVM::Type VectorTy) noexcept {
1245
2.82k
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1246
2.82k
    assuming(LLVM::Core::Floor != LLVM::Core::NotIntrinsic);
1247
2.82k
    return Builder.createUnaryIntrinsic(LLVM::Core::Floor, V);
1248
2.82k
  });
1249
2.82k
}
1250
1251
434
void FunctionCompiler::compileVectorFNearest(LLVM::Type VectorTy) noexcept {
1252
434
  compileVectorOp(VectorTy, [&](auto V) noexcept {
1253
434
#if LLVM_VERSION_MAJOR >= 12 && !defined(__s390x__)
1254
434
    assuming(LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic);
1255
434
    if (LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic) {
1256
434
      return Builder.createUnaryIntrinsic(LLVM::Core::Roundeven, V);
1257
434
    }
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
434
}
1285
1286
782
void FunctionCompiler::compileVectorFNeg(LLVM::Type VectorTy) noexcept {
1287
782
  compileVectorOp(VectorTy,
1288
782
                  [this](auto V) noexcept { return Builder.createFNeg(V); });
1289
782
}
1290
1291
279
void FunctionCompiler::compileVectorFSqrt(LLVM::Type VectorTy) noexcept {
1292
279
  compileVectorOp(VectorTy, [this](auto V) noexcept {
1293
279
    assuming(LLVM::Core::Sqrt != LLVM::Core::NotIntrinsic);
1294
279
    return Builder.createUnaryIntrinsic(LLVM::Core::Sqrt, V);
1295
279
  });
1296
279
}
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.87k
                                           LLVM::Type LoadTy) noexcept {
1308
4.87k
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
1309
4.87k
  Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
1310
4.87k
}
1311
1312
void FunctionCompiler::compileVectorLoadOp(unsigned MemoryIndex,
1313
                                           uint64_t Offset, unsigned Alignment,
1314
                                           LLVM::Type LoadTy,
1315
                                           LLVM::Type ExtendTy,
1316
1.61k
                                           bool Signed) noexcept {
1317
1.61k
  compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy, ExtendTy, Signed);
1318
1.61k
  Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
1319
1.61k
}
1320
1321
720
void FunctionCompiler::compileVectorLShr(LLVM::Type VectorTy) noexcept {
1322
720
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1323
720
    return Builder.createLShr(LHS, RHS);
1324
720
  });
1325
720
}
1326
1327
void FunctionCompiler::compileVectorNarrow(LLVM::Type FromTy,
1328
683
                                           bool Signed) noexcept {
1329
683
  auto [MinInt,
1330
683
        MaxInt] = [&]() noexcept -> std::tuple<LLVM::Value, LLVM::Value> {
1331
683
    switch (FromTy.getElementType().getIntegerBitWidth()) {
1332
280
    case 16: {
1333
280
      const auto Min =
1334
280
          static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::min()
1335
280
                                      : std::numeric_limits<uint8_t>::min());
1336
280
      const auto Max =
1337
280
          static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::max()
1338
280
                                      : std::numeric_limits<uint8_t>::max());
1339
280
      return {LLContext.getInt16(static_cast<uint16_t>(Min)),
1340
280
              LLContext.getInt16(static_cast<uint16_t>(Max))};
1341
0
    }
1342
403
    case 32: {
1343
403
      const auto Min =
1344
403
          static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::min()
1345
403
                                      : std::numeric_limits<uint16_t>::min());
1346
403
      const auto Max =
1347
403
          static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::max()
1348
403
                                      : std::numeric_limits<uint16_t>::max());
1349
403
      return {LLContext.getInt32(static_cast<uint32_t>(Min)),
1350
403
              LLContext.getInt32(static_cast<uint32_t>(Max))};
1351
0
    }
1352
0
    default:
1353
0
      assumingUnreachable();
1354
683
    }
1355
683
  }();
1356
683
  const auto Count = FromTy.getVectorSize();
1357
683
  auto VMin = Builder.createVectorSplat(Count, MinInt);
1358
683
  auto VMax = Builder.createVectorSplat(Count, MaxInt);
1359
1360
683
  auto TruncTy = FromTy.getTruncatedElementVectorType();
1361
1362
683
  auto F2 = Builder.createBitCast(stackPop(), FromTy);
1363
683
  F2 = Builder.createSelect(Builder.createICmpSLT(F2, VMin), VMin, F2);
1364
683
  F2 = Builder.createSelect(Builder.createICmpSGT(F2, VMax), VMax, F2);
1365
683
  F2 = Builder.createTrunc(F2, TruncTy);
1366
1367
683
  auto F1 = Builder.createBitCast(stackPop(), FromTy);
1368
683
  F1 = Builder.createSelect(Builder.createICmpSLT(F1, VMin), VMin, F1);
1369
683
  F1 = Builder.createSelect(Builder.createICmpSGT(F1, VMax), VMax, F1);
1370
683
  F1 = Builder.createTrunc(F1, TruncTy);
1371
1372
683
  std::vector<uint32_t> Mask(Count * 2);
1373
683
  std::iota(Mask.begin(), Mask.end(), 0);
1374
683
  auto V = Endian::native == Endian::little
1375
683
               ? Builder.createShuffleVector(
1376
683
                     F1, F2, LLVM::Value::getConstVector32(LLContext, Mask))
1377
683
               : Builder.createShuffleVector(
1378
0
                     F2, F1, LLVM::Value::getConstVector32(LLContext, Mask));
1379
683
  stackPush(Builder.createBitCast(V, Context.Int64x2Ty));
1380
683
}
1381
1382
3.19k
void FunctionCompiler::compileVectorNeg(LLVM::Type VectorTy) noexcept {
1383
3.19k
  compileVectorOp(VectorTy,
1384
3.19k
                  [this](auto V) noexcept { return Builder.createNeg(V); });
1385
3.19k
}
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
789
void FunctionCompiler::compileVectorPromote() noexcept {
1395
789
  compileVectorOp(Context.Floatx4Ty, [this](auto V) noexcept {
1396
789
    auto UndefV = LLVM::Value::getUndef(V.getType());
1397
789
    auto Low = Builder.createShuffleVector(
1398
789
        V, UndefV, LLVM::Value::getConstVector32(LLContext, {0u, 1u}));
1399
789
    return Builder.createFPExt(Low,
1400
789
                               LLVM::Type::getVectorType(Context.DoubleTy, 2));
1401
789
  });
1402
789
}
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.42k
void FunctionCompiler::compileVectorShl(LLVM::Type VectorTy) noexcept {
1484
1.42k
  compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1485
1.42k
    return Builder.createShl(LHS, RHS);
1486
1.42k
  });
1487
1.42k
}
1488
1489
105
void FunctionCompiler::compileVectorSwizzle() noexcept {
1490
105
  auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
1491
105
  auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
1492
1493
105
#if defined(__x86_64__)
1494
105
  if (Context.SupportSSSE3) {
1495
105
    auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112));
1496
105
    auto Added = Builder.createAdd(Index, Magic);
1497
105
    auto NewIndex = Builder.createSelect(
1498
105
        Builder.createICmpUGT(Index, Added),
1499
105
        LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added);
1500
105
    assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic);
1501
105
    stackPush(Builder.createBitCast(
1502
105
        Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {},
1503
105
                                {Vector, NewIndex}),
1504
105
        Context.Int64x2Ty));
1505
105
    return;
1506
105
  }
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
955
                                                bool PadZero) noexcept {
1561
955
  compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
1562
955
    const auto Size = VectorTy.getVectorSize();
1563
955
    auto FPTy = VectorTy.getElementType();
1564
955
    auto IntMin = LLContext.getInt32(
1565
955
        static_cast<uint32_t>(std::numeric_limits<int32_t>::min()));
1566
955
    auto IntMax = LLContext.getInt32(
1567
955
        static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
1568
955
    auto IntMinV = Builder.createVectorSplat(Size, IntMin);
1569
955
    auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
1570
955
    auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType());
1571
955
    auto FPMin = Builder.createSIToFP(IntMin, FPTy);
1572
955
    auto FPMax = Builder.createSIToFP(IntMax, FPTy);
1573
955
    auto FPMinV = Builder.createVectorSplat(Size, FPMin);
1574
955
    auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
1575
1576
955
    auto Normal = Builder.createFCmpORD(V, V);
1577
955
    auto NotUnder = Builder.createFCmpUGE(V, FPMinV);
1578
955
    auto NotOver = Builder.createFCmpULT(V, FPMaxV);
1579
955
    V = Builder.createFPToSI(
1580
955
        V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
1581
955
    V = Builder.createSelect(Normal, V, IntZeroV);
1582
955
    V = Builder.createSelect(NotUnder, V, IntMinV);
1583
955
    V = Builder.createSelect(NotOver, V, IntMaxV);
1584
955
    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
955
    return V;
1596
955
  });
1597
955
}
1598
1599
void FunctionCompiler::compileVectorTruncSatU32(LLVM::Type VectorTy,
1600
5.97k
                                                bool PadZero) noexcept {
1601
5.97k
  compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
1602
5.97k
    const auto Size = VectorTy.getVectorSize();
1603
5.97k
    auto FPTy = VectorTy.getElementType();
1604
5.97k
    auto IntMin = LLContext.getInt32(std::numeric_limits<uint32_t>::min());
1605
5.97k
    auto IntMax = LLContext.getInt32(std::numeric_limits<uint32_t>::max());
1606
5.97k
    auto IntMinV = Builder.createVectorSplat(Size, IntMin);
1607
5.97k
    auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
1608
5.97k
    auto FPMin = Builder.createUIToFP(IntMin, FPTy);
1609
5.97k
    auto FPMax = Builder.createUIToFP(IntMax, FPTy);
1610
5.97k
    auto FPMinV = Builder.createVectorSplat(Size, FPMin);
1611
5.97k
    auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
1612
1613
5.97k
    auto NotUnder = Builder.createFCmpOGE(V, FPMinV);
1614
5.97k
    auto NotOver = Builder.createFCmpULT(V, FPMaxV);
1615
5.97k
    V = Builder.createFPToUI(
1616
5.97k
        V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
1617
5.97k
    V = Builder.createSelect(NotUnder, V, IntMinV);
1618
5.97k
    V = Builder.createSelect(NotOver, V, IntMaxV);
1619
5.97k
    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.97k
    return V;
1632
5.97k
  });
1633
5.97k
}
1634
1635
406
void FunctionCompiler::compileVectorVectorAdd(LLVM::Type VectorTy) noexcept {
1636
406
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1637
406
    return Builder.createAdd(LHS, RHS);
1638
406
  });
1639
406
}
1640
1641
void FunctionCompiler::compileVectorVectorAddSat(LLVM::Type VectorTy,
1642
991
                                                 bool Signed) noexcept {
1643
991
  auto ID = Signed ? LLVM::Core::SAddSat : LLVM::Core::UAddSat;
1644
991
  assuming(ID != LLVM::Core::NotIntrinsic);
1645
991
  compileVectorVectorOp(
1646
991
      VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
1647
991
        return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
1648
991
      });
1649
991
}
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
344
void FunctionCompiler::compileVectorVectorFMin(LLVM::Type VectorTy) noexcept {
1682
344
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1683
344
    auto LNaN = Builder.createFCmpUNO(LHS, LHS);
1684
344
    auto RNaN = Builder.createFCmpUNO(RHS, RHS);
1685
344
    auto OLT = Builder.createFCmpOLT(LHS, RHS);
1686
344
    auto OGT = Builder.createFCmpOGT(LHS, RHS);
1687
344
    auto Ret = Builder.createBitCast(
1688
344
        Builder.createOr(Builder.createBitCast(LHS, Context.Int64x2Ty),
1689
344
                         Builder.createBitCast(RHS, Context.Int64x2Ty)),
1690
344
        LHS.getType());
1691
344
    Ret = Builder.createSelect(OGT, RHS, Ret);
1692
344
    Ret = Builder.createSelect(OLT, LHS, Ret);
1693
344
    Ret = Builder.createSelect(LNaN, LHS, Ret);
1694
344
    Ret = Builder.createSelect(RNaN, RHS, Ret);
1695
344
    return Ret;
1696
344
  });
1697
344
}
1698
1699
269
void FunctionCompiler::compileVectorVectorFMul(LLVM::Type VectorTy) noexcept {
1700
269
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1701
269
    return Builder.createFMul(LHS, RHS);
1702
269
  });
1703
269
}
1704
1705
325
void FunctionCompiler::compileVectorVectorFPMax(LLVM::Type VectorTy) noexcept {
1706
325
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1707
325
    auto Cmp = Builder.createFCmpOGT(RHS, LHS);
1708
325
    return Builder.createSelect(Cmp, RHS, LHS);
1709
325
  });
1710
325
}
1711
1712
332
void FunctionCompiler::compileVectorVectorFPMin(LLVM::Type VectorTy) noexcept {
1713
332
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1714
332
    auto Cmp = Builder.createFCmpOLT(RHS, LHS);
1715
332
    return Builder.createSelect(Cmp, RHS, LHS);
1716
332
  });
1717
332
}
1718
1719
467
void FunctionCompiler::compileVectorVectorFSub(LLVM::Type VectorTy) noexcept {
1720
467
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1721
467
    return Builder.createFSub(LHS, RHS);
1722
467
  });
1723
467
}
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
362
void FunctionCompiler::compileVectorVectorMul(LLVM::Type VectorTy) noexcept {
1734
362
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1735
362
    return Builder.createMul(LHS, RHS);
1736
362
  });
1737
362
}
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
162
void FunctionCompiler::compileVectorVectorQ15MulSat() noexcept {
1749
162
  compileVectorVectorOp(
1750
162
      Context.Int16x8Ty, [this](auto LHS, auto RHS) noexcept -> LLVM::Value {
1751
162
#if defined(__x86_64__)
1752
162
        if (Context.SupportSSSE3) {
1753
162
          assuming(LLVM::Core::X86SSSE3PMulHrSw128 != LLVM::Core::NotIntrinsic);
1754
162
          auto Result = Builder.createIntrinsic(LLVM::Core::X86SSSE3PMulHrSw128,
1755
162
                                                {}, {LHS, RHS});
1756
162
          auto IntMaxV = Builder.createVectorSplat(
1757
162
              8, LLContext.getInt16(UINT16_C(0x8000)));
1758
162
          auto NotOver = Builder.createSExt(
1759
162
              Builder.createICmpEQ(Result, IntMaxV), Context.Int16x8Ty);
1760
162
          return Builder.createXor(Result, NotOver);
1761
162
        }
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
162
      });
1794
162
}
1795
1796
497
void FunctionCompiler::compileVectorVectorSMax(LLVM::Type VectorTy) noexcept {
1797
497
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1798
497
    return Builder.createIntrinsic(LLVM::Core::SMax, {LHS.getType()},
1799
497
                                   {LHS, RHS});
1800
497
  });
1801
497
}
1802
1803
321
void FunctionCompiler::compileVectorVectorSMin(LLVM::Type VectorTy) noexcept {
1804
321
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1805
321
    return Builder.createIntrinsic(LLVM::Core::SMin, {LHS.getType()},
1806
321
                                   {LHS, RHS});
1807
321
  });
1808
321
}
1809
1810
705
void FunctionCompiler::compileVectorVectorSub(LLVM::Type VectorTy) noexcept {
1811
705
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1812
705
    return Builder.createSub(LHS, RHS);
1813
705
  });
1814
705
}
1815
1816
void FunctionCompiler::compileVectorVectorSubSat(LLVM::Type VectorTy,
1817
392
                                                 bool Signed) noexcept {
1818
392
  auto ID = Signed ? LLVM::Core::SSubSat : LLVM::Core::USubSat;
1819
392
  assuming(ID != LLVM::Core::NotIntrinsic);
1820
392
  compileVectorVectorOp(
1821
392
      VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
1822
392
        return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
1823
392
      });
1824
392
}
1825
1826
261
void FunctionCompiler::compileVectorVectorUAvgr(LLVM::Type VectorTy) noexcept {
1827
261
  auto ExtendTy = VectorTy.getExtendedElementVectorType();
1828
261
  compileVectorVectorOp(
1829
261
      VectorTy,
1830
261
      [this, VectorTy, ExtendTy](auto LHS, auto RHS) noexcept -> LLVM::Value {
1831
261
#if defined(__x86_64__)
1832
261
        if (Context.SupportSSE2) {
1833
261
          const auto ID = [VectorTy]() noexcept {
1834
261
            switch (VectorTy.getElementType().getIntegerBitWidth()) {
1835
151
            case 8:
1836
151
              return LLVM::Core::X86SSE2PAvgB;
1837
110
            case 16:
1838
110
              return LLVM::Core::X86SSE2PAvgW;
1839
0
            default:
1840
0
              assumingUnreachable();
1841
261
            }
1842
261
          }();
1843
261
          assuming(ID != LLVM::Core::NotIntrinsic);
1844
261
          return Builder.createIntrinsic(ID, {}, {LHS, RHS});
1845
261
        }
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
261
      });
1871
261
}
1872
1873
706
void FunctionCompiler::compileVectorVectorUMax(LLVM::Type VectorTy) noexcept {
1874
706
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1875
706
    return Builder.createIntrinsic(LLVM::Core::UMax, {LHS.getType()},
1876
706
                                   {LHS, RHS});
1877
706
  });
1878
706
}
1879
1880
281
void FunctionCompiler::compileVectorVectorUMin(LLVM::Type VectorTy) noexcept {
1881
281
  compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
1882
281
    return Builder.createIntrinsic(LLVM::Core::UMin, {LHS.getType()},
1883
281
                                   {LHS, RHS});
1884
281
  });
1885
281
}
1886
1887
} // namespace WasmEdge