Coverage Report

Created: 2026-11-09 06:49

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