Coverage Report

Created: 2025-09-27 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "llvm/compiler.h"
5
6
#include "aot/version.h"
7
#include "common/defines.h"
8
#include "common/filesystem.h"
9
#include "common/spdlog.h"
10
#include "data.h"
11
#include "llvm.h"
12
#include "system/allocator.h"
13
14
#include <algorithm>
15
#include <array>
16
#include <cinttypes>
17
#include <cstdint>
18
#include <cstdlib>
19
#include <limits>
20
#include <memory>
21
#include <numeric>
22
#include <string>
23
#include <string_view>
24
#include <system_error>
25
26
namespace LLVM = WasmEdge::LLVM;
27
using namespace std::literals;
28
29
namespace {
30
31
static bool
32
isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
33
static LLVM::Type toLLVMType(LLVM::Context LLContext,
34
                             const WasmEdge::ValType &ValType) noexcept;
35
static std::vector<LLVM::Type>
36
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
37
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
38
static LLVM::Type
39
toLLVMRetsType(LLVM::Context LLContext,
40
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
41
static LLVM::Type
42
toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
43
           const WasmEdge::AST::FunctionType &FuncType) noexcept;
44
static LLVM::Value
45
toLLVMConstantZero(LLVM::Context LLContext,
46
                   const WasmEdge::ValType &ValType) noexcept;
47
static std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
48
                                             LLVM::Value Struct) noexcept;
49
class FunctionCompiler;
50
51
// XXX: Misalignment handler not implemented yet, forcing unalignment
52
// force unalignment load/store
53
static inline constexpr const bool kForceUnalignment = true;
54
55
// force checking div/rem on zero
56
static inline constexpr const bool kForceDivCheck = true;
57
58
// Size of a ValVariant
59
static inline constexpr const uint32_t kValSize = sizeof(WasmEdge::ValVariant);
60
61
// Translate Compiler::OptimizationLevel to llvm::PassBuilder version
62
#if LLVM_VERSION_MAJOR >= 13
63
static inline const char *
64
toLLVMLevel(WasmEdge::CompilerConfigure::OptimizationLevel Level) noexcept {
65
  using OL = WasmEdge::CompilerConfigure::OptimizationLevel;
66
  switch (Level) {
67
  case OL::O0:
68
    return "default<O0>,function(tailcallelim)";
69
  case OL::O1:
70
    return "default<O1>,function(tailcallelim)";
71
  case OL::O2:
72
    return "default<O2>";
73
  case OL::O3:
74
    return "default<O3>";
75
  case OL::Os:
76
    return "default<Os>";
77
  case OL::Oz:
78
    return "default<Oz>";
79
  default:
80
    assumingUnreachable();
81
  }
82
}
83
#else
84
static inline std::pair<unsigned int, unsigned int>
85
2.00k
toLLVMLevel(WasmEdge::CompilerConfigure::OptimizationLevel Level) noexcept {
86
2.00k
  using OL = WasmEdge::CompilerConfigure::OptimizationLevel;
87
2.00k
  switch (Level) {
88
0
  case OL::O0:
89
0
    return {0, 0};
90
0
  case OL::O1:
91
0
    return {1, 0};
92
0
  case OL::O2:
93
0
    return {2, 0};
94
2.00k
  case OL::O3:
95
2.00k
    return {3, 0};
96
0
  case OL::Os:
97
0
    return {2, 1};
98
0
  case OL::Oz:
99
0
    return {2, 2};
100
0
  default:
101
0
    assumingUnreachable();
102
2.00k
  }
103
2.00k
}
104
#endif
105
106
static inline LLVMCodeGenOptLevel toLLVMCodeGenLevel(
107
2.00k
    WasmEdge::CompilerConfigure::OptimizationLevel Level) noexcept {
108
2.00k
  using OL = WasmEdge::CompilerConfigure::OptimizationLevel;
109
2.00k
  switch (Level) {
110
0
  case OL::O0:
111
0
    return LLVMCodeGenLevelNone;
112
0
  case OL::O1:
113
0
    return LLVMCodeGenLevelLess;
114
0
  case OL::O2:
115
0
    return LLVMCodeGenLevelDefault;
116
2.00k
  case OL::O3:
117
2.00k
    return LLVMCodeGenLevelAggressive;
118
0
  case OL::Os:
119
0
    return LLVMCodeGenLevelDefault;
120
0
  case OL::Oz:
121
0
    return LLVMCodeGenLevelDefault;
122
0
  default:
123
0
    assumingUnreachable();
124
2.00k
  }
125
2.00k
}
126
} // namespace
127
128
struct LLVM::Compiler::CompileContext {
129
  LLVM::Context LLContext;
130
  LLVM::Module &LLModule;
131
  LLVM::Attribute Cold;
132
  LLVM::Attribute NoAlias;
133
  LLVM::Attribute NoInline;
134
  LLVM::Attribute NoReturn;
135
  LLVM::Attribute ReadOnly;
136
  LLVM::Attribute StrictFP;
137
  LLVM::Attribute UWTable;
138
  LLVM::Attribute NoStackArgProbe;
139
  LLVM::Type VoidTy;
140
  LLVM::Type Int8Ty;
141
  LLVM::Type Int16Ty;
142
  LLVM::Type Int32Ty;
143
  LLVM::Type Int64Ty;
144
  LLVM::Type Int128Ty;
145
  LLVM::Type FloatTy;
146
  LLVM::Type DoubleTy;
147
  LLVM::Type Int8x16Ty;
148
  LLVM::Type Int16x8Ty;
149
  LLVM::Type Int32x4Ty;
150
  LLVM::Type Floatx4Ty;
151
  LLVM::Type Int64x2Ty;
152
  LLVM::Type Doublex2Ty;
153
  LLVM::Type Int128x1Ty;
154
  LLVM::Type Int8PtrTy;
155
  LLVM::Type Int32PtrTy;
156
  LLVM::Type Int64PtrTy;
157
  LLVM::Type Int128PtrTy;
158
  LLVM::Type Int8PtrPtrTy;
159
  LLVM::Type ExecCtxTy;
160
  LLVM::Type ExecCtxPtrTy;
161
  LLVM::Type IntrinsicsTableTy;
162
  LLVM::Type IntrinsicsTablePtrTy;
163
  LLVM::Message SubtargetFeatures;
164
165
#if defined(__x86_64__)
166
#if defined(__XOP__)
167
  bool SupportXOP = true;
168
#else
169
  bool SupportXOP = false;
170
#endif
171
172
#if defined(__SSE4_1__)
173
  bool SupportSSE4_1 = true;
174
#else
175
  bool SupportSSE4_1 = false;
176
#endif
177
178
#if defined(__SSSE3__)
179
  bool SupportSSSE3 = true;
180
#else
181
  bool SupportSSSE3 = false;
182
#endif
183
184
#if defined(__SSE2__)
185
  bool SupportSSE2 = true;
186
#else
187
  bool SupportSSE2 = false;
188
#endif
189
#endif
190
191
#if defined(__aarch64__)
192
#if defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__ARM_NEON_FP)
193
  bool SupportNEON = true;
194
#else
195
  bool SupportNEON = false;
196
#endif
197
#endif
198
199
  std::vector<const AST::CompositeType *> CompositeTypes;
200
  std::vector<LLVM::Value> FunctionWrappers;
201
  std::vector<std::tuple<uint32_t, LLVM::FunctionCallee,
202
                         const WasmEdge::AST::CodeSegment *>>
203
      Functions;
204
  std::vector<LLVM::Type> Globals;
205
  LLVM::Value IntrinsicsTable;
206
  LLVM::FunctionCallee Trap;
207
  CompileContext(LLVM::Context C, LLVM::Module &M,
208
                 bool IsGenericBinary) noexcept
209
2.00k
      : LLContext(C), LLModule(M),
210
2.00k
        Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)),
211
2.00k
        NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)),
212
2.00k
        NoInline(LLVM::Attribute::createEnum(C, LLVM::Core::NoInline, 0)),
213
2.00k
        NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)),
214
2.00k
        ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)),
215
2.00k
        StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)),
216
2.00k
        UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable,
217
2.00k
                                            LLVM::Core::UWTableDefault)),
218
        NoStackArgProbe(
219
2.00k
            LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})),
220
2.00k
        VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()),
221
2.00k
        Int16Ty(LLContext.getInt16Ty()), Int32Ty(LLContext.getInt32Ty()),
222
2.00k
        Int64Ty(LLContext.getInt64Ty()), Int128Ty(LLContext.getInt128Ty()),
223
2.00k
        FloatTy(LLContext.getFloatTy()), DoubleTy(LLContext.getDoubleTy()),
224
2.00k
        Int8x16Ty(LLVM::Type::getVectorType(Int8Ty, 16)),
225
2.00k
        Int16x8Ty(LLVM::Type::getVectorType(Int16Ty, 8)),
226
2.00k
        Int32x4Ty(LLVM::Type::getVectorType(Int32Ty, 4)),
227
2.00k
        Floatx4Ty(LLVM::Type::getVectorType(FloatTy, 4)),
228
2.00k
        Int64x2Ty(LLVM::Type::getVectorType(Int64Ty, 2)),
229
2.00k
        Doublex2Ty(LLVM::Type::getVectorType(DoubleTy, 2)),
230
2.00k
        Int128x1Ty(LLVM::Type::getVectorType(Int128Ty, 1)),
231
2.00k
        Int8PtrTy(Int8Ty.getPointerTo()), Int32PtrTy(Int32Ty.getPointerTo()),
232
2.00k
        Int64PtrTy(Int64Ty.getPointerTo()),
233
2.00k
        Int128PtrTy(Int128Ty.getPointerTo()),
234
2.00k
        Int8PtrPtrTy(Int8PtrTy.getPointerTo()),
235
2.00k
        ExecCtxTy(LLVM::Type::getStructType(
236
2.00k
            "ExecCtx",
237
2.00k
            std::initializer_list<LLVM::Type>{
238
                // Memory
239
2.00k
                Int8PtrTy.getPointerTo(),
240
                // Globals
241
2.00k
                Int128PtrTy.getPointerTo(),
242
                // InstrCount
243
2.00k
                Int64PtrTy,
244
                // CostTable
245
2.00k
                LLVM::Type::getArrayType(Int64Ty, UINT16_MAX + 1)
246
2.00k
                    .getPointerTo(),
247
                // Gas
248
2.00k
                Int64PtrTy,
249
                // GasLimit
250
2.00k
                Int64Ty,
251
                // StopToken
252
2.00k
                Int32PtrTy,
253
2.00k
            })),
254
2.00k
        ExecCtxPtrTy(ExecCtxTy.getPointerTo()),
255
2.00k
        IntrinsicsTableTy(LLVM::Type::getArrayType(
256
2.00k
            Int8PtrTy,
257
2.00k
            static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))),
258
2.00k
        IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()),
259
2.00k
        IntrinsicsTable(LLModule.addGlobal(IntrinsicsTablePtrTy, true,
260
2.00k
                                           LLVMExternalLinkage, LLVM::Value(),
261
2.00k
                                           "intrinsics")) {
262
2.00k
    Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
263
2.00k
    Trap.Fn = LLModule.addFunction(Trap.Ty, LLVMPrivateLinkage, "trap");
264
2.00k
    Trap.Fn.setDSOLocal(true);
265
2.00k
    Trap.Fn.addFnAttr(NoStackArgProbe);
266
2.00k
    Trap.Fn.addFnAttr(StrictFP);
267
2.00k
    Trap.Fn.addFnAttr(UWTable);
268
2.00k
    Trap.Fn.addFnAttr(NoReturn);
269
2.00k
    Trap.Fn.addFnAttr(Cold);
270
2.00k
    Trap.Fn.addFnAttr(NoInline);
271
272
2.00k
    LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage,
273
2.00k
                       LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion),
274
2.00k
                       "version");
275
276
2.00k
    if (!IsGenericBinary) {
277
2.00k
      SubtargetFeatures = LLVM::getHostCPUFeatures();
278
2.00k
      auto Features = SubtargetFeatures.string_view();
279
174k
      while (!Features.empty()) {
280
172k
        std::string_view Feature;
281
172k
        if (auto Pos = Features.find(','); Pos != std::string_view::npos) {
282
170k
          Feature = Features.substr(0, Pos);
283
170k
          Features = Features.substr(Pos + 1);
284
170k
        } else {
285
2.00k
          Feature = std::exchange(Features, std::string_view());
286
2.00k
        }
287
172k
        if (Feature[0] != '+') {
288
96.0k
          continue;
289
96.0k
        }
290
76.0k
        Feature = Feature.substr(1);
291
292
76.0k
#if defined(__x86_64__)
293
76.0k
        if (!SupportXOP && Feature == "xop"sv) {
294
0
          SupportXOP = true;
295
0
        }
296
76.0k
        if (!SupportSSE4_1 && Feature == "sse4.1"sv) {
297
2.00k
          SupportSSE4_1 = true;
298
2.00k
        }
299
76.0k
        if (!SupportSSSE3 && Feature == "ssse3"sv) {
300
2.00k
          SupportSSSE3 = true;
301
2.00k
        }
302
76.0k
        if (!SupportSSE2 && Feature == "sse2"sv) {
303
0
          SupportSSE2 = true;
304
0
        }
305
#elif defined(__aarch64__)
306
        if (!SupportNEON && Feature == "neon"sv) {
307
          SupportNEON = true;
308
        }
309
#endif
310
76.0k
      }
311
2.00k
    }
312
313
2.00k
    {
314
      // create trap
315
2.00k
      LLVM::Builder Builder(LLContext);
316
2.00k
      Builder.positionAtEnd(
317
2.00k
          LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry"));
318
2.00k
      auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
319
2.00k
      auto CallTrap = Builder.createCall(
320
2.00k
          getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy),
321
2.00k
          {Trap.Fn.getFirstParam()});
322
2.00k
      CallTrap.addCallSiteAttribute(NoReturn);
323
2.00k
      Builder.createUnreachable();
324
2.00k
    }
325
2.00k
  }
326
  LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ExecCtx,
327
23.6k
                        uint32_t Index) noexcept {
328
23.6k
    auto Array = Builder.createExtractValue(ExecCtx, 0);
329
#if WASMEDGE_ALLOCATOR_IS_STABLE
330
    auto VPtr = Builder.createLoad(
331
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
332
                                              LLContext.getInt64(Index)));
333
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
334
                     LLVM::Metadata(LLContext, {}));
335
#else
336
23.6k
    auto VPtrPtr = Builder.createLoad(
337
23.6k
        Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array,
338
23.6k
                                                 LLContext.getInt64(Index)));
339
23.6k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
340
23.6k
                        LLVM::Metadata(LLContext, {}));
341
23.6k
    auto VPtr = Builder.createLoad(
342
23.6k
        Int8PtrTy,
343
23.6k
        Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0)));
344
23.6k
#endif
345
23.6k
    return Builder.createBitCast(VPtr, Int8PtrTy);
346
23.6k
  }
347
  std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder,
348
                                               LLVM::Value ExecCtx,
349
332
                                               uint32_t Index) noexcept {
350
332
    auto Ty = Globals[Index];
351
332
    auto Array = Builder.createExtractValue(ExecCtx, 1);
352
332
    auto VPtr = Builder.createLoad(
353
332
        Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
354
332
                                                LLContext.getInt64(Index)));
355
332
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
356
332
                     LLVM::Metadata(LLContext, {}));
357
332
    auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo());
358
332
    return {Ty, Ptr};
359
332
  }
360
  LLVM::Value getInstrCount(LLVM::Builder &Builder,
361
0
                            LLVM::Value ExecCtx) noexcept {
362
0
    return Builder.createExtractValue(ExecCtx, 2);
363
0
  }
364
  LLVM::Value getCostTable(LLVM::Builder &Builder,
365
0
                           LLVM::Value ExecCtx) noexcept {
366
0
    return Builder.createExtractValue(ExecCtx, 3);
367
0
  }
368
0
  LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept {
369
0
    return Builder.createExtractValue(ExecCtx, 4);
370
0
  }
371
  LLVM::Value getGasLimit(LLVM::Builder &Builder,
372
0
                          LLVM::Value ExecCtx) noexcept {
373
0
    return Builder.createExtractValue(ExecCtx, 5);
374
0
  }
375
  LLVM::Value getStopToken(LLVM::Builder &Builder,
376
0
                           LLVM::Value ExecCtx) noexcept {
377
0
    return Builder.createExtractValue(ExecCtx, 6);
378
0
  }
379
  LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder,
380
                                    Executable::Intrinsics Index,
381
6.28k
                                    LLVM::Type Ty) noexcept {
382
6.28k
    const auto Value = static_cast<uint32_t>(Index);
383
6.28k
    auto PtrTy = Ty.getPointerTo();
384
6.28k
    auto PtrPtrTy = PtrTy.getPointerTo();
385
6.28k
    auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable);
386
6.28k
    IT.setMetadata(LLContext, LLVM::Core::InvariantGroup,
387
6.28k
                   LLVM::Metadata(LLContext, {}));
388
6.28k
    auto VPtr =
389
6.28k
        Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0),
390
6.28k
                                   LLContext.getInt64(Value));
391
6.28k
    auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy);
392
6.28k
    return {Ty, Builder.createLoad(PtrTy, Ptr)};
393
6.28k
  }
394
  std::pair<std::vector<ValType>, std::vector<ValType>>
395
18.5k
  resolveBlockType(const BlockType &BType) const noexcept {
396
18.5k
    using VecT = std::vector<ValType>;
397
18.5k
    using RetT = std::pair<VecT, VecT>;
398
18.5k
    if (BType.isEmpty()) {
399
2.11k
      return RetT{};
400
2.11k
    }
401
16.4k
    if (BType.isValType()) {
402
2.59k
      return RetT{{}, {BType.getValType()}};
403
13.8k
    } else {
404
      // Type index case. t2* = type[index].returns
405
13.8k
      const uint32_t TypeIdx = BType.getTypeIndex();
406
13.8k
      const auto &FType = CompositeTypes[TypeIdx]->getFuncType();
407
13.8k
      return RetT{
408
13.8k
          VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()),
409
13.8k
          VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())};
410
13.8k
    }
411
16.4k
  }
412
};
413
414
namespace {
415
416
using namespace WasmEdge;
417
418
34.2k
static bool isVoidReturn(Span<const ValType> ValTypes) noexcept {
419
34.2k
  return ValTypes.empty();
420
34.2k
}
421
422
static LLVM::Type toLLVMType(LLVM::Context LLContext,
423
2.66M
                             const ValType &ValType) noexcept {
424
2.66M
  switch (ValType.getCode()) {
425
276k
  case TypeCode::I32:
426
276k
    return LLContext.getInt32Ty();
427
444k
  case TypeCode::I64:
428
444k
    return LLContext.getInt64Ty();
429
0
  case TypeCode::Ref:
430
41.1k
  case TypeCode::RefNull:
431
1.87M
  case TypeCode::V128:
432
1.87M
    return LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2);
433
50.5k
  case TypeCode::F32:
434
50.5k
    return LLContext.getFloatTy();
435
20.3k
  case TypeCode::F64:
436
20.3k
    return LLContext.getDoubleTy();
437
0
  default:
438
0
    assumingUnreachable();
439
2.66M
  }
440
2.66M
}
441
442
static std::vector<LLVM::Type>
443
toLLVMTypeVector(LLVM::Context LLContext,
444
19.2k
                 Span<const ValType> ValTypes) noexcept {
445
19.2k
  std::vector<LLVM::Type> Result;
446
19.2k
  Result.reserve(ValTypes.size());
447
19.2k
  for (const auto &Type : ValTypes) {
448
18.3k
    Result.push_back(toLLVMType(LLContext, Type));
449
18.3k
  }
450
19.2k
  return Result;
451
19.2k
}
452
453
static std::vector<LLVM::Type>
454
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
455
15.6k
               Span<const ValType> ValTypes) noexcept {
456
15.6k
  auto Result = toLLVMTypeVector(LLContext, ValTypes);
457
15.6k
  Result.insert(Result.begin(), ExecCtxPtrTy);
458
15.6k
  return Result;
459
15.6k
}
460
461
static LLVM::Type toLLVMRetsType(LLVM::Context LLContext,
462
15.6k
                                 Span<const ValType> ValTypes) noexcept {
463
15.6k
  if (isVoidReturn(ValTypes)) {
464
3.62k
    return LLContext.getVoidTy();
465
3.62k
  }
466
12.0k
  if (ValTypes.size() == 1) {
467
11.3k
    return toLLVMType(LLContext, ValTypes.front());
468
11.3k
  }
469
634
  std::vector<LLVM::Type> Result;
470
634
  Result.reserve(ValTypes.size());
471
1.73k
  for (const auto &Type : ValTypes) {
472
1.73k
    Result.push_back(toLLVMType(LLContext, Type));
473
1.73k
  }
474
634
  return LLVM::Type::getStructType(Result);
475
12.0k
}
476
477
static LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
478
15.6k
                             const AST::FunctionType &FuncType) noexcept {
479
15.6k
  auto ArgsTy =
480
15.6k
      toLLVMArgsType(LLContext, ExecCtxPtrTy, FuncType.getParamTypes());
481
15.6k
  auto RetTy = toLLVMRetsType(LLContext, FuncType.getReturnTypes());
482
15.6k
  return LLVM::Type::getFunctionType(RetTy, ArgsTy);
483
15.6k
}
484
485
static LLVM::Value toLLVMConstantZero(LLVM::Context LLContext,
486
2.63M
                                      const ValType &ValType) noexcept {
487
2.63M
  switch (ValType.getCode()) {
488
259k
  case TypeCode::I32:
489
259k
    return LLVM::Value::getConstNull(LLContext.getInt32Ty());
490
441k
  case TypeCode::I64:
491
441k
    return LLVM::Value::getConstNull(LLContext.getInt64Ty());
492
0
  case TypeCode::Ref:
493
40.5k
  case TypeCode::RefNull: {
494
40.5k
    std::array<uint8_t, 16> Data{};
495
40.5k
    const auto Raw = ValType.getRawData();
496
40.5k
    std::copy(Raw.begin(), Raw.end(), Data.begin());
497
40.5k
    return LLVM::Value::getConstVector8(LLContext, Data);
498
0
  }
499
1.82M
  case TypeCode::V128:
500
1.82M
    return LLVM::Value::getConstNull(
501
1.82M
        LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2));
502
48.3k
  case TypeCode::F32:
503
48.3k
    return LLVM::Value::getConstNull(LLContext.getFloatTy());
504
17.7k
  case TypeCode::F64:
505
17.7k
    return LLVM::Value::getConstNull(LLContext.getDoubleTy());
506
0
  default:
507
0
    assumingUnreachable();
508
2.63M
  }
509
2.63M
}
510
511
class FunctionCompiler {
512
  struct Control;
513
514
public:
515
  FunctionCompiler(LLVM::Compiler::CompileContext &Context,
516
                   LLVM::FunctionCallee F, Span<const ValType> Locals,
517
                   bool Interruptible, bool InstructionCounting,
518
                   bool GasMeasuring) noexcept
519
10.7k
      : Context(Context), LLContext(Context.LLContext),
520
10.7k
        Interruptible(Interruptible), F(F), Builder(LLContext) {
521
10.7k
    if (F.Fn) {
522
10.7k
      Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "entry"));
523
10.7k
      ExecCtx = Builder.createLoad(Context.ExecCtxTy, F.Fn.getFirstParam());
524
525
10.7k
      if (InstructionCounting) {
526
0
        LocalInstrCount = Builder.createAlloca(Context.Int64Ty);
527
0
        Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
528
0
      }
529
530
10.7k
      if (GasMeasuring) {
531
0
        LocalGas = Builder.createAlloca(Context.Int64Ty);
532
0
        Builder.createStore(LLContext.getInt64(0), LocalGas);
533
0
      }
534
535
20.0k
      for (LLVM::Value Arg = F.Fn.getFirstParam().getNextParam(); Arg;
536
10.7k
           Arg = Arg.getNextParam()) {
537
9.28k
        LLVM::Type Ty = Arg.getType();
538
9.28k
        LLVM::Value ArgPtr = Builder.createAlloca(Ty);
539
9.28k
        Builder.createStore(Arg, ArgPtr);
540
9.28k
        Local.emplace_back(Ty, ArgPtr);
541
9.28k
      }
542
543
2.63M
      for (const auto &Type : Locals) {
544
2.63M
        LLVM::Type Ty = toLLVMType(LLContext, Type);
545
2.63M
        LLVM::Value ArgPtr = Builder.createAlloca(Ty);
546
2.63M
        Builder.createStore(toLLVMConstantZero(LLContext, Type), ArgPtr);
547
2.63M
        Local.emplace_back(Ty, ArgPtr);
548
2.63M
      }
549
10.7k
    }
550
10.7k
  }
551
552
32.7k
  LLVM::BasicBlock getTrapBB(ErrCode::Value Error) noexcept {
553
32.7k
    if (auto Iter = TrapBB.find(Error); Iter != TrapBB.end()) {
554
29.8k
      return Iter->second;
555
29.8k
    }
556
2.87k
    auto BB = LLVM::BasicBlock::create(LLContext, F.Fn, "trap");
557
2.87k
    TrapBB.emplace(Error, BB);
558
2.87k
    return BB;
559
32.7k
  }
560
561
  void
562
  compile(const AST::CodeSegment &Code,
563
10.7k
          std::pair<std::vector<ValType>, std::vector<ValType>> Type) noexcept {
564
10.7k
    auto RetBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ret");
565
10.7k
    Type.first.clear();
566
10.7k
    enterBlock(RetBB, {}, {}, {}, std::move(Type));
567
10.7k
    compile(Code.getExpr().getInstrs());
568
10.7k
    assuming(ControlStack.empty());
569
10.7k
    compileReturn();
570
571
10.7k
    for (auto &[Error, BB] : TrapBB) {
572
2.87k
      Builder.positionAtEnd(BB);
573
2.87k
      updateInstrCount();
574
2.87k
      updateGasAtTrap();
575
2.87k
      auto CallTrap = Builder.createCall(
576
2.87k
          Context.Trap, {LLContext.getInt32(static_cast<uint32_t>(Error))});
577
2.87k
      CallTrap.addCallSiteAttribute(Context.NoReturn);
578
2.87k
      Builder.createUnreachable();
579
2.87k
    }
580
10.7k
  }
581
582
10.7k
  void compile(AST::InstrView Instrs) noexcept {
583
1.56M
    auto Dispatch = [this](const AST::Instruction &Instr) -> void {
584
1.56M
      switch (Instr.getOpCode()) {
585
      // Control instructions (for blocks)
586
3.57k
      case OpCode::Block: {
587
3.57k
        auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "block");
588
3.57k
        auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "block.end");
589
3.57k
        Builder.createBr(Block);
590
591
3.57k
        Builder.positionAtEnd(Block);
592
3.57k
        auto Type = Context.resolveBlockType(Instr.getBlockType());
593
3.57k
        const auto Arity = Type.first.size();
594
3.57k
        std::vector<LLVM::Value> Args(Arity);
595
3.57k
        if (isUnreachable()) {
596
897
          for (size_t I = 0; I < Arity; ++I) {
597
299
            auto Ty = toLLVMType(LLContext, Type.first[I]);
598
299
            Args[I] = LLVM::Value::getUndef(Ty);
599
299
          }
600
2.97k
        } else {
601
3.50k
          for (size_t I = 0; I < Arity; ++I) {
602
527
            const size_t J = Arity - 1 - I;
603
527
            Args[J] = stackPop();
604
527
          }
605
2.97k
        }
606
3.57k
        enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
607
3.57k
        checkStop();
608
3.57k
        updateGas();
609
3.57k
        return;
610
0
      }
611
1.54k
      case OpCode::Loop: {
612
1.54k
        auto Curr = Builder.getInsertBlock();
613
1.54k
        auto Loop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop");
614
1.54k
        auto EndLoop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop.end");
615
1.54k
        Builder.createBr(Loop);
616
617
1.54k
        Builder.positionAtEnd(Loop);
618
1.54k
        auto Type = Context.resolveBlockType(Instr.getBlockType());
619
1.54k
        const auto Arity = Type.first.size();
620
1.54k
        std::vector<LLVM::Value> Args(Arity);
621
1.54k
        if (isUnreachable()) {
622
806
          for (size_t I = 0; I < Arity; ++I) {
623
327
            auto Ty = toLLVMType(LLContext, Type.first[I]);
624
327
            auto Value = LLVM::Value::getUndef(Ty);
625
327
            auto PHINode = Builder.createPHI(Ty);
626
327
            PHINode.addIncoming(Value, Curr);
627
327
            Args[I] = PHINode;
628
327
          }
629
1.06k
        } else {
630
1.57k
          for (size_t I = 0; I < Arity; ++I) {
631
509
            const size_t J = Arity - 1 - I;
632
509
            auto Value = stackPop();
633
509
            auto PHINode = Builder.createPHI(Value.getType());
634
509
            PHINode.addIncoming(Value, Curr);
635
509
            Args[J] = PHINode;
636
509
          }
637
1.06k
        }
638
1.54k
        enterBlock(Loop, EndLoop, {}, std::move(Args), std::move(Type));
639
1.54k
        checkStop();
640
1.54k
        updateGas();
641
1.54k
        return;
642
0
      }
643
2.68k
      case OpCode::If: {
644
2.68k
        auto Then = LLVM::BasicBlock::create(LLContext, F.Fn, "then");
645
2.68k
        auto Else = LLVM::BasicBlock::create(LLContext, F.Fn, "else");
646
2.68k
        auto EndIf = LLVM::BasicBlock::create(LLContext, F.Fn, "if.end");
647
2.68k
        LLVM::Value Cond;
648
2.68k
        if (isUnreachable()) {
649
589
          Cond = LLVM::Value::getUndef(LLContext.getInt1Ty());
650
2.09k
        } else {
651
2.09k
          Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
652
2.09k
        }
653
2.68k
        Builder.createCondBr(Cond, Then, Else);
654
655
2.68k
        Builder.positionAtEnd(Then);
656
2.68k
        auto Type = Context.resolveBlockType(Instr.getBlockType());
657
2.68k
        const auto Arity = Type.first.size();
658
2.68k
        std::vector<LLVM::Value> Args(Arity);
659
2.68k
        if (isUnreachable()) {
660
1.19k
          for (size_t I = 0; I < Arity; ++I) {
661
607
            auto Ty = toLLVMType(LLContext, Type.first[I]);
662
607
            Args[I] = LLVM::Value::getUndef(Ty);
663
607
          }
664
2.09k
        } else {
665
2.89k
          for (size_t I = 0; I < Arity; ++I) {
666
801
            const size_t J = Arity - 1 - I;
667
801
            Args[J] = stackPop();
668
801
          }
669
2.09k
        }
670
2.68k
        enterBlock(EndIf, {}, Else, std::move(Args), std::move(Type));
671
2.68k
        return;
672
0
      }
673
18.5k
      case OpCode::End: {
674
18.5k
        auto Entry = leaveBlock();
675
18.5k
        if (Entry.ElseBlock) {
676
949
          auto Block = Builder.getInsertBlock();
677
949
          Builder.positionAtEnd(Entry.ElseBlock);
678
949
          enterBlock(Block, {}, {}, std::move(Entry.Args),
679
949
                     std::move(Entry.Type), std::move(Entry.ReturnPHI));
680
949
          Entry = leaveBlock();
681
949
        }
682
18.5k
        buildPHI(Entry.Type.second, Entry.ReturnPHI);
683
18.5k
        return;
684
0
      }
685
1.73k
      case OpCode::Else: {
686
1.73k
        auto Entry = leaveBlock();
687
1.73k
        Builder.positionAtEnd(Entry.ElseBlock);
688
1.73k
        enterBlock(Entry.JumpBlock, {}, {}, std::move(Entry.Args),
689
1.73k
                   std::move(Entry.Type), std::move(Entry.ReturnPHI));
690
1.73k
        return;
691
0
      }
692
1.54M
      default:
693
1.54M
        break;
694
1.56M
      }
695
696
1.54M
      if (isUnreachable()) {
697
441k
        return;
698
441k
      }
699
700
1.10M
      switch (Instr.getOpCode()) {
701
      // Control instructions
702
3.22k
      case OpCode::Unreachable:
703
3.22k
        Builder.createBr(getTrapBB(ErrCode::Value::Unreachable));
704
3.22k
        setUnreachable();
705
3.22k
        Builder.positionAtEnd(
706
3.22k
            LLVM::BasicBlock::create(LLContext, F.Fn, "unreachable.end"));
707
3.22k
        break;
708
41.2k
      case OpCode::Nop:
709
41.2k
        break;
710
      // LEGACY-EH: remove the `Try` cases after deprecating legacy EH.
711
      // case OpCode::Try:
712
      // case OpCode::Throw:
713
      // case OpCode::Throw_ref:
714
740
      case OpCode::Br: {
715
740
        const auto Label = Instr.getJump().TargetIndex;
716
740
        setLableJumpPHI(Label);
717
740
        Builder.createBr(getLabel(Label));
718
740
        setUnreachable();
719
740
        Builder.positionAtEnd(
720
740
            LLVM::BasicBlock::create(LLContext, F.Fn, "br.end"));
721
740
        break;
722
0
      }
723
351
      case OpCode::Br_if: {
724
351
        const auto Label = Instr.getJump().TargetIndex;
725
351
        auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
726
351
        setLableJumpPHI(Label);
727
351
        auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_if.end");
728
351
        Builder.createCondBr(Cond, getLabel(Label), Next);
729
351
        Builder.positionAtEnd(Next);
730
351
        break;
731
0
      }
732
977
      case OpCode::Br_table: {
733
977
        auto LabelTable = Instr.getLabelList();
734
977
        assuming(LabelTable.size() <= std::numeric_limits<uint32_t>::max());
735
977
        const auto LabelTableSize =
736
977
            static_cast<uint32_t>(LabelTable.size() - 1);
737
977
        auto Value = stackPop();
738
977
        setLableJumpPHI(LabelTable[LabelTableSize].TargetIndex);
739
977
        auto Switch = Builder.createSwitch(
740
977
            Value, getLabel(LabelTable[LabelTableSize].TargetIndex),
741
977
            LabelTableSize);
742
36.6k
        for (uint32_t I = 0; I < LabelTableSize; ++I) {
743
35.7k
          setLableJumpPHI(LabelTable[I].TargetIndex);
744
35.7k
          Switch.addCase(LLContext.getInt32(I),
745
35.7k
                         getLabel(LabelTable[I].TargetIndex));
746
35.7k
        }
747
977
        setUnreachable();
748
977
        Builder.positionAtEnd(
749
977
            LLVM::BasicBlock::create(LLContext, F.Fn, "br_table.end"));
750
977
        break;
751
977
      }
752
0
      case OpCode::Br_on_null: {
753
0
        const auto Label = Instr.getJump().TargetIndex;
754
0
        auto Value = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
755
0
        auto Cond = Builder.createICmpEQ(
756
0
            Builder.createExtractElement(Value, LLContext.getInt64(1)),
757
0
            LLContext.getInt64(0));
758
0
        setLableJumpPHI(Label);
759
0
        auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_null.end");
760
0
        Builder.createCondBr(Cond, getLabel(Label), Next);
761
0
        Builder.positionAtEnd(Next);
762
0
        stackPush(Value);
763
0
        break;
764
977
      }
765
0
      case OpCode::Br_on_non_null: {
766
0
        const auto Label = Instr.getJump().TargetIndex;
767
0
        auto Cond = Builder.createICmpNE(
768
0
            Builder.createExtractElement(
769
0
                Builder.createBitCast(Stack.back(), Context.Int64x2Ty),
770
0
                LLContext.getInt64(1)),
771
0
            LLContext.getInt64(0));
772
0
        setLableJumpPHI(Label);
773
0
        auto Next =
774
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_non_null.end");
775
0
        Builder.createCondBr(Cond, getLabel(Label), Next);
776
0
        Builder.positionAtEnd(Next);
777
0
        stackPop();
778
0
        break;
779
977
      }
780
0
      case OpCode::Br_on_cast:
781
0
      case OpCode::Br_on_cast_fail: {
782
0
        auto Ref = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
783
0
        const auto Label = Instr.getBrCast().Jump.TargetIndex;
784
0
        std::array<uint8_t, 16> Buf = {0};
785
0
        std::copy_n(Instr.getBrCast().RType2.getRawData().cbegin(), 8,
786
0
                    Buf.begin());
787
0
        auto VType = Builder.createExtractElement(
788
0
            Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
789
0
                                  Context.Int64x2Ty),
790
0
            LLContext.getInt64(0));
791
0
        auto IsRefTest = Builder.createCall(
792
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kRefTest,
793
0
                                 LLVM::Type::getFunctionType(
794
0
                                     Context.Int32Ty,
795
0
                                     {Context.Int64x2Ty, Context.Int64Ty},
796
0
                                     false)),
797
0
            {Ref, VType});
798
0
        auto Cond =
799
0
            (Instr.getOpCode() == OpCode::Br_on_cast)
800
0
                ? Builder.createICmpNE(IsRefTest, LLContext.getInt32(0))
801
0
                : Builder.createICmpEQ(IsRefTest, LLContext.getInt32(0));
802
0
        setLableJumpPHI(Label);
803
0
        auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_cast.end");
804
0
        Builder.createCondBr(Cond, getLabel(Label), Next);
805
0
        Builder.positionAtEnd(Next);
806
0
        break;
807
0
      }
808
698
      case OpCode::Return:
809
698
        compileReturn();
810
698
        setUnreachable();
811
698
        Builder.positionAtEnd(
812
698
            LLVM::BasicBlock::create(LLContext, F.Fn, "ret.end"));
813
698
        break;
814
3.38k
      case OpCode::Call:
815
3.38k
        updateInstrCount();
816
3.38k
        updateGas();
817
3.38k
        compileCallOp(Instr.getTargetIndex());
818
3.38k
        break;
819
713
      case OpCode::Call_indirect:
820
713
        updateInstrCount();
821
713
        updateGas();
822
713
        compileIndirectCallOp(Instr.getSourceIndex(), Instr.getTargetIndex());
823
713
        break;
824
0
      case OpCode::Return_call:
825
0
        updateInstrCount();
826
0
        updateGas();
827
0
        compileReturnCallOp(Instr.getTargetIndex());
828
0
        setUnreachable();
829
0
        Builder.positionAtEnd(
830
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call.end"));
831
0
        break;
832
0
      case OpCode::Return_call_indirect:
833
0
        updateInstrCount();
834
0
        updateGas();
835
0
        compileReturnIndirectCallOp(Instr.getSourceIndex(),
836
0
                                    Instr.getTargetIndex());
837
0
        setUnreachable();
838
0
        Builder.positionAtEnd(
839
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_indir.end"));
840
0
        break;
841
0
      case OpCode::Call_ref:
842
0
        updateInstrCount();
843
0
        updateGas();
844
0
        compileCallRefOp(Instr.getTargetIndex());
845
0
        break;
846
0
      case OpCode::Return_call_ref:
847
0
        updateInstrCount();
848
0
        updateGas();
849
0
        compileReturnCallRefOp(Instr.getTargetIndex());
850
0
        setUnreachable();
851
0
        Builder.positionAtEnd(
852
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_ref.end"));
853
0
        break;
854
        // LEGACY-EH: remove the `Catch` cases after deprecating legacy EH.
855
        // case OpCode::Catch:
856
        // case OpCode::Catch_all:
857
        // case OpCode::Try_table:
858
859
      // Reference Instructions
860
1.19k
      case OpCode::Ref__null: {
861
1.19k
        std::array<uint8_t, 16> Buf = {0};
862
        // For null references, the dynamic type down scaling is needed.
863
1.19k
        ValType VType;
864
1.19k
        if (Instr.getValType().isAbsHeapType()) {
865
1.19k
          switch (Instr.getValType().getHeapTypeCode()) {
866
0
          case TypeCode::NullFuncRef:
867
492
          case TypeCode::FuncRef:
868
492
            VType = TypeCode::NullFuncRef;
869
492
            break;
870
0
          case TypeCode::NullExternRef:
871
707
          case TypeCode::ExternRef:
872
707
            VType = TypeCode::NullExternRef;
873
707
            break;
874
0
          case TypeCode::NullRef:
875
0
          case TypeCode::AnyRef:
876
0
          case TypeCode::EqRef:
877
0
          case TypeCode::I31Ref:
878
0
          case TypeCode::StructRef:
879
0
          case TypeCode::ArrayRef:
880
0
            VType = TypeCode::NullRef;
881
0
            break;
882
0
          default:
883
0
            assumingUnreachable();
884
1.19k
          }
885
1.19k
        } else {
886
0
          assuming(Instr.getValType().getTypeIndex() <
887
0
                   Context.CompositeTypes.size());
888
0
          const auto *CompType =
889
0
              Context.CompositeTypes[Instr.getValType().getTypeIndex()];
890
0
          assuming(CompType != nullptr);
891
0
          if (CompType->isFunc()) {
892
0
            VType = TypeCode::NullFuncRef;
893
0
          } else {
894
0
            VType = TypeCode::NullRef;
895
0
          }
896
0
        }
897
1.19k
        std::copy_n(VType.getRawData().cbegin(), 8, Buf.begin());
898
1.19k
        stackPush(Builder.createBitCast(
899
1.19k
            LLVM::Value::getConstVector8(LLContext, Buf), Context.Int64x2Ty));
900
1.19k
        break;
901
1.19k
      }
902
573
      case OpCode::Ref__is_null:
903
573
        stackPush(Builder.createZExt(
904
573
            Builder.createICmpEQ(
905
573
                Builder.createExtractElement(
906
573
                    Builder.createBitCast(stackPop(), Context.Int64x2Ty),
907
573
                    LLContext.getInt64(1)),
908
573
                LLContext.getInt64(0)),
909
573
            Context.Int32Ty));
910
573
        break;
911
27
      case OpCode::Ref__func:
912
27
        stackPush(Builder.createCall(
913
27
            Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc,
914
27
                                 LLVM::Type::getFunctionType(Context.Int64x2Ty,
915
27
                                                             {Context.Int32Ty},
916
27
                                                             false)),
917
27
            {LLContext.getInt32(Instr.getTargetIndex())}));
918
27
        break;
919
0
      case OpCode::Ref__eq: {
920
0
        LLVM::Value RHS = stackPop();
921
0
        LLVM::Value LHS = stackPop();
922
0
        stackPush(Builder.createZExt(
923
0
            Builder.createICmpEQ(
924
0
                Builder.createExtractElement(LHS, LLContext.getInt64(1)),
925
0
                Builder.createExtractElement(RHS, LLContext.getInt64(1))),
926
0
            Context.Int32Ty));
927
0
        break;
928
1.19k
      }
929
0
      case OpCode::Ref__as_non_null: {
930
0
        auto Next =
931
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "ref_as_non_null.ok");
932
0
        Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
933
0
        auto IsNotNull = Builder.createLikely(Builder.createICmpNE(
934
0
            Builder.createExtractElement(Stack.back(), LLContext.getInt64(1)),
935
0
            LLContext.getInt64(0)));
936
0
        Builder.createCondBr(IsNotNull, Next,
937
0
                             getTrapBB(ErrCode::Value::CastNullToNonNull));
938
0
        Builder.positionAtEnd(Next);
939
0
        break;
940
1.19k
      }
941
942
      // Reference Instructions (GC proposal)
943
0
      case OpCode::Struct__new:
944
0
      case OpCode::Struct__new_default: {
945
0
        LLVM::Value Args = LLVM::Value::getConstPointerNull(Context.Int8PtrTy);
946
0
        assuming(Instr.getTargetIndex() < Context.CompositeTypes.size());
947
0
        const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
948
0
        assuming(CompType != nullptr && !CompType->isFunc());
949
0
        auto ArgSize = CompType->getFieldTypes().size();
950
0
        if (Instr.getOpCode() == OpCode::Struct__new) {
951
0
          std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
952
0
          for (size_t I = 0; I < ArgSize; ++I) {
953
0
            ArgsVec[ArgSize - I - 1] = stackPop();
954
0
          }
955
0
          Args = Builder.createArray(ArgSize, kValSize);
956
0
          Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, kValSize);
957
0
        } else {
958
0
          ArgSize = 0;
959
0
        }
960
0
        stackPush(Builder.createCall(
961
0
            Context.getIntrinsic(
962
0
                Builder, Executable::Intrinsics::kStructNew,
963
0
                LLVM::Type::getFunctionType(
964
0
                    Context.Int64x2Ty,
965
0
                    {Context.Int32Ty, Context.Int8PtrTy, Context.Int32Ty},
966
0
                    false)),
967
0
            {LLContext.getInt32(Instr.getTargetIndex()), Args,
968
0
             LLContext.getInt32(static_cast<uint32_t>(ArgSize))}));
969
0
        break;
970
0
      }
971
0
      case OpCode::Struct__get:
972
0
      case OpCode::Struct__get_u:
973
0
      case OpCode::Struct__get_s: {
974
0
        assuming(static_cast<size_t>(Instr.getTargetIndex()) <
975
0
                 Context.CompositeTypes.size());
976
0
        const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
977
0
        assuming(CompType != nullptr && !CompType->isFunc());
978
0
        assuming(static_cast<size_t>(Instr.getSourceIndex()) <
979
0
                 CompType->getFieldTypes().size());
980
0
        const auto &StorageType =
981
0
            CompType->getFieldTypes()[Instr.getSourceIndex()].getStorageType();
982
0
        auto Ref = stackPop();
983
0
        auto IsSigned = (Instr.getOpCode() == OpCode::Struct__get_s)
984
0
                            ? LLContext.getInt8(1)
985
0
                            : LLContext.getInt8(0);
986
0
        LLVM::Value Ret = Builder.createAlloca(Context.Int64x2Ty);
987
0
        Builder.createCall(
988
0
            Context.getIntrinsic(
989
0
                Builder, Executable::Intrinsics::kStructGet,
990
0
                LLVM::Type::getFunctionType(Context.VoidTy,
991
0
                                            {Context.Int64x2Ty, Context.Int32Ty,
992
0
                                             Context.Int32Ty, Context.Int8Ty,
993
0
                                             Context.Int8PtrTy},
994
0
                                            false)),
995
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()),
996
0
             LLContext.getInt32(Instr.getSourceIndex()), IsSigned, Ret});
997
998
0
        switch (StorageType.getCode()) {
999
0
        case TypeCode::I8:
1000
0
        case TypeCode::I16:
1001
0
        case TypeCode::I32: {
1002
0
          stackPush(Builder.createValuePtrLoad(Context.Int32Ty, Ret,
1003
0
                                               Context.Int64x2Ty));
1004
0
          break;
1005
0
        }
1006
0
        case TypeCode::I64: {
1007
0
          stackPush(Builder.createValuePtrLoad(Context.Int64Ty, Ret,
1008
0
                                               Context.Int64x2Ty));
1009
0
          break;
1010
0
        }
1011
0
        case TypeCode::F32: {
1012
0
          stackPush(Builder.createValuePtrLoad(Context.FloatTy, Ret,
1013
0
                                               Context.Int64x2Ty));
1014
0
          break;
1015
0
        }
1016
0
        case TypeCode::F64: {
1017
0
          stackPush(Builder.createValuePtrLoad(Context.DoubleTy, Ret,
1018
0
                                               Context.Int64x2Ty));
1019
0
          break;
1020
0
        }
1021
0
        case TypeCode::V128:
1022
0
        case TypeCode::Ref:
1023
0
        case TypeCode::RefNull: {
1024
0
          stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret,
1025
0
                                               Context.Int64x2Ty));
1026
0
          break;
1027
0
        }
1028
0
        default:
1029
0
          assumingUnreachable();
1030
0
        }
1031
0
        break;
1032
0
      }
1033
0
      case OpCode::Struct__set: {
1034
0
        auto Val = stackPop();
1035
0
        auto Ref = stackPop();
1036
0
        LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty);
1037
0
        Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
1038
0
        Builder.createCall(
1039
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kStructSet,
1040
0
                                 LLVM::Type::getFunctionType(
1041
0
                                     Context.VoidTy,
1042
0
                                     {Context.Int64x2Ty, Context.Int32Ty,
1043
0
                                      Context.Int32Ty, Context.Int8PtrTy},
1044
0
                                     false)),
1045
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()),
1046
0
             LLContext.getInt32(Instr.getSourceIndex()), Arg});
1047
0
        break;
1048
0
      }
1049
0
      case OpCode::Array__new: {
1050
0
        auto Length = stackPop();
1051
0
        auto Val = stackPop();
1052
0
        LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty);
1053
0
        Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
1054
0
        stackPush(Builder.createCall(
1055
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kArrayNew,
1056
0
                                 LLVM::Type::getFunctionType(
1057
0
                                     Context.Int64x2Ty,
1058
0
                                     {Context.Int32Ty, Context.Int32Ty,
1059
0
                                      Context.Int8PtrTy, Context.Int32Ty},
1060
0
                                     false)),
1061
0
            {LLContext.getInt32(Instr.getTargetIndex()), Length, Arg,
1062
0
             LLContext.getInt32(1)}));
1063
0
        break;
1064
0
      }
1065
0
      case OpCode::Array__new_default: {
1066
0
        auto Length = stackPop();
1067
0
        LLVM::Value Arg = LLVM::Value::getConstPointerNull(Context.Int8PtrTy);
1068
0
        stackPush(Builder.createCall(
1069
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kArrayNew,
1070
0
                                 LLVM::Type::getFunctionType(
1071
0
                                     Context.Int64x2Ty,
1072
0
                                     {Context.Int32Ty, Context.Int32Ty,
1073
0
                                      Context.Int8PtrTy, Context.Int32Ty},
1074
0
                                     false)),
1075
0
            {LLContext.getInt32(Instr.getTargetIndex()), Length, Arg,
1076
0
             LLContext.getInt32(0)}));
1077
0
        break;
1078
0
      }
1079
0
      case OpCode::Array__new_fixed: {
1080
0
        const auto ArgSize = Instr.getSourceIndex();
1081
0
        std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
1082
0
        for (size_t I = 0; I < ArgSize; ++I) {
1083
0
          ArgsVec[ArgSize - I - 1] = stackPop();
1084
0
        }
1085
0
        LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
1086
0
        Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, kValSize);
1087
0
        stackPush(Builder.createCall(
1088
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kArrayNew,
1089
0
                                 LLVM::Type::getFunctionType(
1090
0
                                     Context.Int64x2Ty,
1091
0
                                     {Context.Int32Ty, Context.Int32Ty,
1092
0
                                      Context.Int8PtrTy, Context.Int32Ty},
1093
0
                                     false)),
1094
0
            {LLContext.getInt32(Instr.getTargetIndex()),
1095
0
             LLContext.getInt32(ArgSize), Args, LLContext.getInt32(ArgSize)}));
1096
0
        break;
1097
0
      }
1098
0
      case OpCode::Array__new_data:
1099
0
      case OpCode::Array__new_elem: {
1100
0
        auto Length = stackPop();
1101
0
        auto Start = stackPop();
1102
0
        stackPush(Builder.createCall(
1103
0
            Context.getIntrinsic(
1104
0
                Builder,
1105
0
                ((Instr.getOpCode() == OpCode::Array__new_data)
1106
0
                     ? Executable::Intrinsics::kArrayNewData
1107
0
                     : Executable::Intrinsics::kArrayNewElem),
1108
0
                LLVM::Type::getFunctionType(Context.Int64x2Ty,
1109
0
                                            {Context.Int32Ty, Context.Int32Ty,
1110
0
                                             Context.Int32Ty, Context.Int32Ty},
1111
0
                                            false)),
1112
0
            {LLContext.getInt32(Instr.getTargetIndex()),
1113
0
             LLContext.getInt32(Instr.getSourceIndex()), Start, Length}));
1114
0
        break;
1115
0
      }
1116
0
      case OpCode::Array__get:
1117
0
      case OpCode::Array__get_u:
1118
0
      case OpCode::Array__get_s: {
1119
0
        assuming(static_cast<size_t>(Instr.getTargetIndex()) <
1120
0
                 Context.CompositeTypes.size());
1121
0
        const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
1122
0
        assuming(CompType != nullptr && !CompType->isFunc());
1123
0
        assuming(static_cast<size_t>(1) == CompType->getFieldTypes().size());
1124
0
        const auto &StorageType = CompType->getFieldTypes()[0].getStorageType();
1125
0
        auto Idx = stackPop();
1126
0
        auto Ref = stackPop();
1127
0
        auto IsSigned = (Instr.getOpCode() == OpCode::Array__get_s)
1128
0
                            ? LLContext.getInt8(1)
1129
0
                            : LLContext.getInt8(0);
1130
0
        LLVM::Value Ret = Builder.createAlloca(Context.Int64x2Ty);
1131
0
        Builder.createCall(
1132
0
            Context.getIntrinsic(
1133
0
                Builder, Executable::Intrinsics::kArrayGet,
1134
0
                LLVM::Type::getFunctionType(Context.VoidTy,
1135
0
                                            {Context.Int64x2Ty, Context.Int32Ty,
1136
0
                                             Context.Int32Ty, Context.Int8Ty,
1137
0
                                             Context.Int8PtrTy},
1138
0
                                            false)),
1139
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()), Idx, IsSigned,
1140
0
             Ret});
1141
1142
0
        switch (StorageType.getCode()) {
1143
0
        case TypeCode::I8:
1144
0
        case TypeCode::I16:
1145
0
        case TypeCode::I32: {
1146
0
          stackPush(Builder.createValuePtrLoad(Context.Int32Ty, Ret,
1147
0
                                               Context.Int64x2Ty));
1148
0
          break;
1149
0
        }
1150
0
        case TypeCode::I64: {
1151
0
          stackPush(Builder.createValuePtrLoad(Context.Int64Ty, Ret,
1152
0
                                               Context.Int64x2Ty));
1153
0
          break;
1154
0
        }
1155
0
        case TypeCode::F32: {
1156
0
          stackPush(Builder.createValuePtrLoad(Context.FloatTy, Ret,
1157
0
                                               Context.Int64x2Ty));
1158
0
          break;
1159
0
        }
1160
0
        case TypeCode::F64: {
1161
0
          stackPush(Builder.createValuePtrLoad(Context.DoubleTy, Ret,
1162
0
                                               Context.Int64x2Ty));
1163
0
          break;
1164
0
        }
1165
0
        case TypeCode::V128:
1166
0
        case TypeCode::Ref:
1167
0
        case TypeCode::RefNull: {
1168
0
          stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret,
1169
0
                                               Context.Int64x2Ty));
1170
0
          break;
1171
0
        }
1172
0
        default:
1173
0
          assumingUnreachable();
1174
0
        }
1175
0
        break;
1176
0
      }
1177
0
      case OpCode::Array__set: {
1178
0
        auto Val = stackPop();
1179
0
        auto Idx = stackPop();
1180
0
        auto Ref = stackPop();
1181
0
        LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty);
1182
0
        Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
1183
0
        Builder.createCall(
1184
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kArraySet,
1185
0
                                 LLVM::Type::getFunctionType(
1186
0
                                     Context.VoidTy,
1187
0
                                     {Context.Int64x2Ty, Context.Int32Ty,
1188
0
                                      Context.Int32Ty, Context.Int8PtrTy},
1189
0
                                     false)),
1190
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()), Idx, Arg});
1191
0
        break;
1192
0
      }
1193
0
      case OpCode::Array__len: {
1194
0
        auto Ref = stackPop();
1195
0
        stackPush(Builder.createCall(
1196
0
            Context.getIntrinsic(
1197
0
                Builder, Executable::Intrinsics::kArrayLen,
1198
0
                LLVM::Type::getFunctionType(Context.Int32Ty,
1199
0
                                            {Context.Int64x2Ty}, false)),
1200
0
            {Ref}));
1201
0
        break;
1202
0
      }
1203
0
      case OpCode::Array__fill: {
1204
0
        auto Cnt = stackPop();
1205
0
        auto Val = stackPop();
1206
0
        auto Off = stackPop();
1207
0
        auto Ref = stackPop();
1208
0
        LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty);
1209
0
        Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
1210
0
        Builder.createCall(
1211
0
            Context.getIntrinsic(
1212
0
                Builder, Executable::Intrinsics::kArrayFill,
1213
0
                LLVM::Type::getFunctionType(Context.VoidTy,
1214
0
                                            {Context.Int64x2Ty, Context.Int32Ty,
1215
0
                                             Context.Int32Ty, Context.Int32Ty,
1216
0
                                             Context.Int8PtrTy},
1217
0
                                            false)),
1218
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()), Off, Cnt, Arg});
1219
0
        break;
1220
0
      }
1221
0
      case OpCode::Array__copy: {
1222
0
        auto Cnt = stackPop();
1223
0
        auto SrcOff = stackPop();
1224
0
        auto SrcRef = stackPop();
1225
0
        auto DstOff = stackPop();
1226
0
        auto DstRef = stackPop();
1227
0
        Builder.createCall(
1228
0
            Context.getIntrinsic(
1229
0
                Builder, Executable::Intrinsics::kArrayCopy,
1230
0
                LLVM::Type::getFunctionType(Context.VoidTy,
1231
0
                                            {Context.Int64x2Ty, Context.Int32Ty,
1232
0
                                             Context.Int32Ty, Context.Int64x2Ty,
1233
0
                                             Context.Int32Ty, Context.Int32Ty,
1234
0
                                             Context.Int32Ty},
1235
0
                                            false)),
1236
0
            {DstRef, LLContext.getInt32(Instr.getTargetIndex()), DstOff, SrcRef,
1237
0
             LLContext.getInt32(Instr.getSourceIndex()), SrcOff, Cnt});
1238
0
        break;
1239
0
      }
1240
0
      case OpCode::Array__init_data:
1241
0
      case OpCode::Array__init_elem: {
1242
0
        auto Cnt = stackPop();
1243
0
        auto SrcOff = stackPop();
1244
0
        auto DstOff = stackPop();
1245
0
        auto Ref = stackPop();
1246
0
        Builder.createCall(
1247
0
            Context.getIntrinsic(
1248
0
                Builder,
1249
0
                ((Instr.getOpCode() == OpCode::Array__init_data)
1250
0
                     ? Executable::Intrinsics::kArrayInitData
1251
0
                     : Executable::Intrinsics::kArrayInitElem),
1252
0
                LLVM::Type::getFunctionType(Context.VoidTy,
1253
0
                                            {Context.Int64x2Ty, Context.Int32Ty,
1254
0
                                             Context.Int32Ty, Context.Int32Ty,
1255
0
                                             Context.Int32Ty, Context.Int32Ty},
1256
0
                                            false)),
1257
0
            {Ref, LLContext.getInt32(Instr.getTargetIndex()),
1258
0
             LLContext.getInt32(Instr.getSourceIndex()), DstOff, SrcOff, Cnt});
1259
0
        break;
1260
0
      }
1261
0
      case OpCode::Ref__test:
1262
0
      case OpCode::Ref__test_null: {
1263
0
        auto Ref = stackPop();
1264
0
        std::array<uint8_t, 16> Buf = {0};
1265
0
        std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
1266
0
        auto VType = Builder.createExtractElement(
1267
0
            Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
1268
0
                                  Context.Int64x2Ty),
1269
0
            LLContext.getInt64(0));
1270
0
        stackPush(Builder.createCall(
1271
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kRefTest,
1272
0
                                 LLVM::Type::getFunctionType(
1273
0
                                     Context.Int32Ty,
1274
0
                                     {Context.Int64x2Ty, Context.Int64Ty},
1275
0
                                     false)),
1276
0
            {Ref, VType}));
1277
0
        break;
1278
0
      }
1279
0
      case OpCode::Ref__cast:
1280
0
      case OpCode::Ref__cast_null: {
1281
0
        auto Ref = stackPop();
1282
0
        std::array<uint8_t, 16> Buf = {0};
1283
0
        std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
1284
0
        auto VType = Builder.createExtractElement(
1285
0
            Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
1286
0
                                  Context.Int64x2Ty),
1287
0
            LLContext.getInt64(0));
1288
0
        stackPush(Builder.createCall(
1289
0
            Context.getIntrinsic(Builder, Executable::Intrinsics::kRefCast,
1290
0
                                 LLVM::Type::getFunctionType(
1291
0
                                     Context.Int64x2Ty,
1292
0
                                     {Context.Int64x2Ty, Context.Int64Ty},
1293
0
                                     false)),
1294
0
            {Ref, VType}));
1295
0
        break;
1296
0
      }
1297
0
      case OpCode::Any__convert_extern: {
1298
0
        std::array<uint8_t, 16> RawRef = {0};
1299
0
        auto Ref = stackPop();
1300
0
        auto PtrVal = Builder.createExtractElement(Ref, LLContext.getInt64(1));
1301
0
        auto IsNullBB =
1302
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.null");
1303
0
        auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn,
1304
0
                                                  "any_conv_extern.not_null");
1305
0
        auto IsExtrefBB = LLVM::BasicBlock::create(LLContext, F.Fn,
1306
0
                                                   "any_conv_extern.is_extref");
1307
0
        auto EndBB =
1308
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.end");
1309
0
        auto CondIsNull = Builder.createICmpEQ(PtrVal, LLContext.getInt64(0));
1310
0
        Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB);
1311
1312
0
        Builder.positionAtEnd(IsNullBB);
1313
0
        auto VT = ValType(TypeCode::RefNull, TypeCode::NullRef);
1314
0
        std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
1315
0
        auto Ret1 = Builder.createBitCast(
1316
0
            LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
1317
0
        Builder.createBr(EndBB);
1318
1319
0
        Builder.positionAtEnd(NotNullBB);
1320
0
        auto Ret2 = Builder.createBitCast(
1321
0
            Builder.createInsertElement(
1322
0
                Builder.createBitCast(Ref, Context.Int8x16Ty),
1323
0
                LLContext.getInt8(0), LLContext.getInt64(1)),
1324
0
            Context.Int64x2Ty);
1325
0
        auto HType = Builder.createExtractElement(
1326
0
            Builder.createBitCast(Ret2, Context.Int8x16Ty),
1327
0
            LLContext.getInt64(3));
1328
0
        auto CondIsExtref = Builder.createOr(
1329
0
            Builder.createICmpEQ(HType, LLContext.getInt8(static_cast<uint8_t>(
1330
0
                                            TypeCode::ExternRef))),
1331
0
            Builder.createICmpEQ(HType, LLContext.getInt8(static_cast<uint8_t>(
1332
0
                                            TypeCode::NullExternRef))));
1333
0
        Builder.createCondBr(CondIsExtref, IsExtrefBB, EndBB);
1334
1335
0
        Builder.positionAtEnd(IsExtrefBB);
1336
0
        VT = ValType(TypeCode::Ref, TypeCode::AnyRef);
1337
0
        std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
1338
0
        auto Ret3 = Builder.createInsertElement(
1339
0
            Builder.createBitCast(
1340
0
                LLVM::Value::getConstVector8(LLContext, RawRef),
1341
0
                Context.Int64x2Ty),
1342
0
            PtrVal, LLContext.getInt64(1));
1343
0
        Builder.createBr(EndBB);
1344
1345
0
        Builder.positionAtEnd(EndBB);
1346
0
        auto Ret = Builder.createPHI(Context.Int64x2Ty);
1347
0
        Ret.addIncoming(Ret1, IsNullBB);
1348
0
        Ret.addIncoming(Ret2, NotNullBB);
1349
0
        Ret.addIncoming(Ret3, IsExtrefBB);
1350
0
        stackPush(Ret);
1351
0
        break;
1352
0
      }
1353
0
      case OpCode::Extern__convert_any: {
1354
0
        std::array<uint8_t, 16> RawRef = {0};
1355
0
        auto Ref = stackPop();
1356
0
        auto IsNullBB =
1357
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.null");
1358
0
        auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn,
1359
0
                                                  "extern_conv_any.not_null");
1360
0
        auto EndBB =
1361
0
            LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.end");
1362
0
        auto CondIsNull = Builder.createICmpEQ(
1363
0
            Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1364
0
            LLContext.getInt64(0));
1365
0
        Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB);
1366
1367
0
        Builder.positionAtEnd(IsNullBB);
1368
0
        auto VT = ValType(TypeCode::RefNull, TypeCode::NullExternRef);
1369
0
        std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
1370
0
        auto Ret1 = Builder.createBitCast(
1371
0
            LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
1372
0
        Builder.createBr(EndBB);
1373
1374
0
        Builder.positionAtEnd(NotNullBB);
1375
0
        auto Ret2 = Builder.createBitCast(
1376
0
            Builder.createInsertElement(
1377
0
                Builder.createBitCast(Ref, Context.Int8x16Ty),
1378
0
                LLContext.getInt8(1), LLContext.getInt64(1)),
1379
0
            Context.Int64x2Ty);
1380
0
        Builder.createBr(EndBB);
1381
1382
0
        Builder.positionAtEnd(EndBB);
1383
0
        auto Ret = Builder.createPHI(Context.Int64x2Ty);
1384
0
        Ret.addIncoming(Ret1, IsNullBB);
1385
0
        Ret.addIncoming(Ret2, NotNullBB);
1386
0
        stackPush(Ret);
1387
0
        break;
1388
0
      }
1389
0
      case OpCode::Ref__i31: {
1390
0
        std::array<uint8_t, 16> RawRef = {0};
1391
0
        auto VT = ValType(TypeCode::Ref, TypeCode::I31Ref);
1392
0
        std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
1393
0
        auto Ref = Builder.createBitCast(
1394
0
            LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
1395
0
        auto Val = Builder.createZExt(
1396
0
            Builder.createOr(
1397
0
                Builder.createAnd(stackPop(), LLContext.getInt32(0x7FFFFFFFU)),
1398
0
                LLContext.getInt32(0x80000000U)),
1399
0
            Context.Int64Ty);
1400
0
        stackPush(Builder.createInsertElement(Ref, Val, LLContext.getInt64(1)));
1401
0
        break;
1402
0
      }
1403
0
      case OpCode::I31__get_s: {
1404
0
        auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok");
1405
0
        auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1406
0
        auto Val = Builder.createTrunc(
1407
0
            Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1408
0
            Context.Int32Ty);
1409
0
        auto IsNotNull = Builder.createLikely(Builder.createICmpNE(
1410
0
            Builder.createAnd(Val, LLContext.getInt32(0x80000000U)),
1411
0
            LLContext.getInt32(0)));
1412
0
        Builder.createCondBr(IsNotNull, Next,
1413
0
                             getTrapBB(ErrCode::Value::AccessNullI31));
1414
0
        Builder.positionAtEnd(Next);
1415
0
        Val = Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU));
1416
0
        stackPush(Builder.createOr(
1417
0
            Val, Builder.createShl(
1418
0
                     Builder.createAnd(Val, LLContext.getInt32(0x40000000U)),
1419
0
                     LLContext.getInt32(1))));
1420
0
        break;
1421
0
      }
1422
0
      case OpCode::I31__get_u: {
1423
0
        auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok");
1424
0
        auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1425
0
        auto Val = Builder.createTrunc(
1426
0
            Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1427
0
            Context.Int32Ty);
1428
0
        auto IsNotNull = Builder.createLikely(Builder.createICmpNE(
1429
0
            Builder.createAnd(Val, LLContext.getInt32(0x80000000U)),
1430
0
            LLContext.getInt32(0)));
1431
0
        Builder.createCondBr(IsNotNull, Next,
1432
0
                             getTrapBB(ErrCode::Value::AccessNullI31));
1433
0
        Builder.positionAtEnd(Next);
1434
0
        stackPush(Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU)));
1435
0
        break;
1436
0
      }
1437
1438
      // Parametric Instructions
1439
3.50k
      case OpCode::Drop:
1440
3.50k
        stackPop();
1441
3.50k
        break;
1442
752
      case OpCode::Select:
1443
1.20k
      case OpCode::Select_t: {
1444
1.20k
        auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
1445
1.20k
        auto False = stackPop();
1446
1.20k
        auto True = stackPop();
1447
1.20k
        stackPush(Builder.createSelect(Cond, True, False));
1448
1.20k
        break;
1449
752
      }
1450
1451
      // Variable Instructions
1452
11.1k
      case OpCode::Local__get: {
1453
11.1k
        const auto &L = Local[Instr.getTargetIndex()];
1454
11.1k
        stackPush(Builder.createLoad(L.first, L.second));
1455
11.1k
        break;
1456
752
      }
1457
4.97k
      case OpCode::Local__set:
1458
4.97k
        Builder.createStore(stackPop(), Local[Instr.getTargetIndex()].second);
1459
4.97k
        break;
1460
771
      case OpCode::Local__tee:
1461
771
        Builder.createStore(Stack.back(), Local[Instr.getTargetIndex()].second);
1462
771
        break;
1463
275
      case OpCode::Global__get: {
1464
275
        const auto G =
1465
275
            Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex());
1466
275
        stackPush(Builder.createLoad(G.first, G.second));
1467
275
        break;
1468
752
      }
1469
57
      case OpCode::Global__set:
1470
57
        Builder.createStore(
1471
57
            stackPop(),
1472
57
            Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex()).second);
1473
57
        break;
1474
1475
      // Table Instructions
1476
35
      case OpCode::Table__get: {
1477
35
        auto Idx = stackPop();
1478
35
        stackPush(Builder.createCall(
1479
35
            Context.getIntrinsic(
1480
35
                Builder, Executable::Intrinsics::kTableGet,
1481
35
                LLVM::Type::getFunctionType(Context.Int64x2Ty,
1482
35
                                            {Context.Int32Ty, Context.Int32Ty},
1483
35
                                            false)),
1484
35
            {LLContext.getInt32(Instr.getTargetIndex()), Idx}));
1485
35
        break;
1486
752
      }
1487
29
      case OpCode::Table__set: {
1488
29
        auto Ref = stackPop();
1489
29
        auto Idx = stackPop();
1490
29
        Builder.createCall(
1491
29
            Context.getIntrinsic(
1492
29
                Builder, Executable::Intrinsics::kTableSet,
1493
29
                LLVM::Type::getFunctionType(
1494
29
                    Context.Int64Ty,
1495
29
                    {Context.Int32Ty, Context.Int32Ty, Context.Int64x2Ty},
1496
29
                    false)),
1497
29
            {LLContext.getInt32(Instr.getTargetIndex()), Idx, Ref});
1498
29
        break;
1499
752
      }
1500
27
      case OpCode::Table__init: {
1501
27
        auto Len = stackPop();
1502
27
        auto Src = stackPop();
1503
27
        auto Dst = stackPop();
1504
27
        Builder.createCall(
1505
27
            Context.getIntrinsic(
1506
27
                Builder, Executable::Intrinsics::kTableInit,
1507
27
                LLVM::Type::getFunctionType(Context.VoidTy,
1508
27
                                            {Context.Int32Ty, Context.Int32Ty,
1509
27
                                             Context.Int32Ty, Context.Int32Ty,
1510
27
                                             Context.Int32Ty},
1511
27
                                            false)),
1512
27
            {LLContext.getInt32(Instr.getTargetIndex()),
1513
27
             LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
1514
27
        break;
1515
752
      }
1516
35
      case OpCode::Elem__drop: {
1517
35
        Builder.createCall(
1518
35
            Context.getIntrinsic(Builder, Executable::Intrinsics::kElemDrop,
1519
35
                                 LLVM::Type::getFunctionType(
1520
35
                                     Context.VoidTy, {Context.Int32Ty}, false)),
1521
35
            {LLContext.getInt32(Instr.getTargetIndex())});
1522
35
        break;
1523
752
      }
1524
22
      case OpCode::Table__copy: {
1525
22
        auto Len = stackPop();
1526
22
        auto Src = stackPop();
1527
22
        auto Dst = stackPop();
1528
22
        Builder.createCall(
1529
22
            Context.getIntrinsic(
1530
22
                Builder, Executable::Intrinsics::kTableCopy,
1531
22
                LLVM::Type::getFunctionType(Context.VoidTy,
1532
22
                                            {Context.Int32Ty, Context.Int32Ty,
1533
22
                                             Context.Int32Ty, Context.Int32Ty,
1534
22
                                             Context.Int32Ty},
1535
22
                                            false)),
1536
22
            {LLContext.getInt32(Instr.getTargetIndex()),
1537
22
             LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
1538
22
        break;
1539
752
      }
1540
17
      case OpCode::Table__grow: {
1541
17
        auto NewSize = stackPop();
1542
17
        auto Val = stackPop();
1543
17
        stackPush(Builder.createCall(
1544
17
            Context.getIntrinsic(
1545
17
                Builder, Executable::Intrinsics::kTableGrow,
1546
17
                LLVM::Type::getFunctionType(
1547
17
                    Context.Int32Ty,
1548
17
                    {Context.Int32Ty, Context.Int64x2Ty, Context.Int32Ty},
1549
17
                    false)),
1550
17
            {LLContext.getInt32(Instr.getTargetIndex()), Val, NewSize}));
1551
17
        break;
1552
752
      }
1553
21
      case OpCode::Table__size: {
1554
21
        stackPush(Builder.createCall(
1555
21
            Context.getIntrinsic(Builder, Executable::Intrinsics::kTableSize,
1556
21
                                 LLVM::Type::getFunctionType(Context.Int32Ty,
1557
21
                                                             {Context.Int32Ty},
1558
21
                                                             false)),
1559
21
            {LLContext.getInt32(Instr.getTargetIndex())}));
1560
21
        break;
1561
752
      }
1562
3
      case OpCode::Table__fill: {
1563
3
        auto Len = stackPop();
1564
3
        auto Val = stackPop();
1565
3
        auto Off = stackPop();
1566
3
        Builder.createCall(
1567
3
            Context.getIntrinsic(Builder, Executable::Intrinsics::kTableFill,
1568
3
                                 LLVM::Type::getFunctionType(
1569
3
                                     Context.Int32Ty,
1570
3
                                     {Context.Int32Ty, Context.Int32Ty,
1571
3
                                      Context.Int64x2Ty, Context.Int32Ty},
1572
3
                                     false)),
1573
3
            {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
1574
3
        break;
1575
752
      }
1576
1577
      // Memory Instructions
1578
1.20k
      case OpCode::I32__load:
1579
1.20k
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1580
1.20k
                      Instr.getMemoryAlign(), Context.Int32Ty);
1581
1.20k
        break;
1582
4.36k
      case OpCode::I64__load:
1583
4.36k
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1584
4.36k
                      Instr.getMemoryAlign(), Context.Int64Ty);
1585
4.36k
        break;
1586
118
      case OpCode::F32__load:
1587
118
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1588
118
                      Instr.getMemoryAlign(), Context.FloatTy);
1589
118
        break;
1590
306
      case OpCode::F64__load:
1591
306
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1592
306
                      Instr.getMemoryAlign(), Context.DoubleTy);
1593
306
        break;
1594
466
      case OpCode::I32__load8_s:
1595
466
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1596
466
                      Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty,
1597
466
                      true);
1598
466
        break;
1599
173
      case OpCode::I32__load8_u:
1600
173
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1601
173
                      Instr.getMemoryAlign(), Context.Int8Ty, Context.Int32Ty,
1602
173
                      false);
1603
173
        break;
1604
466
      case OpCode::I32__load16_s:
1605
466
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1606
466
                      Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty,
1607
466
                      true);
1608
466
        break;
1609
1.73k
      case OpCode::I32__load16_u:
1610
1.73k
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1611
1.73k
                      Instr.getMemoryAlign(), Context.Int16Ty, Context.Int32Ty,
1612
1.73k
                      false);
1613
1.73k
        break;
1614
808
      case OpCode::I64__load8_s:
1615
808
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1616
808
                      Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty,
1617
808
                      true);
1618
808
        break;
1619
455
      case OpCode::I64__load8_u:
1620
455
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1621
455
                      Instr.getMemoryAlign(), Context.Int8Ty, Context.Int64Ty,
1622
455
                      false);
1623
455
        break;
1624
515
      case OpCode::I64__load16_s:
1625
515
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1626
515
                      Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty,
1627
515
                      true);
1628
515
        break;
1629
681
      case OpCode::I64__load16_u:
1630
681
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1631
681
                      Instr.getMemoryAlign(), Context.Int16Ty, Context.Int64Ty,
1632
681
                      false);
1633
681
        break;
1634
405
      case OpCode::I64__load32_s:
1635
405
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1636
405
                      Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty,
1637
405
                      true);
1638
405
        break;
1639
450
      case OpCode::I64__load32_u:
1640
450
        compileLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1641
450
                      Instr.getMemoryAlign(), Context.Int32Ty, Context.Int64Ty,
1642
450
                      false);
1643
450
        break;
1644
458
      case OpCode::I32__store:
1645
458
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1646
458
                       Instr.getMemoryAlign(), Context.Int32Ty);
1647
458
        break;
1648
1.49k
      case OpCode::I64__store:
1649
1.49k
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1650
1.49k
                       Instr.getMemoryAlign(), Context.Int64Ty);
1651
1.49k
        break;
1652
75
      case OpCode::F32__store:
1653
75
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1654
75
                       Instr.getMemoryAlign(), Context.FloatTy);
1655
75
        break;
1656
46
      case OpCode::F64__store:
1657
46
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1658
46
                       Instr.getMemoryAlign(), Context.DoubleTy);
1659
46
        break;
1660
357
      case OpCode::I32__store8:
1661
378
      case OpCode::I64__store8:
1662
378
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1663
378
                       Instr.getMemoryAlign(), Context.Int8Ty, true);
1664
378
        break;
1665
232
      case OpCode::I32__store16:
1666
280
      case OpCode::I64__store16:
1667
280
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1668
280
                       Instr.getMemoryAlign(), Context.Int16Ty, true);
1669
280
        break;
1670
36
      case OpCode::I64__store32:
1671
36
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
1672
36
                       Instr.getMemoryAlign(), Context.Int32Ty, true);
1673
36
        break;
1674
877
      case OpCode::Memory__size:
1675
877
        stackPush(Builder.createCall(
1676
877
            Context.getIntrinsic(Builder, Executable::Intrinsics::kMemSize,
1677
877
                                 LLVM::Type::getFunctionType(Context.Int32Ty,
1678
877
                                                             {Context.Int32Ty},
1679
877
                                                             false)),
1680
877
            {LLContext.getInt32(Instr.getTargetIndex())}));
1681
877
        break;
1682
551
      case OpCode::Memory__grow: {
1683
551
        auto Diff = stackPop();
1684
551
        stackPush(Builder.createCall(
1685
551
            Context.getIntrinsic(
1686
551
                Builder, Executable::Intrinsics::kMemGrow,
1687
551
                LLVM::Type::getFunctionType(Context.Int32Ty,
1688
551
                                            {Context.Int32Ty, Context.Int32Ty},
1689
551
                                            false)),
1690
551
            {LLContext.getInt32(Instr.getTargetIndex()), Diff}));
1691
551
        break;
1692
232
      }
1693
26
      case OpCode::Memory__init: {
1694
26
        auto Len = stackPop();
1695
26
        auto Src = stackPop();
1696
26
        auto Dst = stackPop();
1697
26
        Builder.createCall(
1698
26
            Context.getIntrinsic(
1699
26
                Builder, Executable::Intrinsics::kMemInit,
1700
26
                LLVM::Type::getFunctionType(Context.VoidTy,
1701
26
                                            {Context.Int32Ty, Context.Int32Ty,
1702
26
                                             Context.Int32Ty, Context.Int32Ty,
1703
26
                                             Context.Int32Ty},
1704
26
                                            false)),
1705
26
            {LLContext.getInt32(Instr.getTargetIndex()),
1706
26
             LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
1707
26
        break;
1708
232
      }
1709
24
      case OpCode::Data__drop: {
1710
24
        Builder.createCall(
1711
24
            Context.getIntrinsic(Builder, Executable::Intrinsics::kDataDrop,
1712
24
                                 LLVM::Type::getFunctionType(
1713
24
                                     Context.VoidTy, {Context.Int32Ty}, false)),
1714
24
            {LLContext.getInt32(Instr.getTargetIndex())});
1715
24
        break;
1716
232
      }
1717
253
      case OpCode::Memory__copy: {
1718
253
        auto Len = stackPop();
1719
253
        auto Src = stackPop();
1720
253
        auto Dst = stackPop();
1721
253
        Builder.createCall(
1722
253
            Context.getIntrinsic(
1723
253
                Builder, Executable::Intrinsics::kMemCopy,
1724
253
                LLVM::Type::getFunctionType(Context.VoidTy,
1725
253
                                            {Context.Int32Ty, Context.Int32Ty,
1726
253
                                             Context.Int32Ty, Context.Int32Ty,
1727
253
                                             Context.Int32Ty},
1728
253
                                            false)),
1729
253
            {LLContext.getInt32(Instr.getTargetIndex()),
1730
253
             LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
1731
253
        break;
1732
232
      }
1733
594
      case OpCode::Memory__fill: {
1734
594
        auto Len = stackPop();
1735
594
        auto Val = Builder.createTrunc(stackPop(), Context.Int8Ty);
1736
594
        auto Off = stackPop();
1737
594
        Builder.createCall(
1738
594
            Context.getIntrinsic(
1739
594
                Builder, Executable::Intrinsics::kMemFill,
1740
594
                LLVM::Type::getFunctionType(Context.VoidTy,
1741
594
                                            {Context.Int32Ty, Context.Int32Ty,
1742
594
                                             Context.Int8Ty, Context.Int32Ty},
1743
594
                                            false)),
1744
594
            {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
1745
594
        break;
1746
232
      }
1747
1748
      // Const Numeric Instructions
1749
609k
      case OpCode::I32__const:
1750
609k
        stackPush(LLContext.getInt32(Instr.getNum().get<uint32_t>()));
1751
609k
        break;
1752
90.1k
      case OpCode::I64__const:
1753
90.1k
        stackPush(LLContext.getInt64(Instr.getNum().get<uint64_t>()));
1754
90.1k
        break;
1755
16.0k
      case OpCode::F32__const:
1756
16.0k
        stackPush(LLContext.getFloat(Instr.getNum().get<float>()));
1757
16.0k
        break;
1758
7.46k
      case OpCode::F64__const:
1759
7.46k
        stackPush(LLContext.getDouble(Instr.getNum().get<double>()));
1760
7.46k
        break;
1761
1762
      // Unary Numeric Instructions
1763
7.56k
      case OpCode::I32__eqz:
1764
7.56k
        stackPush(Builder.createZExt(
1765
7.56k
            Builder.createICmpEQ(stackPop(), LLContext.getInt32(0)),
1766
7.56k
            Context.Int32Ty));
1767
7.56k
        break;
1768
1.22k
      case OpCode::I64__eqz:
1769
1.22k
        stackPush(Builder.createZExt(
1770
1.22k
            Builder.createICmpEQ(stackPop(), LLContext.getInt64(0)),
1771
1.22k
            Context.Int32Ty));
1772
1.22k
        break;
1773
2.34k
      case OpCode::I32__clz:
1774
2.34k
        assuming(LLVM::Core::Ctlz != LLVM::Core::NotIntrinsic);
1775
2.34k
        stackPush(Builder.createIntrinsic(LLVM::Core::Ctlz, {Context.Int32Ty},
1776
2.34k
                                          {stackPop(), LLContext.getFalse()}));
1777
2.34k
        break;
1778
311
      case OpCode::I64__clz:
1779
311
        assuming(LLVM::Core::Ctlz != LLVM::Core::NotIntrinsic);
1780
311
        stackPush(Builder.createIntrinsic(LLVM::Core::Ctlz, {Context.Int64Ty},
1781
311
                                          {stackPop(), LLContext.getFalse()}));
1782
311
        break;
1783
2.10k
      case OpCode::I32__ctz:
1784
2.10k
        assuming(LLVM::Core::Cttz != LLVM::Core::NotIntrinsic);
1785
2.10k
        stackPush(Builder.createIntrinsic(LLVM::Core::Cttz, {Context.Int32Ty},
1786
2.10k
                                          {stackPop(), LLContext.getFalse()}));
1787
2.10k
        break;
1788
465
      case OpCode::I64__ctz:
1789
465
        assuming(LLVM::Core::Cttz != LLVM::Core::NotIntrinsic);
1790
465
        stackPush(Builder.createIntrinsic(LLVM::Core::Cttz, {Context.Int64Ty},
1791
465
                                          {stackPop(), LLContext.getFalse()}));
1792
465
        break;
1793
17.2k
      case OpCode::I32__popcnt:
1794
19.1k
      case OpCode::I64__popcnt:
1795
19.1k
        assuming(LLVM::Core::Ctpop != LLVM::Core::NotIntrinsic);
1796
19.1k
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Ctpop, stackPop()));
1797
19.1k
        break;
1798
1.09k
      case OpCode::F32__abs:
1799
2.12k
      case OpCode::F64__abs:
1800
2.12k
        assuming(LLVM::Core::Fabs != LLVM::Core::NotIntrinsic);
1801
2.12k
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Fabs, stackPop()));
1802
2.12k
        break;
1803
1.07k
      case OpCode::F32__neg:
1804
1.84k
      case OpCode::F64__neg:
1805
1.84k
        stackPush(Builder.createFNeg(stackPop()));
1806
1.84k
        break;
1807
1.86k
      case OpCode::F32__ceil:
1808
4.48k
      case OpCode::F64__ceil:
1809
4.48k
        assuming(LLVM::Core::Ceil != LLVM::Core::NotIntrinsic);
1810
4.48k
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Ceil, stackPop()));
1811
4.48k
        break;
1812
886
      case OpCode::F32__floor:
1813
1.26k
      case OpCode::F64__floor:
1814
1.26k
        assuming(LLVM::Core::Floor != LLVM::Core::NotIntrinsic);
1815
1.26k
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Floor, stackPop()));
1816
1.26k
        break;
1817
555
      case OpCode::F32__trunc:
1818
856
      case OpCode::F64__trunc:
1819
856
        assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
1820
856
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Trunc, stackPop()));
1821
856
        break;
1822
838
      case OpCode::F32__nearest:
1823
1.19k
      case OpCode::F64__nearest: {
1824
1.19k
        const bool IsFloat = Instr.getOpCode() == OpCode::F32__nearest;
1825
1.19k
        LLVM::Value Value = stackPop();
1826
1827
1.19k
#if LLVM_VERSION_MAJOR >= 12 && !defined(__s390x__)
1828
1.19k
        assuming(LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic);
1829
1.19k
        if (LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic) {
1830
1.19k
          stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Roundeven, Value));
1831
1.19k
          break;
1832
1.19k
        }
1833
0
#endif
1834
1835
        // The VectorSize is only used when SSE4_1 or NEON is supported.
1836
0
        [[maybe_unused]] const uint32_t VectorSize = IsFloat ? 4 : 2;
1837
0
#if defined(__x86_64__)
1838
0
        if (Context.SupportSSE4_1) {
1839
0
          auto Zero = LLContext.getInt64(0);
1840
0
          auto VectorTy =
1841
0
              LLVM::Type::getVectorType(Value.getType(), VectorSize);
1842
0
          LLVM::Value Ret = LLVM::Value::getUndef(VectorTy);
1843
0
          Ret = Builder.createInsertElement(Ret, Value, Zero);
1844
0
          auto ID = IsFloat ? LLVM::Core::X86SSE41RoundSs
1845
0
                            : LLVM::Core::X86SSE41RoundSd;
1846
0
          assuming(ID != LLVM::Core::NotIntrinsic);
1847
0
          Ret = Builder.createIntrinsic(ID, {},
1848
0
                                        {Ret, Ret, LLContext.getInt32(8)});
1849
0
          Ret = Builder.createExtractElement(Ret, Zero);
1850
0
          stackPush(Ret);
1851
0
          break;
1852
0
        }
1853
0
#endif
1854
1855
#if defined(__aarch64__)
1856
        if (Context.SupportNEON &&
1857
            LLVM::Core::AArch64NeonFRIntN != LLVM::Core::NotIntrinsic) {
1858
          auto Zero = LLContext.getInt64(0);
1859
          auto VectorTy =
1860
              LLVM::Type::getVectorType(Value.getType(), VectorSize);
1861
          LLVM::Value Ret = LLVM::Value::getUndef(VectorTy);
1862
          Ret = Builder.createInsertElement(Ret, Value, Zero);
1863
          Ret =
1864
              Builder.createUnaryIntrinsic(LLVM::Core::AArch64NeonFRIntN, Ret);
1865
          Ret = Builder.createExtractElement(Ret, Zero);
1866
          stackPush(Ret);
1867
          break;
1868
        }
1869
#endif
1870
1871
        // Fallback case.
1872
        // If the SSE4.1 is not supported on the x86_64 platform or
1873
        // the NEON is not supported on the aarch64 platform,
1874
        // then fallback to this.
1875
0
        assuming(LLVM::Core::Nearbyint != LLVM::Core::NotIntrinsic);
1876
0
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Nearbyint, Value));
1877
0
        break;
1878
0
      }
1879
398
      case OpCode::F32__sqrt:
1880
2.41k
      case OpCode::F64__sqrt:
1881
2.41k
        assuming(LLVM::Core::Sqrt != LLVM::Core::NotIntrinsic);
1882
2.41k
        stackPush(Builder.createUnaryIntrinsic(LLVM::Core::Sqrt, stackPop()));
1883
2.41k
        break;
1884
322
      case OpCode::I32__wrap_i64:
1885
322
        stackPush(Builder.createTrunc(stackPop(), Context.Int32Ty));
1886
322
        break;
1887
1.35k
      case OpCode::I32__trunc_f32_s:
1888
1.35k
        compileSignedTrunc(Context.Int32Ty);
1889
1.35k
        break;
1890
321
      case OpCode::I32__trunc_f64_s:
1891
321
        compileSignedTrunc(Context.Int32Ty);
1892
321
        break;
1893
181
      case OpCode::I32__trunc_f32_u:
1894
181
        compileUnsignedTrunc(Context.Int32Ty);
1895
181
        break;
1896
1.51k
      case OpCode::I32__trunc_f64_u:
1897
1.51k
        compileUnsignedTrunc(Context.Int32Ty);
1898
1.51k
        break;
1899
2.43k
      case OpCode::I64__extend_i32_s:
1900
2.43k
        stackPush(Builder.createSExt(stackPop(), Context.Int64Ty));
1901
2.43k
        break;
1902
415
      case OpCode::I64__extend_i32_u:
1903
415
        stackPush(Builder.createZExt(stackPop(), Context.Int64Ty));
1904
415
        break;
1905
52
      case OpCode::I64__trunc_f32_s:
1906
52
        compileSignedTrunc(Context.Int64Ty);
1907
52
        break;
1908
422
      case OpCode::I64__trunc_f64_s:
1909
422
        compileSignedTrunc(Context.Int64Ty);
1910
422
        break;
1911
970
      case OpCode::I64__trunc_f32_u:
1912
970
        compileUnsignedTrunc(Context.Int64Ty);
1913
970
        break;
1914
1.25k
      case OpCode::I64__trunc_f64_u:
1915
1.25k
        compileUnsignedTrunc(Context.Int64Ty);
1916
1.25k
        break;
1917
1.78k
      case OpCode::F32__convert_i32_s:
1918
2.16k
      case OpCode::F32__convert_i64_s:
1919
2.16k
        stackPush(Builder.createSIToFP(stackPop(), Context.FloatTy));
1920
2.16k
        break;
1921
642
      case OpCode::F32__convert_i32_u:
1922
1.73k
      case OpCode::F32__convert_i64_u:
1923
1.73k
        stackPush(Builder.createUIToFP(stackPop(), Context.FloatTy));
1924
1.73k
        break;
1925
1.78k
      case OpCode::F64__convert_i32_s:
1926
6.42k
      case OpCode::F64__convert_i64_s:
1927
6.42k
        stackPush(Builder.createSIToFP(stackPop(), Context.DoubleTy));
1928
6.42k
        break;
1929
1.30k
      case OpCode::F64__convert_i32_u:
1930
1.48k
      case OpCode::F64__convert_i64_u:
1931
1.48k
        stackPush(Builder.createUIToFP(stackPop(), Context.DoubleTy));
1932
1.48k
        break;
1933
198
      case OpCode::F32__demote_f64:
1934
198
        stackPush(Builder.createFPTrunc(stackPop(), Context.FloatTy));
1935
198
        break;
1936
88
      case OpCode::F64__promote_f32:
1937
88
        stackPush(Builder.createFPExt(stackPop(), Context.DoubleTy));
1938
88
        break;
1939
886
      case OpCode::I32__reinterpret_f32:
1940
886
        stackPush(Builder.createBitCast(stackPop(), Context.Int32Ty));
1941
886
        break;
1942
647
      case OpCode::I64__reinterpret_f64:
1943
647
        stackPush(Builder.createBitCast(stackPop(), Context.Int64Ty));
1944
647
        break;
1945
4.53k
      case OpCode::F32__reinterpret_i32:
1946
4.53k
        stackPush(Builder.createBitCast(stackPop(), Context.FloatTy));
1947
4.53k
        break;
1948
1.15k
      case OpCode::F64__reinterpret_i64:
1949
1.15k
        stackPush(Builder.createBitCast(stackPop(), Context.DoubleTy));
1950
1.15k
        break;
1951
2.33k
      case OpCode::I32__extend8_s:
1952
2.33k
        stackPush(Builder.createSExt(
1953
2.33k
            Builder.createTrunc(stackPop(), Context.Int8Ty), Context.Int32Ty));
1954
2.33k
        break;
1955
3.29k
      case OpCode::I32__extend16_s:
1956
3.29k
        stackPush(Builder.createSExt(
1957
3.29k
            Builder.createTrunc(stackPop(), Context.Int16Ty), Context.Int32Ty));
1958
3.29k
        break;
1959
383
      case OpCode::I64__extend8_s:
1960
383
        stackPush(Builder.createSExt(
1961
383
            Builder.createTrunc(stackPop(), Context.Int8Ty), Context.Int64Ty));
1962
383
        break;
1963
614
      case OpCode::I64__extend16_s:
1964
614
        stackPush(Builder.createSExt(
1965
614
            Builder.createTrunc(stackPop(), Context.Int16Ty), Context.Int64Ty));
1966
614
        break;
1967
745
      case OpCode::I64__extend32_s:
1968
745
        stackPush(Builder.createSExt(
1969
745
            Builder.createTrunc(stackPop(), Context.Int32Ty), Context.Int64Ty));
1970
745
        break;
1971
1972
      // Binary Numeric Instructions
1973
1.19k
      case OpCode::I32__eq:
1974
1.45k
      case OpCode::I64__eq: {
1975
1.45k
        LLVM::Value RHS = stackPop();
1976
1.45k
        LLVM::Value LHS = stackPop();
1977
1.45k
        stackPush(Builder.createZExt(Builder.createICmpEQ(LHS, RHS),
1978
1.45k
                                     Context.Int32Ty));
1979
1.45k
        break;
1980
1.19k
      }
1981
763
      case OpCode::I32__ne:
1982
785
      case OpCode::I64__ne: {
1983
785
        LLVM::Value RHS = stackPop();
1984
785
        LLVM::Value LHS = stackPop();
1985
785
        stackPush(Builder.createZExt(Builder.createICmpNE(LHS, RHS),
1986
785
                                     Context.Int32Ty));
1987
785
        break;
1988
763
      }
1989
4.45k
      case OpCode::I32__lt_s:
1990
5.07k
      case OpCode::I64__lt_s: {
1991
5.07k
        LLVM::Value RHS = stackPop();
1992
5.07k
        LLVM::Value LHS = stackPop();
1993
5.07k
        stackPush(Builder.createZExt(Builder.createICmpSLT(LHS, RHS),
1994
5.07k
                                     Context.Int32Ty));
1995
5.07k
        break;
1996
4.45k
      }
1997
6.58k
      case OpCode::I32__lt_u:
1998
6.97k
      case OpCode::I64__lt_u: {
1999
6.97k
        LLVM::Value RHS = stackPop();
2000
6.97k
        LLVM::Value LHS = stackPop();
2001
6.97k
        stackPush(Builder.createZExt(Builder.createICmpULT(LHS, RHS),
2002
6.97k
                                     Context.Int32Ty));
2003
6.97k
        break;
2004
6.58k
      }
2005
1.20k
      case OpCode::I32__gt_s:
2006
1.64k
      case OpCode::I64__gt_s: {
2007
1.64k
        LLVM::Value RHS = stackPop();
2008
1.64k
        LLVM::Value LHS = stackPop();
2009
1.64k
        stackPush(Builder.createZExt(Builder.createICmpSGT(LHS, RHS),
2010
1.64k
                                     Context.Int32Ty));
2011
1.64k
        break;
2012
1.20k
      }
2013
7.88k
      case OpCode::I32__gt_u:
2014
8.12k
      case OpCode::I64__gt_u: {
2015
8.12k
        LLVM::Value RHS = stackPop();
2016
8.12k
        LLVM::Value LHS = stackPop();
2017
8.12k
        stackPush(Builder.createZExt(Builder.createICmpUGT(LHS, RHS),
2018
8.12k
                                     Context.Int32Ty));
2019
8.12k
        break;
2020
7.88k
      }
2021
2.04k
      case OpCode::I32__le_s:
2022
2.96k
      case OpCode::I64__le_s: {
2023
2.96k
        LLVM::Value RHS = stackPop();
2024
2.96k
        LLVM::Value LHS = stackPop();
2025
2.96k
        stackPush(Builder.createZExt(Builder.createICmpSLE(LHS, RHS),
2026
2.96k
                                     Context.Int32Ty));
2027
2.96k
        break;
2028
2.04k
      }
2029
495
      case OpCode::I32__le_u:
2030
2.14k
      case OpCode::I64__le_u: {
2031
2.14k
        LLVM::Value RHS = stackPop();
2032
2.14k
        LLVM::Value LHS = stackPop();
2033
2.14k
        stackPush(Builder.createZExt(Builder.createICmpULE(LHS, RHS),
2034
2.14k
                                     Context.Int32Ty));
2035
2.14k
        break;
2036
495
      }
2037
1.30k
      case OpCode::I32__ge_s:
2038
1.34k
      case OpCode::I64__ge_s: {
2039
1.34k
        LLVM::Value RHS = stackPop();
2040
1.34k
        LLVM::Value LHS = stackPop();
2041
1.34k
        stackPush(Builder.createZExt(Builder.createICmpSGE(LHS, RHS),
2042
1.34k
                                     Context.Int32Ty));
2043
1.34k
        break;
2044
1.30k
      }
2045
2.98k
      case OpCode::I32__ge_u:
2046
3.61k
      case OpCode::I64__ge_u: {
2047
3.61k
        LLVM::Value RHS = stackPop();
2048
3.61k
        LLVM::Value LHS = stackPop();
2049
3.61k
        stackPush(Builder.createZExt(Builder.createICmpUGE(LHS, RHS),
2050
3.61k
                                     Context.Int32Ty));
2051
3.61k
        break;
2052
2.98k
      }
2053
160
      case OpCode::F32__eq:
2054
216
      case OpCode::F64__eq: {
2055
216
        LLVM::Value RHS = stackPop();
2056
216
        LLVM::Value LHS = stackPop();
2057
216
        stackPush(Builder.createZExt(Builder.createFCmpOEQ(LHS, RHS),
2058
216
                                     Context.Int32Ty));
2059
216
        break;
2060
160
      }
2061
92
      case OpCode::F32__ne:
2062
120
      case OpCode::F64__ne: {
2063
120
        LLVM::Value RHS = stackPop();
2064
120
        LLVM::Value LHS = stackPop();
2065
120
        stackPush(Builder.createZExt(Builder.createFCmpUNE(LHS, RHS),
2066
120
                                     Context.Int32Ty));
2067
120
        break;
2068
92
      }
2069
177
      case OpCode::F32__lt:
2070
301
      case OpCode::F64__lt: {
2071
301
        LLVM::Value RHS = stackPop();
2072
301
        LLVM::Value LHS = stackPop();
2073
301
        stackPush(Builder.createZExt(Builder.createFCmpOLT(LHS, RHS),
2074
301
                                     Context.Int32Ty));
2075
301
        break;
2076
177
      }
2077
149
      case OpCode::F32__gt:
2078
205
      case OpCode::F64__gt: {
2079
205
        LLVM::Value RHS = stackPop();
2080
205
        LLVM::Value LHS = stackPop();
2081
205
        stackPush(Builder.createZExt(Builder.createFCmpOGT(LHS, RHS),
2082
205
                                     Context.Int32Ty));
2083
205
        break;
2084
149
      }
2085
75
      case OpCode::F32__le:
2086
174
      case OpCode::F64__le: {
2087
174
        LLVM::Value RHS = stackPop();
2088
174
        LLVM::Value LHS = stackPop();
2089
174
        stackPush(Builder.createZExt(Builder.createFCmpOLE(LHS, RHS),
2090
174
                                     Context.Int32Ty));
2091
174
        break;
2092
75
      }
2093
249
      case OpCode::F32__ge:
2094
275
      case OpCode::F64__ge: {
2095
275
        LLVM::Value RHS = stackPop();
2096
275
        LLVM::Value LHS = stackPop();
2097
275
        stackPush(Builder.createZExt(Builder.createFCmpOGE(LHS, RHS),
2098
275
                                     Context.Int32Ty));
2099
275
        break;
2100
249
      }
2101
803
      case OpCode::I32__add:
2102
1.27k
      case OpCode::I64__add: {
2103
1.27k
        LLVM::Value RHS = stackPop();
2104
1.27k
        LLVM::Value LHS = stackPop();
2105
1.27k
        stackPush(Builder.createAdd(LHS, RHS));
2106
1.27k
        break;
2107
803
      }
2108
1.68k
      case OpCode::I32__sub:
2109
2.11k
      case OpCode::I64__sub: {
2110
2.11k
        LLVM::Value RHS = stackPop();
2111
2.11k
        LLVM::Value LHS = stackPop();
2112
2113
2.11k
        stackPush(Builder.createSub(LHS, RHS));
2114
2.11k
        break;
2115
1.68k
      }
2116
609
      case OpCode::I32__mul:
2117
1.19k
      case OpCode::I64__mul: {
2118
1.19k
        LLVM::Value RHS = stackPop();
2119
1.19k
        LLVM::Value LHS = stackPop();
2120
1.19k
        stackPush(Builder.createMul(LHS, RHS));
2121
1.19k
        break;
2122
609
      }
2123
1.38k
      case OpCode::I32__div_s:
2124
1.95k
      case OpCode::I64__div_s: {
2125
1.95k
        LLVM::Value RHS = stackPop();
2126
1.95k
        LLVM::Value LHS = stackPop();
2127
1.95k
        if constexpr (kForceDivCheck) {
2128
1.95k
          const bool Is32 = Instr.getOpCode() == OpCode::I32__div_s;
2129
1.95k
          LLVM::Value IntZero =
2130
1.95k
              Is32 ? LLContext.getInt32(0) : LLContext.getInt64(0);
2131
1.95k
          LLVM::Value IntMinusOne =
2132
1.95k
              Is32 ? LLContext.getInt32(static_cast<uint32_t>(INT32_C(-1)))
2133
1.95k
                   : LLContext.getInt64(static_cast<uint64_t>(INT64_C(-1)));
2134
1.95k
          LLVM::Value IntMin = Is32 ? LLContext.getInt32(static_cast<uint32_t>(
2135
1.38k
                                          std::numeric_limits<int32_t>::min()))
2136
1.95k
                                    : LLContext.getInt64(static_cast<uint64_t>(
2137
567
                                          std::numeric_limits<int64_t>::min()));
2138
2139
1.95k
          auto NoZeroBB =
2140
1.95k
              LLVM::BasicBlock::create(LLContext, F.Fn, "div.nozero");
2141
1.95k
          auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "div.ok");
2142
2143
1.95k
          auto IsNotZero =
2144
1.95k
              Builder.createLikely(Builder.createICmpNE(RHS, IntZero));
2145
1.95k
          Builder.createCondBr(IsNotZero, NoZeroBB,
2146
1.95k
                               getTrapBB(ErrCode::Value::DivideByZero));
2147
2148
1.95k
          Builder.positionAtEnd(NoZeroBB);
2149
1.95k
          auto NotOverflow = Builder.createLikely(
2150
1.95k
              Builder.createOr(Builder.createICmpNE(LHS, IntMin),
2151
1.95k
                               Builder.createICmpNE(RHS, IntMinusOne)));
2152
1.95k
          Builder.createCondBr(NotOverflow, OkBB,
2153
1.95k
                               getTrapBB(ErrCode::Value::IntegerOverflow));
2154
2155
1.95k
          Builder.positionAtEnd(OkBB);
2156
1.95k
        }
2157
1.95k
        stackPush(Builder.createSDiv(LHS, RHS));
2158
1.95k
        break;
2159
1.38k
      }
2160
3.57k
      case OpCode::I32__div_u:
2161
3.88k
      case OpCode::I64__div_u: {
2162
3.88k
        LLVM::Value RHS = stackPop();
2163
3.88k
        LLVM::Value LHS = stackPop();
2164
3.88k
        if constexpr (kForceDivCheck) {
2165
3.88k
          const bool Is32 = Instr.getOpCode() == OpCode::I32__div_u;
2166
3.88k
          LLVM::Value IntZero =
2167
3.88k
              Is32 ? LLContext.getInt32(0) : LLContext.getInt64(0);
2168
3.88k
          auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "div.ok");
2169
2170
3.88k
          auto IsNotZero =
2171
3.88k
              Builder.createLikely(Builder.createICmpNE(RHS, IntZero));
2172
3.88k
          Builder.createCondBr(IsNotZero, OkBB,
2173
3.88k
                               getTrapBB(ErrCode::Value::DivideByZero));
2174
3.88k
          Builder.positionAtEnd(OkBB);
2175
3.88k
        }
2176
3.88k
        stackPush(Builder.createUDiv(LHS, RHS));
2177
3.88k
        break;
2178
3.57k
      }
2179
981
      case OpCode::I32__rem_s:
2180
1.43k
      case OpCode::I64__rem_s: {
2181
1.43k
        LLVM::Value RHS = stackPop();
2182
1.43k
        LLVM::Value LHS = stackPop();
2183
        // handle INT32_MIN % -1
2184
1.43k
        const bool Is32 = Instr.getOpCode() == OpCode::I32__rem_s;
2185
1.43k
        LLVM::Value IntMinusOne =
2186
1.43k
            Is32 ? LLContext.getInt32(static_cast<uint32_t>(INT32_C(-1)))
2187
1.43k
                 : LLContext.getInt64(static_cast<uint64_t>(INT64_C(-1)));
2188
1.43k
        LLVM::Value IntMin = Is32 ? LLContext.getInt32(static_cast<uint32_t>(
2189
981
                                        std::numeric_limits<int32_t>::min()))
2190
1.43k
                                  : LLContext.getInt64(static_cast<uint64_t>(
2191
455
                                        std::numeric_limits<int64_t>::min()));
2192
1.43k
        LLVM::Value IntZero =
2193
1.43k
            Is32 ? LLContext.getInt32(0) : LLContext.getInt64(0);
2194
2195
1.43k
        auto NoOverflowBB =
2196
1.43k
            LLVM::BasicBlock::create(LLContext, F.Fn, "no.overflow");
2197
1.43k
        auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "end.overflow");
2198
2199
1.43k
        if constexpr (kForceDivCheck) {
2200
1.43k
          auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rem.ok");
2201
2202
1.43k
          auto IsNotZero =
2203
1.43k
              Builder.createLikely(Builder.createICmpNE(RHS, IntZero));
2204
1.43k
          Builder.createCondBr(IsNotZero, OkBB,
2205
1.43k
                               getTrapBB(ErrCode::Value::DivideByZero));
2206
1.43k
          Builder.positionAtEnd(OkBB);
2207
1.43k
        }
2208
2209
1.43k
        auto CurrBB = Builder.getInsertBlock();
2210
2211
1.43k
        auto NotOverflow = Builder.createLikely(
2212
1.43k
            Builder.createOr(Builder.createICmpNE(LHS, IntMin),
2213
1.43k
                             Builder.createICmpNE(RHS, IntMinusOne)));
2214
1.43k
        Builder.createCondBr(NotOverflow, NoOverflowBB, EndBB);
2215
2216
1.43k
        Builder.positionAtEnd(NoOverflowBB);
2217
1.43k
        auto Ret1 = Builder.createSRem(LHS, RHS);
2218
1.43k
        Builder.createBr(EndBB);
2219
2220
1.43k
        Builder.positionAtEnd(EndBB);
2221
1.43k
        auto Ret = Builder.createPHI(Ret1.getType());
2222
1.43k
        Ret.addIncoming(Ret1, NoOverflowBB);
2223
1.43k
        Ret.addIncoming(IntZero, CurrBB);
2224
2225
1.43k
        stackPush(Ret);
2226
1.43k
        break;
2227
981
      }
2228
1.47k
      case OpCode::I32__rem_u:
2229
2.07k
      case OpCode::I64__rem_u: {
2230
2.07k
        LLVM::Value RHS = stackPop();
2231
2.07k
        LLVM::Value LHS = stackPop();
2232
2.07k
        if constexpr (kForceDivCheck) {
2233
2.07k
          LLVM::Value IntZero = Instr.getOpCode() == OpCode::I32__rem_u
2234
2.07k
                                    ? LLContext.getInt32(0)
2235
2.07k
                                    : LLContext.getInt64(0);
2236
2.07k
          auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rem.ok");
2237
2238
2.07k
          auto IsNotZero =
2239
2.07k
              Builder.createLikely(Builder.createICmpNE(RHS, IntZero));
2240
2.07k
          Builder.createCondBr(IsNotZero, OkBB,
2241
2.07k
                               getTrapBB(ErrCode::Value::DivideByZero));
2242
2.07k
          Builder.positionAtEnd(OkBB);
2243
2.07k
        }
2244
2.07k
        stackPush(Builder.createURem(LHS, RHS));
2245
2.07k
        break;
2246
1.47k
      }
2247
697
      case OpCode::I32__and:
2248
2.04k
      case OpCode::I64__and: {
2249
2.04k
        LLVM::Value RHS = stackPop();
2250
2.04k
        LLVM::Value LHS = stackPop();
2251
2.04k
        stackPush(Builder.createAnd(LHS, RHS));
2252
2.04k
        break;
2253
697
      }
2254
1.47k
      case OpCode::I32__or:
2255
1.83k
      case OpCode::I64__or: {
2256
1.83k
        LLVM::Value RHS = stackPop();
2257
1.83k
        LLVM::Value LHS = stackPop();
2258
1.83k
        stackPush(Builder.createOr(LHS, RHS));
2259
1.83k
        break;
2260
1.47k
      }
2261
1.13k
      case OpCode::I32__xor:
2262
1.64k
      case OpCode::I64__xor: {
2263
1.64k
        LLVM::Value RHS = stackPop();
2264
1.64k
        LLVM::Value LHS = stackPop();
2265
1.64k
        stackPush(Builder.createXor(LHS, RHS));
2266
1.64k
        break;
2267
1.13k
      }
2268
2.04k
      case OpCode::I32__shl:
2269
2.38k
      case OpCode::I64__shl: {
2270
2.38k
        LLVM::Value Mask = Instr.getOpCode() == OpCode::I32__shl
2271
2.38k
                               ? LLContext.getInt32(31)
2272
2.38k
                               : LLContext.getInt64(63);
2273
2.38k
        LLVM::Value RHS = Builder.createAnd(stackPop(), Mask);
2274
2.38k
        LLVM::Value LHS = stackPop();
2275
2.38k
        stackPush(Builder.createShl(LHS, RHS));
2276
2.38k
        break;
2277
2.04k
      }
2278
1.76k
      case OpCode::I32__shr_s:
2279
2.48k
      case OpCode::I64__shr_s: {
2280
2.48k
        LLVM::Value Mask = Instr.getOpCode() == OpCode::I32__shr_s
2281
2.48k
                               ? LLContext.getInt32(31)
2282
2.48k
                               : LLContext.getInt64(63);
2283
2.48k
        LLVM::Value RHS = Builder.createAnd(stackPop(), Mask);
2284
2.48k
        LLVM::Value LHS = stackPop();
2285
2.48k
        stackPush(Builder.createAShr(LHS, RHS));
2286
2.48k
        break;
2287
1.76k
      }
2288
5.07k
      case OpCode::I32__shr_u:
2289
5.36k
      case OpCode::I64__shr_u: {
2290
5.36k
        LLVM::Value Mask = Instr.getOpCode() == OpCode::I32__shr_u
2291
5.36k
                               ? LLContext.getInt32(31)
2292
5.36k
                               : LLContext.getInt64(63);
2293
5.36k
        LLVM::Value RHS = Builder.createAnd(stackPop(), Mask);
2294
5.36k
        LLVM::Value LHS = stackPop();
2295
5.36k
        stackPush(Builder.createLShr(LHS, RHS));
2296
5.36k
        break;
2297
5.07k
      }
2298
2.71k
      case OpCode::I32__rotl: {
2299
2.71k
        LLVM::Value RHS = stackPop();
2300
2.71k
        LLVM::Value LHS = stackPop();
2301
2.71k
        assuming(LLVM::Core::FShl != LLVM::Core::NotIntrinsic);
2302
2.71k
        stackPush(Builder.createIntrinsic(LLVM::Core::FShl, {Context.Int32Ty},
2303
2.71k
                                          {LHS, LHS, RHS}));
2304
2.71k
        break;
2305
2.71k
      }
2306
1.11k
      case OpCode::I32__rotr: {
2307
1.11k
        LLVM::Value RHS = stackPop();
2308
1.11k
        LLVM::Value LHS = stackPop();
2309
1.11k
        assuming(LLVM::Core::FShr != LLVM::Core::NotIntrinsic);
2310
1.11k
        stackPush(Builder.createIntrinsic(LLVM::Core::FShr, {Context.Int32Ty},
2311
1.11k
                                          {LHS, LHS, RHS}));
2312
1.11k
        break;
2313
1.11k
      }
2314
1.06k
      case OpCode::I64__rotl: {
2315
1.06k
        LLVM::Value RHS = stackPop();
2316
1.06k
        LLVM::Value LHS = stackPop();
2317
1.06k
        assuming(LLVM::Core::FShl != LLVM::Core::NotIntrinsic);
2318
1.06k
        stackPush(Builder.createIntrinsic(LLVM::Core::FShl, {Context.Int64Ty},
2319
1.06k
                                          {LHS, LHS, RHS}));
2320
1.06k
        break;
2321
1.06k
      }
2322
1.37k
      case OpCode::I64__rotr: {
2323
1.37k
        LLVM::Value RHS = stackPop();
2324
1.37k
        LLVM::Value LHS = stackPop();
2325
1.37k
        assuming(LLVM::Core::FShr != LLVM::Core::NotIntrinsic);
2326
1.37k
        stackPush(Builder.createIntrinsic(LLVM::Core::FShr, {Context.Int64Ty},
2327
1.37k
                                          {LHS, LHS, RHS}));
2328
1.37k
        break;
2329
1.37k
      }
2330
275
      case OpCode::F32__add:
2331
579
      case OpCode::F64__add: {
2332
579
        LLVM::Value RHS = stackPop();
2333
579
        LLVM::Value LHS = stackPop();
2334
579
        stackPush(Builder.createFAdd(LHS, RHS));
2335
579
        break;
2336
275
      }
2337
134
      case OpCode::F32__sub:
2338
427
      case OpCode::F64__sub: {
2339
427
        LLVM::Value RHS = stackPop();
2340
427
        LLVM::Value LHS = stackPop();
2341
427
        stackPush(Builder.createFSub(LHS, RHS));
2342
427
        break;
2343
134
      }
2344
548
      case OpCode::F32__mul:
2345
693
      case OpCode::F64__mul: {
2346
693
        LLVM::Value RHS = stackPop();
2347
693
        LLVM::Value LHS = stackPop();
2348
693
        stackPush(Builder.createFMul(LHS, RHS));
2349
693
        break;
2350
548
      }
2351
226
      case OpCode::F32__div:
2352
570
      case OpCode::F64__div: {
2353
570
        LLVM::Value RHS = stackPop();
2354
570
        LLVM::Value LHS = stackPop();
2355
570
        stackPush(Builder.createFDiv(LHS, RHS));
2356
570
        break;
2357
226
      }
2358
308
      case OpCode::F32__min:
2359
719
      case OpCode::F64__min: {
2360
719
        LLVM::Value RHS = stackPop();
2361
719
        LLVM::Value LHS = stackPop();
2362
719
        auto FpTy = Instr.getOpCode() == OpCode::F32__min ? Context.FloatTy
2363
719
                                                          : Context.DoubleTy;
2364
719
        auto IntTy = Instr.getOpCode() == OpCode::F32__min ? Context.Int32Ty
2365
719
                                                           : Context.Int64Ty;
2366
2367
719
        auto UEQ = Builder.createFCmpUEQ(LHS, RHS);
2368
719
        auto UNO = Builder.createFCmpUNO(LHS, RHS);
2369
2370
719
        auto LHSInt = Builder.createBitCast(LHS, IntTy);
2371
719
        auto RHSInt = Builder.createBitCast(RHS, IntTy);
2372
719
        auto OrInt = Builder.createOr(LHSInt, RHSInt);
2373
719
        auto OrFp = Builder.createBitCast(OrInt, FpTy);
2374
2375
719
        auto AddFp = Builder.createFAdd(LHS, RHS);
2376
2377
719
        assuming(LLVM::Core::MinNum != LLVM::Core::NotIntrinsic);
2378
719
        auto MinFp = Builder.createIntrinsic(LLVM::Core::MinNum,
2379
719
                                             {LHS.getType()}, {LHS, RHS});
2380
2381
719
        auto Ret = Builder.createSelect(
2382
719
            UEQ, Builder.createSelect(UNO, AddFp, OrFp), MinFp);
2383
719
        stackPush(Ret);
2384
719
        break;
2385
719
      }
2386
337
      case OpCode::F32__max:
2387
945
      case OpCode::F64__max: {
2388
945
        LLVM::Value RHS = stackPop();
2389
945
        LLVM::Value LHS = stackPop();
2390
945
        auto FpTy = Instr.getOpCode() == OpCode::F32__max ? Context.FloatTy
2391
945
                                                          : Context.DoubleTy;
2392
945
        auto IntTy = Instr.getOpCode() == OpCode::F32__max ? Context.Int32Ty
2393
945
                                                           : Context.Int64Ty;
2394
2395
945
        auto UEQ = Builder.createFCmpUEQ(LHS, RHS);
2396
945
        auto UNO = Builder.createFCmpUNO(LHS, RHS);
2397
2398
945
        auto LHSInt = Builder.createBitCast(LHS, IntTy);
2399
945
        auto RHSInt = Builder.createBitCast(RHS, IntTy);
2400
945
        auto AndInt = Builder.createAnd(LHSInt, RHSInt);
2401
945
        auto AndFp = Builder.createBitCast(AndInt, FpTy);
2402
2403
945
        auto AddFp = Builder.createFAdd(LHS, RHS);
2404
2405
945
        assuming(LLVM::Core::MaxNum != LLVM::Core::NotIntrinsic);
2406
945
        auto MaxFp = Builder.createIntrinsic(LLVM::Core::MaxNum,
2407
945
                                             {LHS.getType()}, {LHS, RHS});
2408
2409
945
        auto Ret = Builder.createSelect(
2410
945
            UEQ, Builder.createSelect(UNO, AddFp, AndFp), MaxFp);
2411
945
        stackPush(Ret);
2412
945
        break;
2413
945
      }
2414
532
      case OpCode::F32__copysign:
2415
935
      case OpCode::F64__copysign: {
2416
935
        LLVM::Value RHS = stackPop();
2417
935
        LLVM::Value LHS = stackPop();
2418
935
        assuming(LLVM::Core::CopySign != LLVM::Core::NotIntrinsic);
2419
935
        stackPush(Builder.createIntrinsic(LLVM::Core::CopySign, {LHS.getType()},
2420
935
                                          {LHS, RHS}));
2421
935
        break;
2422
935
      }
2423
2424
      // Saturating Truncation Numeric Instructions
2425
173
      case OpCode::I32__trunc_sat_f32_s:
2426
173
        compileSignedTruncSat(Context.Int32Ty);
2427
173
        break;
2428
98
      case OpCode::I32__trunc_sat_f32_u:
2429
98
        compileUnsignedTruncSat(Context.Int32Ty);
2430
98
        break;
2431
316
      case OpCode::I32__trunc_sat_f64_s:
2432
316
        compileSignedTruncSat(Context.Int32Ty);
2433
316
        break;
2434
172
      case OpCode::I32__trunc_sat_f64_u:
2435
172
        compileUnsignedTruncSat(Context.Int32Ty);
2436
172
        break;
2437
439
      case OpCode::I64__trunc_sat_f32_s:
2438
439
        compileSignedTruncSat(Context.Int64Ty);
2439
439
        break;
2440
376
      case OpCode::I64__trunc_sat_f32_u:
2441
376
        compileUnsignedTruncSat(Context.Int64Ty);
2442
376
        break;
2443
386
      case OpCode::I64__trunc_sat_f64_s:
2444
386
        compileSignedTruncSat(Context.Int64Ty);
2445
386
        break;
2446
411
      case OpCode::I64__trunc_sat_f64_u:
2447
411
        compileUnsignedTruncSat(Context.Int64Ty);
2448
411
        break;
2449
2450
      // SIMD Memory Instructions
2451
5.46k
      case OpCode::V128__load:
2452
5.46k
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2453
5.46k
                            Instr.getMemoryAlign(), Context.Int128x1Ty);
2454
5.46k
        break;
2455
147
      case OpCode::V128__load8x8_s:
2456
147
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2457
147
                            Instr.getMemoryAlign(),
2458
147
                            LLVM::Type::getVectorType(Context.Int8Ty, 8),
2459
147
                            Context.Int16x8Ty, true);
2460
147
        break;
2461
42
      case OpCode::V128__load8x8_u:
2462
42
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2463
42
                            Instr.getMemoryAlign(),
2464
42
                            LLVM::Type::getVectorType(Context.Int8Ty, 8),
2465
42
                            Context.Int16x8Ty, false);
2466
42
        break;
2467
356
      case OpCode::V128__load16x4_s:
2468
356
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2469
356
                            Instr.getMemoryAlign(),
2470
356
                            LLVM::Type::getVectorType(Context.Int16Ty, 4),
2471
356
                            Context.Int32x4Ty, true);
2472
356
        break;
2473
490
      case OpCode::V128__load16x4_u:
2474
490
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2475
490
                            Instr.getMemoryAlign(),
2476
490
                            LLVM::Type::getVectorType(Context.Int16Ty, 4),
2477
490
                            Context.Int32x4Ty, false);
2478
490
        break;
2479
170
      case OpCode::V128__load32x2_s:
2480
170
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2481
170
                            Instr.getMemoryAlign(),
2482
170
                            LLVM::Type::getVectorType(Context.Int32Ty, 2),
2483
170
                            Context.Int64x2Ty, true);
2484
170
        break;
2485
133
      case OpCode::V128__load32x2_u:
2486
133
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2487
133
                            Instr.getMemoryAlign(),
2488
133
                            LLVM::Type::getVectorType(Context.Int32Ty, 2),
2489
133
                            Context.Int64x2Ty, false);
2490
133
        break;
2491
69
      case OpCode::V128__load8_splat:
2492
69
        compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2493
69
                           Instr.getMemoryAlign(), Context.Int8Ty,
2494
69
                           Context.Int8x16Ty);
2495
69
        break;
2496
189
      case OpCode::V128__load16_splat:
2497
189
        compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2498
189
                           Instr.getMemoryAlign(), Context.Int16Ty,
2499
189
                           Context.Int16x8Ty);
2500
189
        break;
2501
201
      case OpCode::V128__load32_splat:
2502
201
        compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2503
201
                           Instr.getMemoryAlign(), Context.Int32Ty,
2504
201
                           Context.Int32x4Ty);
2505
201
        break;
2506
124
      case OpCode::V128__load64_splat:
2507
124
        compileSplatLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2508
124
                           Instr.getMemoryAlign(), Context.Int64Ty,
2509
124
                           Context.Int64x2Ty);
2510
124
        break;
2511
81
      case OpCode::V128__load32_zero:
2512
81
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2513
81
                            Instr.getMemoryAlign(), Context.Int32Ty,
2514
81
                            Context.Int128Ty, false);
2515
81
        break;
2516
146
      case OpCode::V128__load64_zero:
2517
146
        compileVectorLoadOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2518
146
                            Instr.getMemoryAlign(), Context.Int64Ty,
2519
146
                            Context.Int128Ty, false);
2520
146
        break;
2521
235
      case OpCode::V128__store:
2522
235
        compileStoreOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2523
235
                       Instr.getMemoryAlign(), Context.Int128x1Ty, false, true);
2524
235
        break;
2525
230
      case OpCode::V128__load8_lane:
2526
230
        compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2527
230
                          Instr.getMemoryAlign(), Instr.getMemoryLane(),
2528
230
                          Context.Int8Ty, Context.Int8x16Ty);
2529
230
        break;
2530
177
      case OpCode::V128__load16_lane:
2531
177
        compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2532
177
                          Instr.getMemoryAlign(), Instr.getMemoryLane(),
2533
177
                          Context.Int16Ty, Context.Int16x8Ty);
2534
177
        break;
2535
123
      case OpCode::V128__load32_lane:
2536
123
        compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2537
123
                          Instr.getMemoryAlign(), Instr.getMemoryLane(),
2538
123
                          Context.Int32Ty, Context.Int32x4Ty);
2539
123
        break;
2540
21
      case OpCode::V128__load64_lane:
2541
21
        compileLoadLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2542
21
                          Instr.getMemoryAlign(), Instr.getMemoryLane(),
2543
21
                          Context.Int64Ty, Context.Int64x2Ty);
2544
21
        break;
2545
135
      case OpCode::V128__store8_lane:
2546
135
        compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2547
135
                           Instr.getMemoryAlign(), Instr.getMemoryLane(),
2548
135
                           Context.Int8Ty, Context.Int8x16Ty);
2549
135
        break;
2550
63
      case OpCode::V128__store16_lane:
2551
63
        compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2552
63
                           Instr.getMemoryAlign(), Instr.getMemoryLane(),
2553
63
                           Context.Int16Ty, Context.Int16x8Ty);
2554
63
        break;
2555
142
      case OpCode::V128__store32_lane:
2556
142
        compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2557
142
                           Instr.getMemoryAlign(), Instr.getMemoryLane(),
2558
142
                           Context.Int32Ty, Context.Int32x4Ty);
2559
142
        break;
2560
35
      case OpCode::V128__store64_lane:
2561
35
        compileStoreLaneOp(Instr.getTargetIndex(), Instr.getMemoryOffset(),
2562
35
                           Instr.getMemoryAlign(), Instr.getMemoryLane(),
2563
35
                           Context.Int64Ty, Context.Int64x2Ty);
2564
35
        break;
2565
2566
      // SIMD Const Instructions
2567
372
      case OpCode::V128__const: {
2568
372
        const auto Value = Instr.getNum().get<uint64x2_t>();
2569
372
        auto Vector =
2570
372
            LLVM::Value::getConstVector64(LLContext, {Value[0], Value[1]});
2571
372
        stackPush(Builder.createBitCast(Vector, Context.Int64x2Ty));
2572
372
        break;
2573
935
      }
2574
2575
      // SIMD Shuffle Instructions
2576
16
      case OpCode::I8x16__shuffle: {
2577
16
        auto V2 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
2578
16
        auto V1 = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
2579
16
        const auto V3 = Instr.getNum().get<uint128_t>();
2580
16
        std::array<uint8_t, 16> Mask;
2581
272
        for (size_t I = 0; I < 16; ++I) {
2582
256
          auto Num = static_cast<uint8_t>(V3 >> (I * 8));
2583
256
          if constexpr (Endian::native == Endian::little) {
2584
256
            Mask[I] = Num;
2585
          } else {
2586
            Mask[15 - I] = Num < 16 ? 15 - Num : 47 - Num;
2587
          }
2588
256
        }
2589
16
        stackPush(Builder.createBitCast(
2590
16
            Builder.createShuffleVector(
2591
16
                V1, V2, LLVM::Value::getConstVector8(LLContext, Mask)),
2592
16
            Context.Int64x2Ty));
2593
16
        break;
2594
935
      }
2595
2596
      // SIMD Lane Instructions
2597
62
      case OpCode::I8x16__extract_lane_s:
2598
62
        compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
2599
62
                             Context.Int32Ty, true);
2600
62
        break;
2601
29
      case OpCode::I8x16__extract_lane_u:
2602
29
        compileExtractLaneOp(Context.Int8x16Ty, Instr.getMemoryLane(),
2603
29
                             Context.Int32Ty, false);
2604
29
        break;
2605
151
      case OpCode::I8x16__replace_lane:
2606
151
        compileReplaceLaneOp(Context.Int8x16Ty, Instr.getMemoryLane());
2607
151
        break;
2608
515
      case OpCode::I16x8__extract_lane_s:
2609
515
        compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
2610
515
                             Context.Int32Ty, true);
2611
515
        break;
2612
452
      case OpCode::I16x8__extract_lane_u:
2613
452
        compileExtractLaneOp(Context.Int16x8Ty, Instr.getMemoryLane(),
2614
452
                             Context.Int32Ty, false);
2615
452
        break;
2616
779
      case OpCode::I16x8__replace_lane:
2617
779
        compileReplaceLaneOp(Context.Int16x8Ty, Instr.getMemoryLane());
2618
779
        break;
2619
68
      case OpCode::I32x4__extract_lane:
2620
68
        compileExtractLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
2621
68
        break;
2622
218
      case OpCode::I32x4__replace_lane:
2623
218
        compileReplaceLaneOp(Context.Int32x4Ty, Instr.getMemoryLane());
2624
218
        break;
2625
157
      case OpCode::I64x2__extract_lane:
2626
157
        compileExtractLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
2627
157
        break;
2628
14
      case OpCode::I64x2__replace_lane:
2629
14
        compileReplaceLaneOp(Context.Int64x2Ty, Instr.getMemoryLane());
2630
14
        break;
2631
68
      case OpCode::F32x4__extract_lane:
2632
68
        compileExtractLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
2633
68
        break;
2634
24
      case OpCode::F32x4__replace_lane:
2635
24
        compileReplaceLaneOp(Context.Floatx4Ty, Instr.getMemoryLane());
2636
24
        break;
2637
72
      case OpCode::F64x2__extract_lane:
2638
72
        compileExtractLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
2639
72
        break;
2640
8
      case OpCode::F64x2__replace_lane:
2641
8
        compileReplaceLaneOp(Context.Doublex2Ty, Instr.getMemoryLane());
2642
8
        break;
2643
2644
      // SIMD Numeric Instructions
2645
65
      case OpCode::I8x16__swizzle:
2646
65
        compileVectorSwizzle();
2647
65
        break;
2648
39.4k
      case OpCode::I8x16__splat:
2649
39.4k
        compileSplatOp(Context.Int8x16Ty);
2650
39.4k
        break;
2651
9.85k
      case OpCode::I16x8__splat:
2652
9.85k
        compileSplatOp(Context.Int16x8Ty);
2653
9.85k
        break;
2654
1.47k
      case OpCode::I32x4__splat:
2655
1.47k
        compileSplatOp(Context.Int32x4Ty);
2656
1.47k
        break;
2657
686
      case OpCode::I64x2__splat:
2658
686
        compileSplatOp(Context.Int64x2Ty);
2659
686
        break;
2660
349
      case OpCode::F32x4__splat:
2661
349
        compileSplatOp(Context.Floatx4Ty);
2662
349
        break;
2663
66
      case OpCode::F64x2__splat:
2664
66
        compileSplatOp(Context.Doublex2Ty);
2665
66
        break;
2666
108
      case OpCode::I8x16__eq:
2667
108
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntEQ);
2668
108
        break;
2669
434
      case OpCode::I8x16__ne:
2670
434
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntNE);
2671
434
        break;
2672
71
      case OpCode::I8x16__lt_s:
2673
71
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLT);
2674
71
        break;
2675
73
      case OpCode::I8x16__lt_u:
2676
73
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULT);
2677
73
        break;
2678
149
      case OpCode::I8x16__gt_s:
2679
149
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGT);
2680
149
        break;
2681
241
      case OpCode::I8x16__gt_u:
2682
241
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGT);
2683
241
        break;
2684
114
      case OpCode::I8x16__le_s:
2685
114
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSLE);
2686
114
        break;
2687
108
      case OpCode::I8x16__le_u:
2688
108
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntULE);
2689
108
        break;
2690
936
      case OpCode::I8x16__ge_s:
2691
936
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntSGE);
2692
936
        break;
2693
122
      case OpCode::I8x16__ge_u:
2694
122
        compileVectorCompareOp(Context.Int8x16Ty, LLVMIntUGE);
2695
122
        break;
2696
86
      case OpCode::I16x8__eq:
2697
86
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntEQ);
2698
86
        break;
2699
237
      case OpCode::I16x8__ne:
2700
237
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntNE);
2701
237
        break;
2702
57
      case OpCode::I16x8__lt_s:
2703
57
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLT);
2704
57
        break;
2705
226
      case OpCode::I16x8__lt_u:
2706
226
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULT);
2707
226
        break;
2708
260
      case OpCode::I16x8__gt_s:
2709
260
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGT);
2710
260
        break;
2711
149
      case OpCode::I16x8__gt_u:
2712
149
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGT);
2713
149
        break;
2714
106
      case OpCode::I16x8__le_s:
2715
106
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSLE);
2716
106
        break;
2717
110
      case OpCode::I16x8__le_u:
2718
110
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntULE);
2719
110
        break;
2720
164
      case OpCode::I16x8__ge_s:
2721
164
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntSGE);
2722
164
        break;
2723
66
      case OpCode::I16x8__ge_u:
2724
66
        compileVectorCompareOp(Context.Int16x8Ty, LLVMIntUGE);
2725
66
        break;
2726
76
      case OpCode::I32x4__eq:
2727
76
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntEQ);
2728
76
        break;
2729
147
      case OpCode::I32x4__ne:
2730
147
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntNE);
2731
147
        break;
2732
63
      case OpCode::I32x4__lt_s:
2733
63
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLT);
2734
63
        break;
2735
154
      case OpCode::I32x4__lt_u:
2736
154
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULT);
2737
154
        break;
2738
128
      case OpCode::I32x4__gt_s:
2739
128
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGT);
2740
128
        break;
2741
276
      case OpCode::I32x4__gt_u:
2742
276
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGT);
2743
276
        break;
2744
279
      case OpCode::I32x4__le_s:
2745
279
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSLE);
2746
279
        break;
2747
271
      case OpCode::I32x4__le_u:
2748
271
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntULE);
2749
271
        break;
2750
85
      case OpCode::I32x4__ge_s:
2751
85
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntSGE);
2752
85
        break;
2753
109
      case OpCode::I32x4__ge_u:
2754
109
        compileVectorCompareOp(Context.Int32x4Ty, LLVMIntUGE);
2755
109
        break;
2756
102
      case OpCode::I64x2__eq:
2757
102
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntEQ);
2758
102
        break;
2759
54
      case OpCode::I64x2__ne:
2760
54
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntNE);
2761
54
        break;
2762
63
      case OpCode::I64x2__lt_s:
2763
63
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLT);
2764
63
        break;
2765
124
      case OpCode::I64x2__gt_s:
2766
124
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGT);
2767
124
        break;
2768
35
      case OpCode::I64x2__le_s:
2769
35
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSLE);
2770
35
        break;
2771
43
      case OpCode::I64x2__ge_s:
2772
43
        compileVectorCompareOp(Context.Int64x2Ty, LLVMIntSGE);
2773
43
        break;
2774
1.49k
      case OpCode::F32x4__eq:
2775
1.49k
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOEQ,
2776
1.49k
                               Context.Int32x4Ty);
2777
1.49k
        break;
2778
44
      case OpCode::F32x4__ne:
2779
44
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealUNE,
2780
44
                               Context.Int32x4Ty);
2781
44
        break;
2782
918
      case OpCode::F32x4__lt:
2783
918
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLT,
2784
918
                               Context.Int32x4Ty);
2785
918
        break;
2786
85
      case OpCode::F32x4__gt:
2787
85
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOGT,
2788
85
                               Context.Int32x4Ty);
2789
85
        break;
2790
339
      case OpCode::F32x4__le:
2791
339
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOLE,
2792
339
                               Context.Int32x4Ty);
2793
339
        break;
2794
97
      case OpCode::F32x4__ge:
2795
97
        compileVectorCompareOp(Context.Floatx4Ty, LLVMRealOGE,
2796
97
                               Context.Int32x4Ty);
2797
97
        break;
2798
57
      case OpCode::F64x2__eq:
2799
57
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOEQ,
2800
57
                               Context.Int64x2Ty);
2801
57
        break;
2802
115
      case OpCode::F64x2__ne:
2803
115
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealUNE,
2804
115
                               Context.Int64x2Ty);
2805
115
        break;
2806
138
      case OpCode::F64x2__lt:
2807
138
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLT,
2808
138
                               Context.Int64x2Ty);
2809
138
        break;
2810
56
      case OpCode::F64x2__gt:
2811
56
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGT,
2812
56
                               Context.Int64x2Ty);
2813
56
        break;
2814
166
      case OpCode::F64x2__le:
2815
166
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOLE,
2816
166
                               Context.Int64x2Ty);
2817
166
        break;
2818
86
      case OpCode::F64x2__ge:
2819
86
        compileVectorCompareOp(Context.Doublex2Ty, LLVMRealOGE,
2820
86
                               Context.Int64x2Ty);
2821
86
        break;
2822
132
      case OpCode::V128__not:
2823
132
        Stack.back() = Builder.createNot(Stack.back());
2824
132
        break;
2825
65
      case OpCode::V128__and: {
2826
65
        auto RHS = stackPop();
2827
65
        auto LHS = stackPop();
2828
65
        stackPush(Builder.createAnd(LHS, RHS));
2829
65
        break;
2830
935
      }
2831
83
      case OpCode::V128__andnot: {
2832
83
        auto RHS = stackPop();
2833
83
        auto LHS = stackPop();
2834
83
        stackPush(Builder.createAnd(LHS, Builder.createNot(RHS)));
2835
83
        break;
2836
935
      }
2837
113
      case OpCode::V128__or: {
2838
113
        auto RHS = stackPop();
2839
113
        auto LHS = stackPop();
2840
113
        stackPush(Builder.createOr(LHS, RHS));
2841
113
        break;
2842
935
      }
2843
51
      case OpCode::V128__xor: {
2844
51
        auto RHS = stackPop();
2845
51
        auto LHS = stackPop();
2846
51
        stackPush(Builder.createXor(LHS, RHS));
2847
51
        break;
2848
935
      }
2849
111
      case OpCode::V128__bitselect: {
2850
111
        auto C = stackPop();
2851
111
        auto V2 = stackPop();
2852
111
        auto V1 = stackPop();
2853
111
        stackPush(Builder.createXor(
2854
111
            Builder.createAnd(Builder.createXor(V1, V2), C), V2));
2855
111
        break;
2856
935
      }
2857
107
      case OpCode::V128__any_true:
2858
107
        compileVectorAnyTrue();
2859
107
        break;
2860
828
      case OpCode::I8x16__abs:
2861
828
        compileVectorAbs(Context.Int8x16Ty);
2862
828
        break;
2863
1.35k
      case OpCode::I8x16__neg:
2864
1.35k
        compileVectorNeg(Context.Int8x16Ty);
2865
1.35k
        break;
2866
157
      case OpCode::I8x16__popcnt:
2867
157
        compileVectorPopcnt();
2868
157
        break;
2869
323
      case OpCode::I8x16__all_true:
2870
323
        compileVectorAllTrue(Context.Int8x16Ty);
2871
323
        break;
2872
774
      case OpCode::I8x16__bitmask:
2873
774
        compileVectorBitMask(Context.Int8x16Ty);
2874
774
        break;
2875
84
      case OpCode::I8x16__narrow_i16x8_s:
2876
84
        compileVectorNarrow(Context.Int16x8Ty, true);
2877
84
        break;
2878
211
      case OpCode::I8x16__narrow_i16x8_u:
2879
211
        compileVectorNarrow(Context.Int16x8Ty, false);
2880
211
        break;
2881
232
      case OpCode::I8x16__shl:
2882
232
        compileVectorShl(Context.Int8x16Ty);
2883
232
        break;
2884
1.05k
      case OpCode::I8x16__shr_s:
2885
1.05k
        compileVectorAShr(Context.Int8x16Ty);
2886
1.05k
        break;
2887
83
      case OpCode::I8x16__shr_u:
2888
83
        compileVectorLShr(Context.Int8x16Ty);
2889
83
        break;
2890
51
      case OpCode::I8x16__add:
2891
51
        compileVectorVectorAdd(Context.Int8x16Ty);
2892
51
        break;
2893
1.00k
      case OpCode::I8x16__add_sat_s:
2894
1.00k
        compileVectorVectorAddSat(Context.Int8x16Ty, true);
2895
1.00k
        break;
2896
69
      case OpCode::I8x16__add_sat_u:
2897
69
        compileVectorVectorAddSat(Context.Int8x16Ty, false);
2898
69
        break;
2899
70
      case OpCode::I8x16__sub:
2900
70
        compileVectorVectorSub(Context.Int8x16Ty);
2901
70
        break;
2902
207
      case OpCode::I8x16__sub_sat_s:
2903
207
        compileVectorVectorSubSat(Context.Int8x16Ty, true);
2904
207
        break;
2905
93
      case OpCode::I8x16__sub_sat_u:
2906
93
        compileVectorVectorSubSat(Context.Int8x16Ty, false);
2907
93
        break;
2908
84
      case OpCode::I8x16__min_s:
2909
84
        compileVectorVectorSMin(Context.Int8x16Ty);
2910
84
        break;
2911
114
      case OpCode::I8x16__min_u:
2912
114
        compileVectorVectorUMin(Context.Int8x16Ty);
2913
114
        break;
2914
271
      case OpCode::I8x16__max_s:
2915
271
        compileVectorVectorSMax(Context.Int8x16Ty);
2916
271
        break;
2917
117
      case OpCode::I8x16__max_u:
2918
117
        compileVectorVectorUMax(Context.Int8x16Ty);
2919
117
        break;
2920
137
      case OpCode::I8x16__avgr_u:
2921
137
        compileVectorVectorUAvgr(Context.Int8x16Ty);
2922
137
        break;
2923
307
      case OpCode::I16x8__abs:
2924
307
        compileVectorAbs(Context.Int16x8Ty);
2925
307
        break;
2926
238
      case OpCode::I16x8__neg:
2927
238
        compileVectorNeg(Context.Int16x8Ty);
2928
238
        break;
2929
114
      case OpCode::I16x8__all_true:
2930
114
        compileVectorAllTrue(Context.Int16x8Ty);
2931
114
        break;
2932
102
      case OpCode::I16x8__bitmask:
2933
102
        compileVectorBitMask(Context.Int16x8Ty);
2934
102
        break;
2935
46
      case OpCode::I16x8__narrow_i32x4_s:
2936
46
        compileVectorNarrow(Context.Int32x4Ty, true);
2937
46
        break;
2938
358
      case OpCode::I16x8__narrow_i32x4_u:
2939
358
        compileVectorNarrow(Context.Int32x4Ty, false);
2940
358
        break;
2941
1.14k
      case OpCode::I16x8__extend_low_i8x16_s:
2942
1.14k
        compileVectorExtend(Context.Int8x16Ty, true, true);
2943
1.14k
        break;
2944
130
      case OpCode::I16x8__extend_high_i8x16_s:
2945
130
        compileVectorExtend(Context.Int8x16Ty, true, false);
2946
130
        break;
2947
478
      case OpCode::I16x8__extend_low_i8x16_u:
2948
478
        compileVectorExtend(Context.Int8x16Ty, false, true);
2949
478
        break;
2950
22
      case OpCode::I16x8__extend_high_i8x16_u:
2951
22
        compileVectorExtend(Context.Int8x16Ty, false, false);
2952
22
        break;
2953
85
      case OpCode::I16x8__shl:
2954
85
        compileVectorShl(Context.Int16x8Ty);
2955
85
        break;
2956
556
      case OpCode::I16x8__shr_s:
2957
556
        compileVectorAShr(Context.Int16x8Ty);
2958
556
        break;
2959
60
      case OpCode::I16x8__shr_u:
2960
60
        compileVectorLShr(Context.Int16x8Ty);
2961
60
        break;
2962
107
      case OpCode::I16x8__add:
2963
107
        compileVectorVectorAdd(Context.Int16x8Ty);
2964
107
        break;
2965
20
      case OpCode::I16x8__add_sat_s:
2966
20
        compileVectorVectorAddSat(Context.Int16x8Ty, true);
2967
20
        break;
2968
645
      case OpCode::I16x8__add_sat_u:
2969
645
        compileVectorVectorAddSat(Context.Int16x8Ty, false);
2970
645
        break;
2971
332
      case OpCode::I16x8__sub:
2972
332
        compileVectorVectorSub(Context.Int16x8Ty);
2973
332
        break;
2974
38
      case OpCode::I16x8__sub_sat_s:
2975
38
        compileVectorVectorSubSat(Context.Int16x8Ty, true);
2976
38
        break;
2977
65
      case OpCode::I16x8__sub_sat_u:
2978
65
        compileVectorVectorSubSat(Context.Int16x8Ty, false);
2979
65
        break;
2980
117
      case OpCode::I16x8__mul:
2981
117
        compileVectorVectorMul(Context.Int16x8Ty);
2982
117
        break;
2983
112
      case OpCode::I16x8__min_s:
2984
112
        compileVectorVectorSMin(Context.Int16x8Ty);
2985
112
        break;
2986
123
      case OpCode::I16x8__min_u:
2987
123
        compileVectorVectorUMin(Context.Int16x8Ty);
2988
123
        break;
2989
85
      case OpCode::I16x8__max_s:
2990
85
        compileVectorVectorSMax(Context.Int16x8Ty);
2991
85
        break;
2992
831
      case OpCode::I16x8__max_u:
2993
831
        compileVectorVectorUMax(Context.Int16x8Ty);
2994
831
        break;
2995
162
      case OpCode::I16x8__avgr_u:
2996
162
        compileVectorVectorUAvgr(Context.Int16x8Ty);
2997
162
        break;
2998
68
      case OpCode::I16x8__extmul_low_i8x16_s:
2999
68
        compileVectorExtMul(Context.Int8x16Ty, true, true);
3000
68
        break;
3001
212
      case OpCode::I16x8__extmul_high_i8x16_s:
3002
212
        compileVectorExtMul(Context.Int8x16Ty, true, false);
3003
212
        break;
3004
107
      case OpCode::I16x8__extmul_low_i8x16_u:
3005
107
        compileVectorExtMul(Context.Int8x16Ty, false, true);
3006
107
        break;
3007
434
      case OpCode::I16x8__extmul_high_i8x16_u:
3008
434
        compileVectorExtMul(Context.Int8x16Ty, false, false);
3009
434
        break;
3010
203
      case OpCode::I16x8__q15mulr_sat_s:
3011
203
        compileVectorVectorQ15MulSat();
3012
203
        break;
3013
276
      case OpCode::I16x8__extadd_pairwise_i8x16_s:
3014
276
        compileVectorExtAddPairwise(Context.Int8x16Ty, true);
3015
276
        break;
3016
330
      case OpCode::I16x8__extadd_pairwise_i8x16_u:
3017
330
        compileVectorExtAddPairwise(Context.Int8x16Ty, false);
3018
330
        break;
3019
69
      case OpCode::I32x4__abs:
3020
69
        compileVectorAbs(Context.Int32x4Ty);
3021
69
        break;
3022
200
      case OpCode::I32x4__neg:
3023
200
        compileVectorNeg(Context.Int32x4Ty);
3024
200
        break;
3025
201
      case OpCode::I32x4__all_true:
3026
201
        compileVectorAllTrue(Context.Int32x4Ty);
3027
201
        break;
3028
84
      case OpCode::I32x4__bitmask:
3029
84
        compileVectorBitMask(Context.Int32x4Ty);
3030
84
        break;
3031
119
      case OpCode::I32x4__extend_low_i16x8_s:
3032
119
        compileVectorExtend(Context.Int16x8Ty, true, true);
3033
119
        break;
3034
514
      case OpCode::I32x4__extend_high_i16x8_s:
3035
514
        compileVectorExtend(Context.Int16x8Ty, true, false);
3036
514
        break;
3037
1.90k
      case OpCode::I32x4__extend_low_i16x8_u:
3038
1.90k
        compileVectorExtend(Context.Int16x8Ty, false, true);
3039
1.90k
        break;
3040
139
      case OpCode::I32x4__extend_high_i16x8_u:
3041
139
        compileVectorExtend(Context.Int16x8Ty, false, false);
3042
139
        break;
3043
1.73k
      case OpCode::I32x4__shl:
3044
1.73k
        compileVectorShl(Context.Int32x4Ty);
3045
1.73k
        break;
3046
472
      case OpCode::I32x4__shr_s:
3047
472
        compileVectorAShr(Context.Int32x4Ty);
3048
472
        break;
3049
101
      case OpCode::I32x4__shr_u:
3050
101
        compileVectorLShr(Context.Int32x4Ty);
3051
101
        break;
3052
107
      case OpCode::I32x4__add:
3053
107
        compileVectorVectorAdd(Context.Int32x4Ty);
3054
107
        break;
3055
143
      case OpCode::I32x4__sub:
3056
143
        compileVectorVectorSub(Context.Int32x4Ty);
3057
143
        break;
3058
253
      case OpCode::I32x4__mul:
3059
253
        compileVectorVectorMul(Context.Int32x4Ty);
3060
253
        break;
3061
114
      case OpCode::I32x4__min_s:
3062
114
        compileVectorVectorSMin(Context.Int32x4Ty);
3063
114
        break;
3064
102
      case OpCode::I32x4__min_u:
3065
102
        compileVectorVectorUMin(Context.Int32x4Ty);
3066
102
        break;
3067
66
      case OpCode::I32x4__max_s:
3068
66
        compileVectorVectorSMax(Context.Int32x4Ty);
3069
66
        break;
3070
113
      case OpCode::I32x4__max_u:
3071
113
        compileVectorVectorUMax(Context.Int32x4Ty);
3072
113
        break;
3073
104
      case OpCode::I32x4__extmul_low_i16x8_s:
3074
104
        compileVectorExtMul(Context.Int16x8Ty, true, true);
3075
104
        break;
3076
49
      case OpCode::I32x4__extmul_high_i16x8_s:
3077
49
        compileVectorExtMul(Context.Int16x8Ty, true, false);
3078
49
        break;
3079
227
      case OpCode::I32x4__extmul_low_i16x8_u:
3080
227
        compileVectorExtMul(Context.Int16x8Ty, false, true);
3081
227
        break;
3082
60
      case OpCode::I32x4__extmul_high_i16x8_u:
3083
60
        compileVectorExtMul(Context.Int16x8Ty, false, false);
3084
60
        break;
3085
1.27k
      case OpCode::I32x4__extadd_pairwise_i16x8_s:
3086
1.27k
        compileVectorExtAddPairwise(Context.Int16x8Ty, true);
3087
1.27k
        break;
3088
544
      case OpCode::I32x4__extadd_pairwise_i16x8_u:
3089
544
        compileVectorExtAddPairwise(Context.Int16x8Ty, false);
3090
544
        break;
3091
111
      case OpCode::I32x4__dot_i16x8_s: {
3092
111
        auto ExtendTy = Context.Int16x8Ty.getExtendedElementVectorType();
3093
111
        auto Undef = LLVM::Value::getUndef(ExtendTy);
3094
111
        auto LHS = Builder.createSExt(
3095
111
            Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy);
3096
111
        auto RHS = Builder.createSExt(
3097
111
            Builder.createBitCast(stackPop(), Context.Int16x8Ty), ExtendTy);
3098
111
        auto M = Builder.createMul(LHS, RHS);
3099
111
        auto L = Builder.createShuffleVector(
3100
111
            M, Undef,
3101
111
            LLVM::Value::getConstVector32(LLContext, {0U, 2U, 4U, 6U}));
3102
111
        auto R = Builder.createShuffleVector(
3103
111
            M, Undef,
3104
111
            LLVM::Value::getConstVector32(LLContext, {1U, 3U, 5U, 7U}));
3105
111
        auto V = Builder.createAdd(L, R);
3106
111
        stackPush(Builder.createBitCast(V, Context.Int64x2Ty));
3107
111
        break;
3108
935
      }
3109
891
      case OpCode::I64x2__abs:
3110
891
        compileVectorAbs(Context.Int64x2Ty);
3111
891
        break;
3112
537
      case OpCode::I64x2__neg:
3113
537
        compileVectorNeg(Context.Int64x2Ty);
3114
537
        break;
3115
296
      case OpCode::I64x2__all_true:
3116
296
        compileVectorAllTrue(Context.Int64x2Ty);
3117
296
        break;
3118
267
      case OpCode::I64x2__bitmask:
3119
267
        compileVectorBitMask(Context.Int64x2Ty);
3120
267
        break;
3121
147
      case OpCode::I64x2__extend_low_i32x4_s:
3122
147
        compileVectorExtend(Context.Int32x4Ty, true, true);
3123
147
        break;
3124
687
      case OpCode::I64x2__extend_high_i32x4_s:
3125
687
        compileVectorExtend(Context.Int32x4Ty, true, false);
3126
687
        break;
3127
208
      case OpCode::I64x2__extend_low_i32x4_u:
3128
208
        compileVectorExtend(Context.Int32x4Ty, false, true);
3129
208
        break;
3130
596
      case OpCode::I64x2__extend_high_i32x4_u:
3131
596
        compileVectorExtend(Context.Int32x4Ty, false, false);
3132
596
        break;
3133
128
      case OpCode::I64x2__shl:
3134
128
        compileVectorShl(Context.Int64x2Ty);
3135
128
        break;
3136
373
      case OpCode::I64x2__shr_s:
3137
373
        compileVectorAShr(Context.Int64x2Ty);
3138
373
        break;
3139
92
      case OpCode::I64x2__shr_u:
3140
92
        compileVectorLShr(Context.Int64x2Ty);
3141
92
        break;
3142
43
      case OpCode::I64x2__add:
3143
43
        compileVectorVectorAdd(Context.Int64x2Ty);
3144
43
        break;
3145
263
      case OpCode::I64x2__sub:
3146
263
        compileVectorVectorSub(Context.Int64x2Ty);
3147
263
        break;
3148
87
      case OpCode::I64x2__mul:
3149
87
        compileVectorVectorMul(Context.Int64x2Ty);
3150
87
        break;
3151
51
      case OpCode::I64x2__extmul_low_i32x4_s:
3152
51
        compileVectorExtMul(Context.Int32x4Ty, true, true);
3153
51
        break;
3154
496
      case OpCode::I64x2__extmul_high_i32x4_s:
3155
496
        compileVectorExtMul(Context.Int32x4Ty, true, false);
3156
496
        break;
3157
30
      case OpCode::I64x2__extmul_low_i32x4_u:
3158
30
        compileVectorExtMul(Context.Int32x4Ty, false, true);
3159
30
        break;
3160
117
      case OpCode::I64x2__extmul_high_i32x4_u:
3161
117
        compileVectorExtMul(Context.Int32x4Ty, false, false);
3162
117
        break;
3163
125
      case OpCode::F32x4__abs:
3164
125
        compileVectorFAbs(Context.Floatx4Ty);
3165
125
        break;
3166
149
      case OpCode::F32x4__neg:
3167
149
        compileVectorFNeg(Context.Floatx4Ty);
3168
149
        break;
3169
195
      case OpCode::F32x4__sqrt:
3170
195
        compileVectorFSqrt(Context.Floatx4Ty);
3171
195
        break;
3172
131
      case OpCode::F32x4__add:
3173
131
        compileVectorVectorFAdd(Context.Floatx4Ty);
3174
131
        break;
3175
273
      case OpCode::F32x4__sub:
3176
273
        compileVectorVectorFSub(Context.Floatx4Ty);
3177
273
        break;
3178
40
      case OpCode::F32x4__mul:
3179
40
        compileVectorVectorFMul(Context.Floatx4Ty);
3180
40
        break;
3181
189
      case OpCode::F32x4__div:
3182
189
        compileVectorVectorFDiv(Context.Floatx4Ty);
3183
189
        break;
3184
126
      case OpCode::F32x4__min:
3185
126
        compileVectorVectorFMin(Context.Floatx4Ty);
3186
126
        break;
3187
36
      case OpCode::F32x4__max:
3188
36
        compileVectorVectorFMax(Context.Floatx4Ty);
3189
36
        break;
3190
54
      case OpCode::F32x4__pmin:
3191
54
        compileVectorVectorFPMin(Context.Floatx4Ty);
3192
54
        break;
3193
250
      case OpCode::F32x4__pmax:
3194
250
        compileVectorVectorFPMax(Context.Floatx4Ty);
3195
250
        break;
3196
691
      case OpCode::F32x4__ceil:
3197
691
        compileVectorFCeil(Context.Floatx4Ty);
3198
691
        break;
3199
1.58k
      case OpCode::F32x4__floor:
3200
1.58k
        compileVectorFFloor(Context.Floatx4Ty);
3201
1.58k
        break;
3202
1.51k
      case OpCode::F32x4__trunc:
3203
1.51k
        compileVectorFTrunc(Context.Floatx4Ty);
3204
1.51k
        break;
3205
192
      case OpCode::F32x4__nearest:
3206
192
        compileVectorFNearest(Context.Floatx4Ty);
3207
192
        break;
3208
440
      case OpCode::F64x2__abs:
3209
440
        compileVectorFAbs(Context.Doublex2Ty);
3210
440
        break;
3211
788
      case OpCode::F64x2__neg:
3212
788
        compileVectorFNeg(Context.Doublex2Ty);
3213
788
        break;
3214
150
      case OpCode::F64x2__sqrt:
3215
150
        compileVectorFSqrt(Context.Doublex2Ty);
3216
150
        break;
3217
50
      case OpCode::F64x2__add:
3218
50
        compileVectorVectorFAdd(Context.Doublex2Ty);
3219
50
        break;
3220
211
      case OpCode::F64x2__sub:
3221
211
        compileVectorVectorFSub(Context.Doublex2Ty);
3222
211
        break;
3223
143
      case OpCode::F64x2__mul:
3224
143
        compileVectorVectorFMul(Context.Doublex2Ty);
3225
143
        break;
3226
37
      case OpCode::F64x2__div:
3227
37
        compileVectorVectorFDiv(Context.Doublex2Ty);
3228
37
        break;
3229
163
      case OpCode::F64x2__min:
3230
163
        compileVectorVectorFMin(Context.Doublex2Ty);
3231
163
        break;
3232
159
      case OpCode::F64x2__max:
3233
159
        compileVectorVectorFMax(Context.Doublex2Ty);
3234
159
        break;
3235
322
      case OpCode::F64x2__pmin:
3236
322
        compileVectorVectorFPMin(Context.Doublex2Ty);
3237
322
        break;
3238
64
      case OpCode::F64x2__pmax:
3239
64
        compileVectorVectorFPMax(Context.Doublex2Ty);
3240
64
        break;
3241
494
      case OpCode::F64x2__ceil:
3242
494
        compileVectorFCeil(Context.Doublex2Ty);
3243
494
        break;
3244
595
      case OpCode::F64x2__floor:
3245
595
        compileVectorFFloor(Context.Doublex2Ty);
3246
595
        break;
3247
117
      case OpCode::F64x2__trunc:
3248
117
        compileVectorFTrunc(Context.Doublex2Ty);
3249
117
        break;
3250
152
      case OpCode::F64x2__nearest:
3251
152
        compileVectorFNearest(Context.Doublex2Ty);
3252
152
        break;
3253
262
      case OpCode::I32x4__trunc_sat_f32x4_s:
3254
262
        compileVectorTruncSatS32(Context.Floatx4Ty, false);
3255
262
        break;
3256
3.70k
      case OpCode::I32x4__trunc_sat_f32x4_u:
3257
3.70k
        compileVectorTruncSatU32(Context.Floatx4Ty, false);
3258
3.70k
        break;
3259
323
      case OpCode::F32x4__convert_i32x4_s:
3260
323
        compileVectorConvertS(Context.Int32x4Ty, Context.Floatx4Ty, false);
3261
323
        break;
3262
742
      case OpCode::F32x4__convert_i32x4_u:
3263
742
        compileVectorConvertU(Context.Int32x4Ty, Context.Floatx4Ty, false);
3264
742
        break;
3265
745
      case OpCode::I32x4__trunc_sat_f64x2_s_zero:
3266
745
        compileVectorTruncSatS32(Context.Doublex2Ty, true);
3267
745
        break;
3268
2.13k
      case OpCode::I32x4__trunc_sat_f64x2_u_zero:
3269
2.13k
        compileVectorTruncSatU32(Context.Doublex2Ty, true);
3270
2.13k
        break;
3271
331
      case OpCode::F64x2__convert_low_i32x4_s:
3272
331
        compileVectorConvertS(Context.Int32x4Ty, Context.Doublex2Ty, true);
3273
331
        break;
3274
1.31k
      case OpCode::F64x2__convert_low_i32x4_u:
3275
1.31k
        compileVectorConvertU(Context.Int32x4Ty, Context.Doublex2Ty, true);
3276
1.31k
        break;
3277
527
      case OpCode::F32x4__demote_f64x2_zero:
3278
527
        compileVectorDemote();
3279
527
        break;
3280
599
      case OpCode::F64x2__promote_low_f32x4:
3281
599
        compileVectorPromote();
3282
599
        break;
3283
3284
      // Relaxed SIMD Instructions
3285
0
      case OpCode::I8x16__relaxed_swizzle:
3286
0
        compileVectorSwizzle();
3287
0
        break;
3288
0
      case OpCode::I32x4__relaxed_trunc_f32x4_s:
3289
0
        compileVectorTruncSatS32(Context.Floatx4Ty, false);
3290
0
        break;
3291
0
      case OpCode::I32x4__relaxed_trunc_f32x4_u:
3292
0
        compileVectorTruncSatU32(Context.Floatx4Ty, false);
3293
0
        break;
3294
0
      case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
3295
0
        compileVectorTruncSatS32(Context.Doublex2Ty, true);
3296
0
        break;
3297
0
      case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
3298
0
        compileVectorTruncSatU32(Context.Doublex2Ty, true);
3299
0
        break;
3300
0
      case OpCode::F32x4__relaxed_madd:
3301
0
        compileVectorVectorMAdd(Context.Floatx4Ty);
3302
0
        break;
3303
0
      case OpCode::F32x4__relaxed_nmadd:
3304
0
        compileVectorVectorNMAdd(Context.Floatx4Ty);
3305
0
        break;
3306
0
      case OpCode::F64x2__relaxed_madd:
3307
0
        compileVectorVectorMAdd(Context.Doublex2Ty);
3308
0
        break;
3309
0
      case OpCode::F64x2__relaxed_nmadd:
3310
0
        compileVectorVectorNMAdd(Context.Doublex2Ty);
3311
0
        break;
3312
0
      case OpCode::I8x16__relaxed_laneselect:
3313
0
      case OpCode::I16x8__relaxed_laneselect:
3314
0
      case OpCode::I32x4__relaxed_laneselect:
3315
0
      case OpCode::I64x2__relaxed_laneselect: {
3316
0
        auto C = stackPop();
3317
0
        auto V2 = stackPop();
3318
0
        auto V1 = stackPop();
3319
0
        stackPush(Builder.createXor(
3320
0
            Builder.createAnd(Builder.createXor(V1, V2), C), V2));
3321
0
        break;
3322
0
      }
3323
0
      case OpCode::F32x4__relaxed_min:
3324
0
        compileVectorVectorFMin(Context.Floatx4Ty);
3325
0
        break;
3326
0
      case OpCode::F32x4__relaxed_max:
3327
0
        compileVectorVectorFMax(Context.Floatx4Ty);
3328
0
        break;
3329
0
      case OpCode::F64x2__relaxed_min:
3330
0
        compileVectorVectorFMin(Context.Doublex2Ty);
3331
0
        break;
3332
0
      case OpCode::F64x2__relaxed_max:
3333
0
        compileVectorVectorFMax(Context.Doublex2Ty);
3334
0
        break;
3335
0
      case OpCode::I16x8__relaxed_q15mulr_s:
3336
0
        compileVectorVectorQ15MulSat();
3337
0
        break;
3338
0
      case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
3339
0
        compileVectorRelaxedIntegerDotProduct();
3340
0
        break;
3341
0
      case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
3342
0
        compileVectorRelaxedIntegerDotProductAdd();
3343
0
        break;
3344
3345
      // Atomic Instructions
3346
188
      case OpCode::Atomic__fence:
3347
188
        return compileMemoryFence();
3348
34
      case OpCode::Memory__atomic__notify:
3349
34
        return compileAtomicNotify(Instr.getTargetIndex(),
3350
34
                                   Instr.getMemoryOffset());
3351
5
      case OpCode::Memory__atomic__wait32:
3352
5
        return compileAtomicWait(Instr.getTargetIndex(),
3353
5
                                 Instr.getMemoryOffset(), Context.Int32Ty, 32);
3354
2
      case OpCode::Memory__atomic__wait64:
3355
2
        return compileAtomicWait(Instr.getTargetIndex(),
3356
2
                                 Instr.getMemoryOffset(), Context.Int64Ty, 64);
3357
0
      case OpCode::I32__atomic__load:
3358
0
        return compileAtomicLoad(
3359
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3360
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int32Ty, true);
3361
0
      case OpCode::I64__atomic__load:
3362
0
        return compileAtomicLoad(
3363
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3364
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int64Ty, true);
3365
0
      case OpCode::I32__atomic__load8_u:
3366
0
        return compileAtomicLoad(
3367
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3368
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int8Ty);
3369
0
      case OpCode::I32__atomic__load16_u:
3370
0
        return compileAtomicLoad(
3371
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3372
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int16Ty);
3373
0
      case OpCode::I64__atomic__load8_u:
3374
0
        return compileAtomicLoad(
3375
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3376
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int8Ty);
3377
0
      case OpCode::I64__atomic__load16_u:
3378
0
        return compileAtomicLoad(
3379
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3380
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int16Ty);
3381
0
      case OpCode::I64__atomic__load32_u:
3382
0
        return compileAtomicLoad(
3383
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3384
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int32Ty);
3385
0
      case OpCode::I32__atomic__store:
3386
0
        return compileAtomicStore(
3387
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3388
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int32Ty, true);
3389
0
      case OpCode::I64__atomic__store:
3390
0
        return compileAtomicStore(
3391
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3392
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int64Ty, true);
3393
0
      case OpCode::I32__atomic__store8:
3394
0
        return compileAtomicStore(
3395
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3396
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int8Ty, true);
3397
0
      case OpCode::I32__atomic__store16:
3398
0
        return compileAtomicStore(
3399
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3400
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int16Ty, true);
3401
0
      case OpCode::I64__atomic__store8:
3402
0
        return compileAtomicStore(
3403
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3404
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int8Ty, true);
3405
0
      case OpCode::I64__atomic__store16:
3406
0
        return compileAtomicStore(
3407
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3408
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int16Ty, true);
3409
0
      case OpCode::I64__atomic__store32:
3410
0
        return compileAtomicStore(
3411
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3412
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int32Ty, true);
3413
0
      case OpCode::I32__atomic__rmw__add:
3414
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3415
0
                                  Instr.getMemoryOffset(),
3416
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3417
0
                                  Context.Int32Ty, Context.Int32Ty, true);
3418
0
      case OpCode::I64__atomic__rmw__add:
3419
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3420
0
                                  Instr.getMemoryOffset(),
3421
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3422
0
                                  Context.Int64Ty, Context.Int64Ty, true);
3423
0
      case OpCode::I32__atomic__rmw8__add_u:
3424
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3425
0
                                  Instr.getMemoryOffset(),
3426
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3427
0
                                  Context.Int32Ty, Context.Int8Ty);
3428
0
      case OpCode::I32__atomic__rmw16__add_u:
3429
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3430
0
                                  Instr.getMemoryOffset(),
3431
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3432
0
                                  Context.Int32Ty, Context.Int16Ty);
3433
0
      case OpCode::I64__atomic__rmw8__add_u:
3434
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3435
0
                                  Instr.getMemoryOffset(),
3436
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3437
0
                                  Context.Int64Ty, Context.Int8Ty);
3438
0
      case OpCode::I64__atomic__rmw16__add_u:
3439
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3440
0
                                  Instr.getMemoryOffset(),
3441
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3442
0
                                  Context.Int64Ty, Context.Int16Ty);
3443
0
      case OpCode::I64__atomic__rmw32__add_u:
3444
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3445
0
                                  Instr.getMemoryOffset(),
3446
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAdd,
3447
0
                                  Context.Int64Ty, Context.Int32Ty);
3448
0
      case OpCode::I32__atomic__rmw__sub:
3449
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3450
0
                                  Instr.getMemoryOffset(),
3451
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3452
0
                                  Context.Int32Ty, Context.Int32Ty, true);
3453
0
      case OpCode::I64__atomic__rmw__sub:
3454
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3455
0
                                  Instr.getMemoryOffset(),
3456
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3457
0
                                  Context.Int64Ty, Context.Int64Ty, true);
3458
0
      case OpCode::I32__atomic__rmw8__sub_u:
3459
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3460
0
                                  Instr.getMemoryOffset(),
3461
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3462
0
                                  Context.Int32Ty, Context.Int8Ty);
3463
0
      case OpCode::I32__atomic__rmw16__sub_u:
3464
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3465
0
                                  Instr.getMemoryOffset(),
3466
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3467
0
                                  Context.Int32Ty, Context.Int16Ty);
3468
0
      case OpCode::I64__atomic__rmw8__sub_u:
3469
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3470
0
                                  Instr.getMemoryOffset(),
3471
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3472
0
                                  Context.Int64Ty, Context.Int8Ty);
3473
0
      case OpCode::I64__atomic__rmw16__sub_u:
3474
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3475
0
                                  Instr.getMemoryOffset(),
3476
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3477
0
                                  Context.Int64Ty, Context.Int16Ty);
3478
0
      case OpCode::I64__atomic__rmw32__sub_u:
3479
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3480
0
                                  Instr.getMemoryOffset(),
3481
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpSub,
3482
0
                                  Context.Int64Ty, Context.Int32Ty);
3483
0
      case OpCode::I32__atomic__rmw__and:
3484
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3485
0
                                  Instr.getMemoryOffset(),
3486
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3487
0
                                  Context.Int32Ty, Context.Int32Ty, true);
3488
0
      case OpCode::I64__atomic__rmw__and:
3489
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3490
0
                                  Instr.getMemoryOffset(),
3491
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3492
0
                                  Context.Int64Ty, Context.Int64Ty, true);
3493
0
      case OpCode::I32__atomic__rmw8__and_u:
3494
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3495
0
                                  Instr.getMemoryOffset(),
3496
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3497
0
                                  Context.Int32Ty, Context.Int8Ty);
3498
0
      case OpCode::I32__atomic__rmw16__and_u:
3499
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3500
0
                                  Instr.getMemoryOffset(),
3501
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3502
0
                                  Context.Int32Ty, Context.Int16Ty);
3503
0
      case OpCode::I64__atomic__rmw8__and_u:
3504
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3505
0
                                  Instr.getMemoryOffset(),
3506
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3507
0
                                  Context.Int64Ty, Context.Int8Ty);
3508
0
      case OpCode::I64__atomic__rmw16__and_u:
3509
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3510
0
                                  Instr.getMemoryOffset(),
3511
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3512
0
                                  Context.Int64Ty, Context.Int16Ty);
3513
0
      case OpCode::I64__atomic__rmw32__and_u:
3514
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3515
0
                                  Instr.getMemoryOffset(),
3516
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpAnd,
3517
0
                                  Context.Int64Ty, Context.Int32Ty);
3518
0
      case OpCode::I32__atomic__rmw__or:
3519
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3520
0
                                  Instr.getMemoryOffset(),
3521
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3522
0
                                  Context.Int32Ty, Context.Int32Ty, true);
3523
0
      case OpCode::I64__atomic__rmw__or:
3524
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3525
0
                                  Instr.getMemoryOffset(),
3526
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3527
0
                                  Context.Int64Ty, Context.Int64Ty, true);
3528
0
      case OpCode::I32__atomic__rmw8__or_u:
3529
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3530
0
                                  Instr.getMemoryOffset(),
3531
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3532
0
                                  Context.Int32Ty, Context.Int8Ty);
3533
0
      case OpCode::I32__atomic__rmw16__or_u:
3534
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3535
0
                                  Instr.getMemoryOffset(),
3536
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3537
0
                                  Context.Int32Ty, Context.Int16Ty);
3538
0
      case OpCode::I64__atomic__rmw8__or_u:
3539
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3540
0
                                  Instr.getMemoryOffset(),
3541
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3542
0
                                  Context.Int64Ty, Context.Int8Ty);
3543
0
      case OpCode::I64__atomic__rmw16__or_u:
3544
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3545
0
                                  Instr.getMemoryOffset(),
3546
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3547
0
                                  Context.Int64Ty, Context.Int16Ty);
3548
0
      case OpCode::I64__atomic__rmw32__or_u:
3549
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3550
0
                                  Instr.getMemoryOffset(),
3551
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpOr,
3552
0
                                  Context.Int64Ty, Context.Int32Ty);
3553
0
      case OpCode::I32__atomic__rmw__xor:
3554
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3555
0
                                  Instr.getMemoryOffset(),
3556
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3557
0
                                  Context.Int32Ty, Context.Int32Ty, true);
3558
0
      case OpCode::I64__atomic__rmw__xor:
3559
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3560
0
                                  Instr.getMemoryOffset(),
3561
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3562
0
                                  Context.Int64Ty, Context.Int64Ty, true);
3563
0
      case OpCode::I32__atomic__rmw8__xor_u:
3564
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3565
0
                                  Instr.getMemoryOffset(),
3566
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3567
0
                                  Context.Int32Ty, Context.Int8Ty);
3568
0
      case OpCode::I32__atomic__rmw16__xor_u:
3569
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3570
0
                                  Instr.getMemoryOffset(),
3571
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3572
0
                                  Context.Int32Ty, Context.Int16Ty);
3573
0
      case OpCode::I64__atomic__rmw8__xor_u:
3574
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3575
0
                                  Instr.getMemoryOffset(),
3576
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3577
0
                                  Context.Int64Ty, Context.Int8Ty);
3578
0
      case OpCode::I64__atomic__rmw16__xor_u:
3579
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3580
0
                                  Instr.getMemoryOffset(),
3581
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3582
0
                                  Context.Int64Ty, Context.Int16Ty);
3583
0
      case OpCode::I64__atomic__rmw32__xor_u:
3584
0
        return compileAtomicRMWOp(Instr.getTargetIndex(),
3585
0
                                  Instr.getMemoryOffset(),
3586
0
                                  Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXor,
3587
0
                                  Context.Int64Ty, Context.Int32Ty);
3588
0
      case OpCode::I32__atomic__rmw__xchg:
3589
0
        return compileAtomicRMWOp(
3590
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3591
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int32Ty,
3592
0
            Context.Int32Ty, true);
3593
0
      case OpCode::I64__atomic__rmw__xchg:
3594
0
        return compileAtomicRMWOp(
3595
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3596
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int64Ty,
3597
0
            Context.Int64Ty, true);
3598
0
      case OpCode::I32__atomic__rmw8__xchg_u:
3599
0
        return compileAtomicRMWOp(
3600
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3601
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int32Ty,
3602
0
            Context.Int8Ty);
3603
0
      case OpCode::I32__atomic__rmw16__xchg_u:
3604
0
        return compileAtomicRMWOp(
3605
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3606
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int32Ty,
3607
0
            Context.Int16Ty);
3608
0
      case OpCode::I64__atomic__rmw8__xchg_u:
3609
0
        return compileAtomicRMWOp(
3610
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3611
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int64Ty,
3612
0
            Context.Int8Ty);
3613
0
      case OpCode::I64__atomic__rmw16__xchg_u:
3614
0
        return compileAtomicRMWOp(
3615
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3616
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int64Ty,
3617
0
            Context.Int16Ty);
3618
0
      case OpCode::I64__atomic__rmw32__xchg_u:
3619
0
        return compileAtomicRMWOp(
3620
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3621
0
            Instr.getMemoryAlign(), LLVMAtomicRMWBinOpXchg, Context.Int64Ty,
3622
0
            Context.Int32Ty);
3623
0
      case OpCode::I32__atomic__rmw__cmpxchg:
3624
0
        return compileAtomicCompareExchange(
3625
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3626
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int32Ty, true);
3627
0
      case OpCode::I64__atomic__rmw__cmpxchg:
3628
0
        return compileAtomicCompareExchange(
3629
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3630
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int64Ty, true);
3631
0
      case OpCode::I32__atomic__rmw8__cmpxchg_u:
3632
0
        return compileAtomicCompareExchange(
3633
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3634
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int8Ty);
3635
0
      case OpCode::I32__atomic__rmw16__cmpxchg_u:
3636
0
        return compileAtomicCompareExchange(
3637
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3638
0
            Instr.getMemoryAlign(), Context.Int32Ty, Context.Int16Ty);
3639
0
      case OpCode::I64__atomic__rmw8__cmpxchg_u:
3640
0
        return compileAtomicCompareExchange(
3641
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3642
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int8Ty);
3643
0
      case OpCode::I64__atomic__rmw16__cmpxchg_u:
3644
0
        return compileAtomicCompareExchange(
3645
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3646
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int16Ty);
3647
0
      case OpCode::I64__atomic__rmw32__cmpxchg_u:
3648
0
        return compileAtomicCompareExchange(
3649
0
            Instr.getTargetIndex(), Instr.getMemoryOffset(),
3650
0
            Instr.getMemoryAlign(), Context.Int64Ty, Context.Int32Ty);
3651
3652
0
      default:
3653
0
        assumingUnreachable();
3654
1.10M
      }
3655
1.10M
      return;
3656
1.10M
    };
3657
1.56M
    for (const auto &Instr : Instrs) {
3658
      // Update instruction count
3659
1.56M
      if (LocalInstrCount) {
3660
0
        Builder.createStore(
3661
0
            Builder.createAdd(
3662
0
                Builder.createLoad(Context.Int64Ty, LocalInstrCount),
3663
0
                LLContext.getInt64(1)),
3664
0
            LocalInstrCount);
3665
0
      }
3666
1.56M
      if (LocalGas) {
3667
0
        auto NewGas = Builder.createAdd(
3668
0
            Builder.createLoad(Context.Int64Ty, LocalGas),
3669
0
            Builder.createLoad(
3670
0
                Context.Int64Ty,
3671
0
                Builder.createConstInBoundsGEP2_64(
3672
0
                    LLVM::Type::getArrayType(Context.Int64Ty, UINT16_MAX + 1),
3673
0
                    Context.getCostTable(Builder, ExecCtx), 0,
3674
0
                    uint16_t(Instr.getOpCode()))));
3675
0
        Builder.createStore(NewGas, LocalGas);
3676
0
      }
3677
3678
      // Make the instruction node according to Code.
3679
1.56M
      Dispatch(Instr);
3680
1.56M
    }
3681
10.7k
  }
3682
2.14k
  void compileSignedTrunc(LLVM::Type IntType) noexcept {
3683
2.14k
    auto NormBB = LLVM::BasicBlock::create(LLContext, F.Fn, "strunc.norm");
3684
2.14k
    auto NotMinBB = LLVM::BasicBlock::create(LLContext, F.Fn, "strunc.notmin");
3685
2.14k
    auto NotMaxBB = LLVM::BasicBlock::create(LLContext, F.Fn, "strunc.notmax");
3686
2.14k
    auto Value = stackPop();
3687
2.14k
    const auto [Precise, MinFp, MaxFp] =
3688
2.14k
        [IntType, Value]() -> std::tuple<bool, LLVM::Value, LLVM::Value> {
3689
2.14k
      const auto BitWidth = IntType.getIntegerBitWidth();
3690
2.14k
      const auto [Min, Max] = [BitWidth]() -> std::tuple<int64_t, int64_t> {
3691
2.14k
        switch (BitWidth) {
3692
1.67k
        case 32:
3693
1.67k
          return {std::numeric_limits<int32_t>::min(),
3694
1.67k
                  std::numeric_limits<int32_t>::max()};
3695
474
        case 64:
3696
474
          return {std::numeric_limits<int64_t>::min(),
3697
474
                  std::numeric_limits<int64_t>::max()};
3698
0
        default:
3699
0
          assumingUnreachable();
3700
2.14k
        }
3701
2.14k
      }();
3702
2.14k
      auto FPType = Value.getType();
3703
2.14k
      assuming(FPType.isFloatTy() || FPType.isDoubleTy());
3704
2.14k
      const auto FPWidth = FPType.getFPMantissaWidth();
3705
2.14k
      return {BitWidth <= FPWidth, LLVM::Value::getConstReal(FPType, Min),
3706
2.14k
              LLVM::Value::getConstReal(FPType, Max)};
3707
2.14k
    }();
3708
3709
2.14k
    auto IsNotNan = Builder.createLikely(Builder.createFCmpORD(Value, Value));
3710
2.14k
    Builder.createCondBr(IsNotNan, NormBB,
3711
2.14k
                         getTrapBB(ErrCode::Value::InvalidConvToInt));
3712
3713
2.14k
    Builder.positionAtEnd(NormBB);
3714
2.14k
    assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
3715
2.14k
    auto Trunc = Builder.createUnaryIntrinsic(LLVM::Core::Trunc, Value);
3716
2.14k
    auto IsNotUnderflow =
3717
2.14k
        Builder.createLikely(Builder.createFCmpOGE(Trunc, MinFp));
3718
2.14k
    Builder.createCondBr(IsNotUnderflow, NotMinBB,
3719
2.14k
                         getTrapBB(ErrCode::Value::IntegerOverflow));
3720
3721
2.14k
    Builder.positionAtEnd(NotMinBB);
3722
2.14k
    auto IsNotOverflow = Builder.createLikely(
3723
2.14k
        Builder.createFCmp(Precise ? LLVMRealOLE : LLVMRealOLT, Trunc, MaxFp));
3724
2.14k
    Builder.createCondBr(IsNotOverflow, NotMaxBB,
3725
2.14k
                         getTrapBB(ErrCode::Value::IntegerOverflow));
3726
3727
2.14k
    Builder.positionAtEnd(NotMaxBB);
3728
2.14k
    stackPush(Builder.createFPToSI(Trunc, IntType));
3729
2.14k
  }
3730
1.31k
  void compileSignedTruncSat(LLVM::Type IntType) noexcept {
3731
1.31k
    auto CurrBB = Builder.getInsertBlock();
3732
1.31k
    auto NormBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ssat.norm");
3733
1.31k
    auto NotMinBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ssat.notmin");
3734
1.31k
    auto NotMaxBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ssat.notmax");
3735
1.31k
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ssat.end");
3736
1.31k
    auto Value = stackPop();
3737
1.31k
    const auto [Precise, MinInt, MaxInt, MinFp, MaxFp] = [IntType, Value]()
3738
1.31k
        -> std::tuple<bool, uint64_t, uint64_t, LLVM::Value, LLVM::Value> {
3739
1.31k
      const auto BitWidth = IntType.getIntegerBitWidth();
3740
1.31k
      const auto [Min, Max] = [BitWidth]() -> std::tuple<int64_t, int64_t> {
3741
1.31k
        switch (BitWidth) {
3742
489
        case 32:
3743
489
          return {std::numeric_limits<int32_t>::min(),
3744
489
                  std::numeric_limits<int32_t>::max()};
3745
825
        case 64:
3746
825
          return {std::numeric_limits<int64_t>::min(),
3747
825
                  std::numeric_limits<int64_t>::max()};
3748
0
        default:
3749
0
          assumingUnreachable();
3750
1.31k
        }
3751
1.31k
      }();
3752
1.31k
      auto FPType = Value.getType();
3753
1.31k
      assuming(FPType.isFloatTy() || FPType.isDoubleTy());
3754
1.31k
      const auto FPWidth = FPType.getFPMantissaWidth();
3755
1.31k
      return {BitWidth <= FPWidth, static_cast<uint64_t>(Min),
3756
1.31k
              static_cast<uint64_t>(Max),
3757
1.31k
              LLVM::Value::getConstReal(FPType, Min),
3758
1.31k
              LLVM::Value::getConstReal(FPType, Max)};
3759
1.31k
    }();
3760
3761
1.31k
    auto IsNotNan = Builder.createLikely(Builder.createFCmpORD(Value, Value));
3762
1.31k
    Builder.createCondBr(IsNotNan, NormBB, EndBB);
3763
3764
1.31k
    Builder.positionAtEnd(NormBB);
3765
1.31k
    assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
3766
1.31k
    auto Trunc = Builder.createUnaryIntrinsic(LLVM::Core::Trunc, Value);
3767
1.31k
    auto IsNotUnderflow =
3768
1.31k
        Builder.createLikely(Builder.createFCmpOGE(Trunc, MinFp));
3769
1.31k
    Builder.createCondBr(IsNotUnderflow, NotMinBB, EndBB);
3770
3771
1.31k
    Builder.positionAtEnd(NotMinBB);
3772
1.31k
    auto IsNotOverflow = Builder.createLikely(
3773
1.31k
        Builder.createFCmp(Precise ? LLVMRealOLE : LLVMRealOLT, Trunc, MaxFp));
3774
1.31k
    Builder.createCondBr(IsNotOverflow, NotMaxBB, EndBB);
3775
3776
1.31k
    Builder.positionAtEnd(NotMaxBB);
3777
1.31k
    auto IntValue = Builder.createFPToSI(Trunc, IntType);
3778
1.31k
    Builder.createBr(EndBB);
3779
3780
1.31k
    Builder.positionAtEnd(EndBB);
3781
1.31k
    auto PHIRet = Builder.createPHI(IntType);
3782
1.31k
    PHIRet.addIncoming(LLVM::Value::getConstInt(IntType, 0, true), CurrBB);
3783
1.31k
    PHIRet.addIncoming(LLVM::Value::getConstInt(IntType, MinInt, true), NormBB);
3784
1.31k
    PHIRet.addIncoming(LLVM::Value::getConstInt(IntType, MaxInt, true),
3785
1.31k
                       NotMinBB);
3786
1.31k
    PHIRet.addIncoming(IntValue, NotMaxBB);
3787
3788
1.31k
    stackPush(PHIRet);
3789
1.31k
  }
3790
3.92k
  void compileUnsignedTrunc(LLVM::Type IntType) noexcept {
3791
3.92k
    auto NormBB = LLVM::BasicBlock::create(LLContext, F.Fn, "utrunc.norm");
3792
3.92k
    auto NotMinBB = LLVM::BasicBlock::create(LLContext, F.Fn, "utrunc.notmin");
3793
3.92k
    auto NotMaxBB = LLVM::BasicBlock::create(LLContext, F.Fn, "utrunc.notmax");
3794
3.92k
    auto Value = stackPop();
3795
3.92k
    const auto [Precise, MinFp, MaxFp] =
3796
3.92k
        [IntType, Value]() -> std::tuple<bool, LLVM::Value, LLVM::Value> {
3797
3.92k
      const auto BitWidth = IntType.getIntegerBitWidth();
3798
3.92k
      const auto [Min, Max] = [BitWidth]() -> std::tuple<uint64_t, uint64_t> {
3799
3.92k
        switch (BitWidth) {
3800
1.70k
        case 32:
3801
1.70k
          return {std::numeric_limits<uint32_t>::min(),
3802
1.70k
                  std::numeric_limits<uint32_t>::max()};
3803
2.22k
        case 64:
3804
2.22k
          return {std::numeric_limits<uint64_t>::min(),
3805
2.22k
                  std::numeric_limits<uint64_t>::max()};
3806
0
        default:
3807
0
          assumingUnreachable();
3808
3.92k
        }
3809
3.92k
      }();
3810
3.92k
      auto FPType = Value.getType();
3811
3.92k
      assuming(FPType.isFloatTy() || FPType.isDoubleTy());
3812
3.92k
      const auto FPWidth = FPType.getFPMantissaWidth();
3813
3.92k
      return {BitWidth <= FPWidth, LLVM::Value::getConstReal(FPType, Min),
3814
3.92k
              LLVM::Value::getConstReal(FPType, Max)};
3815
3.92k
    }();
3816
3817
3.92k
    auto IsNotNan = Builder.createLikely(Builder.createFCmpORD(Value, Value));
3818
3.92k
    Builder.createCondBr(IsNotNan, NormBB,
3819
3.92k
                         getTrapBB(ErrCode::Value::InvalidConvToInt));
3820
3821
3.92k
    Builder.positionAtEnd(NormBB);
3822
3.92k
    assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
3823
3.92k
    auto Trunc = Builder.createUnaryIntrinsic(LLVM::Core::Trunc, Value);
3824
3.92k
    auto IsNotUnderflow =
3825
3.92k
        Builder.createLikely(Builder.createFCmpOGE(Trunc, MinFp));
3826
3.92k
    Builder.createCondBr(IsNotUnderflow, NotMinBB,
3827
3.92k
                         getTrapBB(ErrCode::Value::IntegerOverflow));
3828
3829
3.92k
    Builder.positionAtEnd(NotMinBB);
3830
3.92k
    auto IsNotOverflow = Builder.createLikely(
3831
3.92k
        Builder.createFCmp(Precise ? LLVMRealOLE : LLVMRealOLT, Trunc, MaxFp));
3832
3.92k
    Builder.createCondBr(IsNotOverflow, NotMaxBB,
3833
3.92k
                         getTrapBB(ErrCode::Value::IntegerOverflow));
3834
3835
3.92k
    Builder.positionAtEnd(NotMaxBB);
3836
3.92k
    stackPush(Builder.createFPToUI(Trunc, IntType));
3837
3.92k
  }
3838
1.05k
  void compileUnsignedTruncSat(LLVM::Type IntType) noexcept {
3839
1.05k
    auto CurrBB = Builder.getInsertBlock();
3840
1.05k
    auto NormBB = LLVM::BasicBlock::create(LLContext, F.Fn, "usat.norm");
3841
1.05k
    auto NotMaxBB = LLVM::BasicBlock::create(LLContext, F.Fn, "usat.notmax");
3842
1.05k
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "usat.end");
3843
1.05k
    auto Value = stackPop();
3844
1.05k
    const auto [Precise, MinInt, MaxInt, MinFp, MaxFp] = [IntType, Value]()
3845
1.05k
        -> std::tuple<bool, uint64_t, uint64_t, LLVM::Value, LLVM::Value> {
3846
1.05k
      const auto BitWidth = IntType.getIntegerBitWidth();
3847
1.05k
      const auto [Min, Max] = [BitWidth]() -> std::tuple<uint64_t, uint64_t> {
3848
1.05k
        switch (BitWidth) {
3849
270
        case 32:
3850
270
          return {std::numeric_limits<uint32_t>::min(),
3851
270
                  std::numeric_limits<uint32_t>::max()};
3852
787
        case 64:
3853
787
          return {std::numeric_limits<uint64_t>::min(),
3854
787
                  std::numeric_limits<uint64_t>::max()};
3855
0
        default:
3856
0
          assumingUnreachable();
3857
1.05k
        }
3858
1.05k
      }();
3859
1.05k
      auto FPType = Value.getType();
3860
1.05k
      assuming(FPType.isFloatTy() || FPType.isDoubleTy());
3861
1.05k
      const auto FPWidth = FPType.getFPMantissaWidth();
3862
1.05k
      return {BitWidth <= FPWidth, Min, Max,
3863
1.05k
              LLVM::Value::getConstReal(FPType, Min),
3864
1.05k
              LLVM::Value::getConstReal(FPType, Max)};
3865
1.05k
    }();
3866
3867
1.05k
    assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
3868
1.05k
    auto Trunc = Builder.createUnaryIntrinsic(LLVM::Core::Trunc, Value);
3869
1.05k
    auto IsNotUnderflow =
3870
1.05k
        Builder.createLikely(Builder.createFCmpOGE(Trunc, MinFp));
3871
1.05k
    Builder.createCondBr(IsNotUnderflow, NormBB, EndBB);
3872
3873
1.05k
    Builder.positionAtEnd(NormBB);
3874
1.05k
    auto IsNotOverflow = Builder.createLikely(
3875
1.05k
        Builder.createFCmp(Precise ? LLVMRealOLE : LLVMRealOLT, Trunc, MaxFp));
3876
1.05k
    Builder.createCondBr(IsNotOverflow, NotMaxBB, EndBB);
3877
3878
1.05k
    Builder.positionAtEnd(NotMaxBB);
3879
1.05k
    auto IntValue = Builder.createFPToUI(Trunc, IntType);
3880
1.05k
    Builder.createBr(EndBB);
3881
3882
1.05k
    Builder.positionAtEnd(EndBB);
3883
1.05k
    auto PHIRet = Builder.createPHI(IntType);
3884
1.05k
    PHIRet.addIncoming(LLVM::Value::getConstInt(IntType, MinInt), CurrBB);
3885
1.05k
    PHIRet.addIncoming(LLVM::Value::getConstInt(IntType, MaxInt), NormBB);
3886
1.05k
    PHIRet.addIncoming(IntValue, NotMaxBB);
3887
3888
1.05k
    stackPush(PHIRet);
3889
1.05k
  }
3890
3891
  void compileAtomicCheckOffsetAlignment(LLVM::Value Offset,
3892
41
                                         LLVM::Type IntType) noexcept {
3893
41
    const auto BitWidth = IntType.getIntegerBitWidth();
3894
41
    auto BWMask = LLContext.getInt64((BitWidth >> 3) - 1);
3895
41
    auto Value = Builder.createAnd(Offset, BWMask);
3896
41
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "address_align_ok");
3897
41
    auto IsAddressAligned = Builder.createLikely(
3898
41
        Builder.createICmpEQ(Value, LLContext.getInt64(0)));
3899
41
    Builder.createCondBr(IsAddressAligned, OkBB,
3900
41
                         getTrapBB(ErrCode::Value::UnalignedAtomicAccess));
3901
3902
41
    Builder.positionAtEnd(OkBB);
3903
41
  }
3904
3905
188
  void compileMemoryFence() noexcept {
3906
188
    Builder.createFence(LLVMAtomicOrderingSequentiallyConsistent);
3907
188
  }
3908
  void compileAtomicNotify(unsigned MemoryIndex,
3909
34
                           unsigned MemoryOffset) noexcept {
3910
34
    auto Count = stackPop();
3911
34
    auto Addr = Builder.createZExt(Stack.back(), Context.Int64Ty);
3912
34
    if (MemoryOffset != 0) {
3913
27
      Addr = Builder.createAdd(Addr, LLContext.getInt64(MemoryOffset));
3914
27
    }
3915
34
    compileAtomicCheckOffsetAlignment(Addr, Context.Int32Ty);
3916
34
    auto Offset = stackPop();
3917
3918
34
    stackPush(Builder.createCall(
3919
34
        Context.getIntrinsic(
3920
34
            Builder, Executable::Intrinsics::kMemAtomicNotify,
3921
34
            LLVM::Type::getFunctionType(
3922
34
                Context.Int32Ty,
3923
34
                {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)),
3924
34
        {LLContext.getInt32(MemoryIndex), Offset, Count}));
3925
34
  }
3926
  void compileAtomicWait(unsigned MemoryIndex, unsigned MemoryOffset,
3927
7
                         LLVM::Type TargetType, uint32_t BitWidth) noexcept {
3928
7
    auto Timeout = stackPop();
3929
7
    auto ExpectedValue = Builder.createZExtOrTrunc(stackPop(), Context.Int64Ty);
3930
7
    auto Addr = Builder.createZExt(Stack.back(), Context.Int64Ty);
3931
7
    if (MemoryOffset != 0) {
3932
3
      Addr = Builder.createAdd(Addr, LLContext.getInt64(MemoryOffset));
3933
3
    }
3934
7
    compileAtomicCheckOffsetAlignment(Addr, TargetType);
3935
7
    auto Offset = stackPop();
3936
3937
7
    stackPush(Builder.createCall(
3938
7
        Context.getIntrinsic(
3939
7
            Builder, Executable::Intrinsics::kMemAtomicWait,
3940
7
            LLVM::Type::getFunctionType(Context.Int32Ty,
3941
7
                                        {Context.Int32Ty, Context.Int32Ty,
3942
7
                                         Context.Int64Ty, Context.Int64Ty,
3943
7
                                         Context.Int32Ty},
3944
7
                                        false)),
3945
7
        {LLContext.getInt32(MemoryIndex), Offset, ExpectedValue, Timeout,
3946
7
         LLContext.getInt32(BitWidth)}));
3947
7
  }
3948
  void compileAtomicLoad(unsigned MemoryIndex, unsigned MemoryOffset,
3949
                         unsigned Alignment, LLVM::Type IntType,
3950
0
                         LLVM::Type TargetType, bool Signed = false) noexcept {
3951
3952
0
    auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
3953
0
    if (MemoryOffset != 0) {
3954
0
      Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
3955
0
    }
3956
0
    compileAtomicCheckOffsetAlignment(Offset, TargetType);
3957
0
    auto VPtr = Builder.createInBoundsGEP1(
3958
0
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex),
3959
0
        Offset);
3960
3961
0
    auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
3962
0
    auto Load = switchEndian(Builder.createLoad(TargetType, Ptr, true));
3963
0
    Load.setAlignment(1 << Alignment);
3964
0
    Load.setOrdering(LLVMAtomicOrderingSequentiallyConsistent);
3965
3966
0
    if (Signed) {
3967
0
      Stack.back() = Builder.createSExt(Load, IntType);
3968
0
    } else {
3969
0
      Stack.back() = Builder.createZExt(Load, IntType);
3970
0
    }
3971
0
  }
3972
  void compileAtomicStore(unsigned MemoryIndex, unsigned MemoryOffset,
3973
                          unsigned Alignment, LLVM::Type, LLVM::Type TargetType,
3974
0
                          bool Signed = false) noexcept {
3975
0
    auto V = stackPop();
3976
3977
0
    if (Signed) {
3978
0
      V = Builder.createSExtOrTrunc(V, TargetType);
3979
0
    } else {
3980
0
      V = Builder.createZExtOrTrunc(V, TargetType);
3981
0
    }
3982
0
    V = switchEndian(V);
3983
0
    auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
3984
0
    if (MemoryOffset != 0) {
3985
0
      Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
3986
0
    }
3987
0
    compileAtomicCheckOffsetAlignment(Offset, TargetType);
3988
0
    auto VPtr = Builder.createInBoundsGEP1(
3989
0
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex),
3990
0
        Offset);
3991
0
    auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
3992
0
    auto Store = Builder.createStore(V, Ptr, true);
3993
0
    Store.setAlignment(1 << Alignment);
3994
0
    Store.setOrdering(LLVMAtomicOrderingSequentiallyConsistent);
3995
0
  }
3996
3997
  void compileAtomicRMWOp(unsigned MemoryIndex, unsigned MemoryOffset,
3998
                          [[maybe_unused]] unsigned Alignment,
3999
                          LLVMAtomicRMWBinOp BinOp, LLVM::Type IntType,
4000
0
                          LLVM::Type TargetType, bool Signed = false) noexcept {
4001
0
    auto Value = Builder.createSExtOrTrunc(stackPop(), TargetType);
4002
0
    auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
4003
0
    if (MemoryOffset != 0) {
4004
0
      Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
4005
0
    }
4006
0
    compileAtomicCheckOffsetAlignment(Offset, TargetType);
4007
0
    auto VPtr = Builder.createInBoundsGEP1(
4008
0
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex),
4009
0
        Offset);
4010
0
    auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
4011
4012
0
    LLVM::Value Ret;
4013
    if constexpr (Endian::native == Endian::big) {
4014
      if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd ||
4015
          BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub) {
4016
        auto AtomicBB = LLVM::BasicBlock::create(LLContext, F.Fn, "atomic.rmw");
4017
        auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "atomic.rmw.ok");
4018
        Builder.createBr(AtomicBB);
4019
        Builder.positionAtEnd(AtomicBB);
4020
4021
        auto Load = Builder.createLoad(TargetType, Ptr, true);
4022
        Load.setOrdering(LLVMAtomicOrderingMonotonic);
4023
        Load.setAlignment(1 << Alignment);
4024
4025
        LLVM::Value New;
4026
        if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpAdd)
4027
          New = Builder.createAdd(switchEndian(Load), Value);
4028
        else if (BinOp == LLVMAtomicRMWBinOp::LLVMAtomicRMWBinOpSub) {
4029
          New = Builder.createSub(switchEndian(Load), Value);
4030
        } else {
4031
          assumingUnreachable();
4032
        }
4033
        New = switchEndian(New);
4034
4035
        auto Exchange = Builder.createAtomicCmpXchg(
4036
            Ptr, Load, New, LLVMAtomicOrderingSequentiallyConsistent,
4037
            LLVMAtomicOrderingSequentiallyConsistent);
4038
4039
        Ret = Builder.createExtractValue(Exchange, 0);
4040
        auto Success = Builder.createExtractValue(Exchange, 1);
4041
        Builder.createCondBr(Success, OkBB, AtomicBB);
4042
        Builder.positionAtEnd(OkBB);
4043
      } else {
4044
        Ret = Builder.createAtomicRMW(BinOp, Ptr, switchEndian(Value),
4045
                                      LLVMAtomicOrderingSequentiallyConsistent);
4046
      }
4047
0
    } else {
4048
0
      Ret = Builder.createAtomicRMW(BinOp, Ptr, switchEndian(Value),
4049
0
                                    LLVMAtomicOrderingSequentiallyConsistent);
4050
0
    }
4051
0
    Ret = switchEndian(Ret);
4052
#if LLVM_VERSION_MAJOR >= 13
4053
    Ret.setAlignment(1 << Alignment);
4054
#endif
4055
0
    if (Signed) {
4056
0
      Stack.back() = Builder.createSExt(Ret, IntType);
4057
0
    } else {
4058
0
      Stack.back() = Builder.createZExt(Ret, IntType);
4059
0
    }
4060
0
  }
4061
  void compileAtomicCompareExchange(unsigned MemoryIndex, unsigned MemoryOffset,
4062
                                    [[maybe_unused]] unsigned Alignment,
4063
                                    LLVM::Type IntType, LLVM::Type TargetType,
4064
0
                                    bool Signed = false) noexcept {
4065
4066
0
    auto Replacement = Builder.createSExtOrTrunc(stackPop(), TargetType);
4067
0
    auto Expected = Builder.createSExtOrTrunc(stackPop(), TargetType);
4068
0
    auto Offset = Builder.createZExt(Stack.back(), Context.Int64Ty);
4069
0
    if (MemoryOffset != 0) {
4070
0
      Offset = Builder.createAdd(Offset, LLContext.getInt64(MemoryOffset));
4071
0
    }
4072
0
    compileAtomicCheckOffsetAlignment(Offset, TargetType);
4073
0
    auto VPtr = Builder.createInBoundsGEP1(
4074
0
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex),
4075
0
        Offset);
4076
0
    auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo());
4077
4078
0
    auto Ret = Builder.createAtomicCmpXchg(
4079
0
        Ptr, switchEndian(Expected), switchEndian(Replacement),
4080
0
        LLVMAtomicOrderingSequentiallyConsistent,
4081
0
        LLVMAtomicOrderingSequentiallyConsistent);
4082
#if LLVM_VERSION_MAJOR >= 13
4083
    Ret.setAlignment(1 << Alignment);
4084
#endif
4085
0
    auto OldVal = Builder.createExtractValue(Ret, 0);
4086
0
    OldVal = switchEndian(OldVal);
4087
0
    if (Signed) {
4088
0
      Stack.back() = Builder.createSExt(OldVal, IntType);
4089
0
    } else {
4090
0
      Stack.back() = Builder.createZExt(OldVal, IntType);
4091
0
    }
4092
0
  }
4093
4094
11.4k
  void compileReturn() noexcept {
4095
11.4k
    updateInstrCount();
4096
11.4k
    updateGas();
4097
11.4k
    auto Ty = F.Ty.getReturnType();
4098
11.4k
    if (Ty.isVoidTy()) {
4099
2.00k
      Builder.createRetVoid();
4100
9.48k
    } else if (Ty.isStructTy()) {
4101
318
      const auto Count = Ty.getStructNumElements();
4102
318
      std::vector<LLVM::Value> Ret(Count);
4103
1.20k
      for (unsigned I = 0; I < Count; ++I) {
4104
889
        const unsigned J = Count - 1 - I;
4105
889
        Ret[J] = stackPop();
4106
889
      }
4107
318
      Builder.createAggregateRet(Ret);
4108
9.16k
    } else {
4109
9.16k
      Builder.createRet(stackPop());
4110
9.16k
    }
4111
11.4k
  }
4112
4113
18.4k
  void updateInstrCount() noexcept {
4114
18.4k
    if (LocalInstrCount) {
4115
0
      auto Store [[maybe_unused]] = Builder.createAtomicRMW(
4116
0
          LLVMAtomicRMWBinOpAdd, Context.getInstrCount(Builder, ExecCtx),
4117
0
          Builder.createLoad(Context.Int64Ty, LocalInstrCount),
4118
0
          LLVMAtomicOrderingMonotonic);
4119
#if LLVM_VERSION_MAJOR >= 13
4120
      Store.setAlignment(8);
4121
#endif
4122
0
      Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
4123
0
    }
4124
18.4k
  }
4125
4126
20.6k
  void updateGas() noexcept {
4127
20.6k
    if (LocalGas) {
4128
0
      auto CurrBB = Builder.getInsertBlock();
4129
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_check");
4130
0
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_ok");
4131
0
      auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_end");
4132
4133
0
      auto Cost = Builder.createLoad(Context.Int64Ty, LocalGas);
4134
0
      Cost.setAlignment(64);
4135
0
      auto GasPtr = Context.getGas(Builder, ExecCtx);
4136
0
      auto GasLimit = Context.getGasLimit(Builder, ExecCtx);
4137
0
      auto Gas = Builder.createLoad(Context.Int64Ty, GasPtr);
4138
0
      Gas.setAlignment(64);
4139
0
      Gas.setOrdering(LLVMAtomicOrderingMonotonic);
4140
0
      Builder.createBr(CheckBB);
4141
0
      Builder.positionAtEnd(CheckBB);
4142
4143
0
      auto PHIOldGas = Builder.createPHI(Context.Int64Ty);
4144
0
      auto NewGas = Builder.createAdd(PHIOldGas, Cost);
4145
0
      auto IsGasRemain =
4146
0
          Builder.createLikely(Builder.createICmpULE(NewGas, GasLimit));
4147
0
      Builder.createCondBr(IsGasRemain, OkBB,
4148
0
                           getTrapBB(ErrCode::Value::CostLimitExceeded));
4149
0
      Builder.positionAtEnd(OkBB);
4150
4151
0
      auto RGasAndSucceed = Builder.createAtomicCmpXchg(
4152
0
          GasPtr, PHIOldGas, NewGas, LLVMAtomicOrderingMonotonic,
4153
0
          LLVMAtomicOrderingMonotonic);
4154
#if LLVM_VERSION_MAJOR >= 13
4155
      RGasAndSucceed.setAlignment(8);
4156
#endif
4157
0
      RGasAndSucceed.setWeak(true);
4158
0
      auto RGas = Builder.createExtractValue(RGasAndSucceed, 0);
4159
0
      auto Succeed = Builder.createExtractValue(RGasAndSucceed, 1);
4160
0
      Builder.createCondBr(Builder.createLikely(Succeed), EndBB, CheckBB);
4161
0
      Builder.positionAtEnd(EndBB);
4162
4163
0
      Builder.createStore(LLContext.getInt64(0), LocalGas);
4164
4165
0
      PHIOldGas.addIncoming(Gas, CurrBB);
4166
0
      PHIOldGas.addIncoming(RGas, OkBB);
4167
0
    }
4168
20.6k
  }
4169
4170
2.87k
  void updateGasAtTrap() noexcept {
4171
2.87k
    if (LocalGas) {
4172
0
      auto Update [[maybe_unused]] = Builder.createAtomicRMW(
4173
0
          LLVMAtomicRMWBinOpAdd, Context.getGas(Builder, ExecCtx),
4174
0
          Builder.createLoad(Context.Int64Ty, LocalGas),
4175
0
          LLVMAtomicOrderingMonotonic);
4176
#if LLVM_VERSION_MAJOR >= 13
4177
      Update.setAlignment(8);
4178
#endif
4179
0
    }
4180
2.87k
  }
4181
4182
private:
4183
3.38k
  void compileCallOp(const unsigned int FuncIndex) noexcept {
4184
3.38k
    const auto &FuncType =
4185
3.38k
        Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
4186
3.38k
            ->getFuncType();
4187
3.38k
    const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
4188
3.38k
    const auto &ParamTypes = FuncType.getParamTypes();
4189
4190
3.38k
    std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
4191
3.38k
    Args[0] = F.Fn.getFirstParam();
4192
4.16k
    for (size_t I = 0; I < ParamTypes.size(); ++I) {
4193
782
      const size_t J = ParamTypes.size() - 1 - I;
4194
782
      Args[J + 1] = stackPop();
4195
782
    }
4196
4197
3.38k
    auto Ret = Builder.createCall(Function, Args);
4198
3.38k
    auto Ty = Ret.getType();
4199
3.38k
    if (Ty.isVoidTy()) {
4200
      // nothing to do
4201
1.81k
    } else if (Ty.isStructTy()) {
4202
159
      for (auto Val : unpackStruct(Builder, Ret)) {
4203
159
        stackPush(Val);
4204
159
      }
4205
1.49k
    } else {
4206
1.49k
      stackPush(Ret);
4207
1.49k
    }
4208
3.38k
  }
4209
4210
  void compileIndirectCallOp(const uint32_t TableIndex,
4211
713
                             const uint32_t FuncTypeIndex) noexcept {
4212
713
    auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
4213
713
    auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
4214
713
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
4215
4216
713
    LLVM::Value FuncIndex = stackPop();
4217
713
    const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
4218
713
    auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
4219
713
    auto RTy = FTy.getReturnType();
4220
4221
713
    const size_t ArgSize = FuncType.getParamTypes().size();
4222
713
    const size_t RetSize =
4223
713
        RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
4224
713
    std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
4225
713
    ArgsVec[0] = F.Fn.getFirstParam();
4226
1.37k
    for (size_t I = 0; I < ArgSize; ++I) {
4227
665
      const size_t J = ArgSize - I;
4228
665
      ArgsVec[J] = stackPop();
4229
665
    }
4230
4231
713
    std::vector<LLVM::Value> FPtrRetsVec;
4232
713
    FPtrRetsVec.reserve(RetSize);
4233
713
    {
4234
713
      auto FPtr = Builder.createCall(
4235
713
          Context.getIntrinsic(
4236
713
              Builder, Executable::Intrinsics::kTableGetFuncSymbol,
4237
713
              LLVM::Type::getFunctionType(
4238
713
                  FTy.getPointerTo(),
4239
713
                  {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)),
4240
713
          {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
4241
713
           FuncIndex});
4242
713
      Builder.createCondBr(
4243
713
          Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
4244
713
          NotNullBB, IsNullBB);
4245
713
      Builder.positionAtEnd(NotNullBB);
4246
4247
713
      auto FPtrRet =
4248
713
          Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
4249
713
      if (RetSize == 0) {
4250
        // nothing to do
4251
527
      } else if (RetSize == 1) {
4252
515
        FPtrRetsVec.push_back(FPtrRet);
4253
515
      } else {
4254
24
        for (auto Val : unpackStruct(Builder, FPtrRet)) {
4255
24
          FPtrRetsVec.push_back(Val);
4256
24
        }
4257
12
      }
4258
713
    }
4259
4260
713
    Builder.createBr(EndBB);
4261
713
    Builder.positionAtEnd(IsNullBB);
4262
4263
713
    std::vector<LLVM::Value> RetsVec;
4264
713
    {
4265
713
      LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
4266
713
      LLVM::Value Rets = Builder.createArray(RetSize, kValSize);
4267
713
      Builder.createArrayPtrStore(
4268
713
          Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize), Args, Context.Int8Ty,
4269
713
          kValSize);
4270
4271
713
      Builder.createCall(
4272
713
          Context.getIntrinsic(
4273
713
              Builder, Executable::Intrinsics::kCallIndirect,
4274
713
              LLVM::Type::getFunctionType(Context.VoidTy,
4275
713
                                          {Context.Int32Ty, Context.Int32Ty,
4276
713
                                           Context.Int32Ty, Context.Int8PtrTy,
4277
713
                                           Context.Int8PtrTy},
4278
713
                                          false)),
4279
713
          {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
4280
713
           FuncIndex, Args, Rets});
4281
4282
713
      if (RetSize == 0) {
4283
        // nothing to do
4284
527
      } else if (RetSize == 1) {
4285
515
        RetsVec.push_back(
4286
515
            Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
4287
515
      } else {
4288
12
        RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
4289
12
                                             kValSize);
4290
12
      }
4291
713
      Builder.createBr(EndBB);
4292
713
      Builder.positionAtEnd(EndBB);
4293
713
    }
4294
4295
1.25k
    for (unsigned I = 0; I < RetSize; ++I) {
4296
539
      auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
4297
539
      PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
4298
539
      PHIRet.addIncoming(RetsVec[I], IsNullBB);
4299
539
      stackPush(PHIRet);
4300
539
    }
4301
713
  }
4302
4303
0
  void compileReturnCallOp(const unsigned int FuncIndex) noexcept {
4304
0
    const auto &FuncType =
4305
0
        Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
4306
0
            ->getFuncType();
4307
0
    const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
4308
0
    const auto &ParamTypes = FuncType.getParamTypes();
4309
4310
0
    std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
4311
0
    Args[0] = F.Fn.getFirstParam();
4312
0
    for (size_t I = 0; I < ParamTypes.size(); ++I) {
4313
0
      const size_t J = ParamTypes.size() - 1 - I;
4314
0
      Args[J + 1] = stackPop();
4315
0
    }
4316
4317
0
    auto Ret = Builder.createCall(Function, Args);
4318
0
    auto Ty = Ret.getType();
4319
0
    if (Ty.isVoidTy()) {
4320
0
      Builder.createRetVoid();
4321
0
    } else {
4322
0
      Builder.createRet(Ret);
4323
0
    }
4324
0
  }
4325
4326
  void compileReturnIndirectCallOp(const uint32_t TableIndex,
4327
0
                                   const uint32_t FuncTypeIndex) noexcept {
4328
0
    auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
4329
0
    auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
4330
4331
0
    LLVM::Value FuncIndex = stackPop();
4332
0
    const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
4333
0
    auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
4334
0
    auto RTy = FTy.getReturnType();
4335
4336
0
    const size_t ArgSize = FuncType.getParamTypes().size();
4337
0
    const size_t RetSize =
4338
0
        RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
4339
0
    std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
4340
0
    ArgsVec[0] = F.Fn.getFirstParam();
4341
0
    for (size_t I = 0; I < ArgSize; ++I) {
4342
0
      const size_t J = ArgSize - I;
4343
0
      ArgsVec[J] = stackPop();
4344
0
    }
4345
4346
0
    {
4347
0
      auto FPtr = Builder.createCall(
4348
0
          Context.getIntrinsic(
4349
0
              Builder, Executable::Intrinsics::kTableGetFuncSymbol,
4350
0
              LLVM::Type::getFunctionType(
4351
0
                  FTy.getPointerTo(),
4352
0
                  {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)),
4353
0
          {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
4354
0
           FuncIndex});
4355
0
      Builder.createCondBr(
4356
0
          Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
4357
0
          NotNullBB, IsNullBB);
4358
0
      Builder.positionAtEnd(NotNullBB);
4359
4360
0
      auto FPtrRet =
4361
0
          Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
4362
0
      if (RetSize == 0) {
4363
0
        Builder.createRetVoid();
4364
0
      } else {
4365
0
        Builder.createRet(FPtrRet);
4366
0
      }
4367
0
    }
4368
4369
0
    Builder.positionAtEnd(IsNullBB);
4370
4371
0
    {
4372
0
      LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
4373
0
      LLVM::Value Rets = Builder.createArray(RetSize, kValSize);
4374
0
      Builder.createArrayPtrStore(
4375
0
          Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize), Args, Context.Int8Ty,
4376
0
          kValSize);
4377
4378
0
      Builder.createCall(
4379
0
          Context.getIntrinsic(
4380
0
              Builder, Executable::Intrinsics::kCallIndirect,
4381
0
              LLVM::Type::getFunctionType(Context.VoidTy,
4382
0
                                          {Context.Int32Ty, Context.Int32Ty,
4383
0
                                           Context.Int32Ty, Context.Int8PtrTy,
4384
0
                                           Context.Int8PtrTy},
4385
0
                                          false)),
4386
0
          {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
4387
0
           FuncIndex, Args, Rets});
4388
4389
0
      if (RetSize == 0) {
4390
0
        Builder.createRetVoid();
4391
0
      } else if (RetSize == 1) {
4392
0
        Builder.createRet(
4393
0
            Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
4394
0
      } else {
4395
0
        Builder.createAggregateRet(Builder.createArrayPtrLoad(
4396
0
            RetSize, RTy, Rets, Context.Int8Ty, kValSize));
4397
0
      }
4398
0
    }
4399
0
  }
4400
4401
0
  void compileCallRefOp(const unsigned int TypeIndex) noexcept {
4402
0
    auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
4403
0
    auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
4404
0
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
4405
4406
0
    auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
4407
0
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
4408
0
    auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
4409
0
        Builder.createExtractElement(Ref, LLContext.getInt64(1)),
4410
0
        LLContext.getInt64(0)));
4411
0
    Builder.createCondBr(IsRefNotNull, OkBB,
4412
0
                         getTrapBB(ErrCode::Value::AccessNullFunc));
4413
0
    Builder.positionAtEnd(OkBB);
4414
4415
0
    const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
4416
0
    auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
4417
0
    auto RTy = FTy.getReturnType();
4418
4419
0
    const size_t ArgSize = FuncType.getParamTypes().size();
4420
0
    const size_t RetSize =
4421
0
        RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
4422
0
    std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
4423
0
    ArgsVec[0] = F.Fn.getFirstParam();
4424
0
    for (size_t I = 0; I < ArgSize; ++I) {
4425
0
      const size_t J = ArgSize - I;
4426
0
      ArgsVec[J] = stackPop();
4427
0
    }
4428
4429
0
    std::vector<LLVM::Value> FPtrRetsVec;
4430
0
    FPtrRetsVec.reserve(RetSize);
4431
0
    {
4432
0
      auto FPtr = Builder.createCall(
4433
0
          Context.getIntrinsic(
4434
0
              Builder, Executable::Intrinsics::kRefGetFuncSymbol,
4435
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(),
4436
0
                                          {Context.Int64x2Ty}, false)),
4437
0
          {Ref});
4438
0
      Builder.createCondBr(
4439
0
          Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
4440
0
          NotNullBB, IsNullBB);
4441
0
      Builder.positionAtEnd(NotNullBB);
4442
4443
0
      auto FPtrRet =
4444
0
          Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
4445
0
      if (RetSize == 0) {
4446
        // nothing to do
4447
0
      } else if (RetSize == 1) {
4448
0
        FPtrRetsVec.push_back(FPtrRet);
4449
0
      } else {
4450
0
        for (auto Val : unpackStruct(Builder, FPtrRet)) {
4451
0
          FPtrRetsVec.push_back(Val);
4452
0
        }
4453
0
      }
4454
0
    }
4455
4456
0
    Builder.createBr(EndBB);
4457
0
    Builder.positionAtEnd(IsNullBB);
4458
4459
0
    std::vector<LLVM::Value> RetsVec;
4460
0
    {
4461
0
      LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
4462
0
      LLVM::Value Rets = Builder.createArray(RetSize, kValSize);
4463
0
      Builder.createArrayPtrStore(
4464
0
          Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize), Args, Context.Int8Ty,
4465
0
          kValSize);
4466
4467
0
      Builder.createCall(
4468
0
          Context.getIntrinsic(
4469
0
              Builder, Executable::Intrinsics::kCallRef,
4470
0
              LLVM::Type::getFunctionType(
4471
0
                  Context.VoidTy,
4472
0
                  {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
4473
0
                  false)),
4474
0
          {Ref, Args, Rets});
4475
4476
0
      if (RetSize == 0) {
4477
        // nothing to do
4478
0
      } else if (RetSize == 1) {
4479
0
        RetsVec.push_back(
4480
0
            Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
4481
0
      } else {
4482
0
        RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
4483
0
                                             kValSize);
4484
0
      }
4485
0
      Builder.createBr(EndBB);
4486
0
      Builder.positionAtEnd(EndBB);
4487
0
    }
4488
4489
0
    for (unsigned I = 0; I < RetSize; ++I) {
4490
0
      auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
4491
0
      PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
4492
0
      PHIRet.addIncoming(RetsVec[I], IsNullBB);
4493
0
      stackPush(PHIRet);
4494
0
    }
4495
0
  }
4496
4497
0
  void compileReturnCallRefOp(const unsigned int TypeIndex) noexcept {
4498
0
    auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
4499
0
    auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
4500
4501
0
    auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
4502
0
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
4503
0
    auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
4504
0
        Builder.createExtractElement(Ref, LLContext.getInt64(1)),
4505
0
        LLContext.getInt64(0)));
4506
0
    Builder.createCondBr(IsRefNotNull, OkBB,
4507
0
                         getTrapBB(ErrCode::Value::AccessNullFunc));
4508
0
    Builder.positionAtEnd(OkBB);
4509
4510
0
    const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
4511
0
    auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
4512
0
    auto RTy = FTy.getReturnType();
4513
4514
0
    const size_t ArgSize = FuncType.getParamTypes().size();
4515
0
    const size_t RetSize =
4516
0
        RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
4517
0
    std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
4518
0
    ArgsVec[0] = F.Fn.getFirstParam();
4519
0
    for (size_t I = 0; I < ArgSize; ++I) {
4520
0
      const size_t J = ArgSize - I;
4521
0
      ArgsVec[J] = stackPop();
4522
0
    }
4523
4524
0
    {
4525
0
      auto FPtr = Builder.createCall(
4526
0
          Context.getIntrinsic(
4527
0
              Builder, Executable::Intrinsics::kRefGetFuncSymbol,
4528
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(),
4529
0
                                          {Context.Int64x2Ty}, false)),
4530
0
          {Ref});
4531
0
      Builder.createCondBr(
4532
0
          Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
4533
0
          NotNullBB, IsNullBB);
4534
0
      Builder.positionAtEnd(NotNullBB);
4535
4536
0
      auto FPtrRet =
4537
0
          Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
4538
0
      if (RetSize == 0) {
4539
0
        Builder.createRetVoid();
4540
0
      } else {
4541
0
        Builder.createRet(FPtrRet);
4542
0
      }
4543
0
    }
4544
4545
0
    Builder.positionAtEnd(IsNullBB);
4546
4547
0
    {
4548
0
      LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
4549
0
      LLVM::Value Rets = Builder.createArray(RetSize, kValSize);
4550
0
      Builder.createArrayPtrStore(
4551
0
          Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize), Args, Context.Int8Ty,
4552
0
          kValSize);
4553
4554
0
      Builder.createCall(
4555
0
          Context.getIntrinsic(
4556
0
              Builder, Executable::Intrinsics::kCallRef,
4557
0
              LLVM::Type::getFunctionType(
4558
0
                  Context.VoidTy,
4559
0
                  {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
4560
0
                  false)),
4561
0
          {Ref, Args, Rets});
4562
4563
0
      if (RetSize == 0) {
4564
0
        Builder.createRetVoid();
4565
0
      } else if (RetSize == 1) {
4566
0
        Builder.createRet(
4567
0
            Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
4568
0
      } else {
4569
0
        Builder.createAggregateRet(Builder.createArrayPtrLoad(
4570
0
            RetSize, RTy, Rets, Context.Int8Ty, kValSize));
4571
0
      }
4572
0
    }
4573
0
  }
4574
4575
  void compileLoadOp(unsigned MemoryIndex, unsigned Offset, unsigned Alignment,
4576
20.3k
                     LLVM::Type LoadTy) noexcept {
4577
20.3k
    if constexpr (kForceUnalignment) {
4578
20.3k
      Alignment = 0;
4579
20.3k
    }
4580
20.3k
    auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
4581
20.3k
    if (Offset != 0) {
4582
13.5k
      Off = Builder.createAdd(Off, LLContext.getInt64(Offset));
4583
13.5k
    }
4584
4585
20.3k
    auto VPtr = Builder.createInBoundsGEP1(
4586
20.3k
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off);
4587
20.3k
    auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo());
4588
20.3k
    auto LoadInst = Builder.createLoad(LoadTy, Ptr, true);
4589
20.3k
    LoadInst.setAlignment(1 << Alignment);
4590
20.3k
    stackPush(switchEndian(LoadInst));
4591
20.3k
  }
4592
  void compileLoadOp(unsigned MemoryIndex, unsigned Offset, unsigned Alignment,
4593
                     LLVM::Type LoadTy, LLVM::Type ExtendTy,
4594
7.71k
                     bool Signed) noexcept {
4595
7.71k
    compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
4596
7.71k
    if (Signed) {
4597
3.33k
      Stack.back() = Builder.createSExt(Stack.back(), ExtendTy);
4598
4.38k
    } else {
4599
4.38k
      Stack.back() = Builder.createZExt(Stack.back(), ExtendTy);
4600
4.38k
    }
4601
7.71k
  }
4602
  void compileVectorLoadOp(unsigned MemoryIndex, unsigned Offset,
4603
5.46k
                           unsigned Alignment, LLVM::Type LoadTy) noexcept {
4604
5.46k
    compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
4605
5.46k
    Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
4606
5.46k
  }
4607
  void compileVectorLoadOp(unsigned MemoryIndex, unsigned Offset,
4608
                           unsigned Alignment, LLVM::Type LoadTy,
4609
1.56k
                           LLVM::Type ExtendTy, bool Signed) noexcept {
4610
1.56k
    compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy, ExtendTy, Signed);
4611
1.56k
    Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
4612
1.56k
  }
4613
  void compileSplatLoadOp(unsigned MemoryIndex, unsigned Offset,
4614
                          unsigned Alignment, LLVM::Type LoadTy,
4615
583
                          LLVM::Type VectorTy) noexcept {
4616
583
    compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
4617
583
    compileSplatOp(VectorTy);
4618
583
  }
4619
  void compileLoadLaneOp(unsigned MemoryIndex, unsigned Offset,
4620
                         unsigned Alignment, unsigned Index, LLVM::Type LoadTy,
4621
551
                         LLVM::Type VectorTy) noexcept {
4622
551
    auto Vector = stackPop();
4623
551
    compileLoadOp(MemoryIndex, Offset, Alignment, LoadTy);
4624
    if constexpr (Endian::native == Endian::big) {
4625
      Index = VectorTy.getVectorSize() - 1 - Index;
4626
    }
4627
551
    auto Value = Stack.back();
4628
551
    Stack.back() = Builder.createBitCast(
4629
551
        Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
4630
551
                                    Value, LLContext.getInt64(Index)),
4631
551
        Context.Int64x2Ty);
4632
551
  }
4633
  void compileStoreOp(unsigned MemoryIndex, unsigned Offset, unsigned Alignment,
4634
                      LLVM::Type LoadTy, bool Trunc = false,
4635
3.37k
                      bool BitCast = false) noexcept {
4636
3.37k
    if constexpr (kForceUnalignment) {
4637
3.37k
      Alignment = 0;
4638
3.37k
    }
4639
3.37k
    auto V = stackPop();
4640
3.37k
    auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
4641
3.37k
    if (Offset != 0) {
4642
2.53k
      Off = Builder.createAdd(Off, LLContext.getInt64(Offset));
4643
2.53k
    }
4644
4645
3.37k
    if (Trunc) {
4646
694
      V = Builder.createTrunc(V, LoadTy);
4647
694
    }
4648
3.37k
    if (BitCast) {
4649
235
      V = Builder.createBitCast(V, LoadTy);
4650
235
    }
4651
3.37k
    V = switchEndian(V);
4652
3.37k
    auto VPtr = Builder.createInBoundsGEP1(
4653
3.37k
        Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off);
4654
3.37k
    auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo());
4655
3.37k
    auto StoreInst = Builder.createStore(V, Ptr, true);
4656
3.37k
    StoreInst.setAlignment(1 << Alignment);
4657
3.37k
  }
4658
  void compileStoreLaneOp(unsigned MemoryIndex, unsigned Offset,
4659
                          unsigned Alignment, unsigned Index, LLVM::Type LoadTy,
4660
375
                          LLVM::Type VectorTy) noexcept {
4661
375
    auto Vector = Stack.back();
4662
    if constexpr (Endian::native == Endian::big) {
4663
      Index = VectorTy.getVectorSize() - Index - 1;
4664
    }
4665
375
    Stack.back() = Builder.createExtractElement(
4666
375
        Builder.createBitCast(Vector, VectorTy), LLContext.getInt64(Index));
4667
375
    compileStoreOp(MemoryIndex, Offset, Alignment, LoadTy);
4668
375
  }
4669
52.4k
  void compileSplatOp(LLVM::Type VectorTy) noexcept {
4670
52.4k
    auto Undef = LLVM::Value::getUndef(VectorTy);
4671
52.4k
    auto Zeros = LLVM::Value::getConstNull(
4672
52.4k
        LLVM::Type::getVectorType(Context.Int32Ty, VectorTy.getVectorSize()));
4673
52.4k
    auto Value = Builder.createTrunc(Stack.back(), VectorTy.getElementType());
4674
52.4k
    auto Vector =
4675
52.4k
        Builder.createInsertElement(Undef, Value, LLContext.getInt64(0));
4676
52.4k
    Vector = Builder.createShuffleVector(Vector, Undef, Zeros);
4677
4678
52.4k
    Stack.back() = Builder.createBitCast(Vector, Context.Int64x2Ty);
4679
52.4k
  }
4680
1.42k
  void compileExtractLaneOp(LLVM::Type VectorTy, unsigned Index) noexcept {
4681
1.42k
    auto Vector = Builder.createBitCast(Stack.back(), VectorTy);
4682
    if constexpr (Endian::native == Endian::big) {
4683
      Index = VectorTy.getVectorSize() - Index - 1;
4684
    }
4685
1.42k
    Stack.back() =
4686
1.42k
        Builder.createExtractElement(Vector, LLContext.getInt64(Index));
4687
1.42k
  }
4688
  void compileExtractLaneOp(LLVM::Type VectorTy, unsigned Index,
4689
1.05k
                            LLVM::Type ExtendTy, bool Signed) noexcept {
4690
1.05k
    compileExtractLaneOp(VectorTy, Index);
4691
1.05k
    if (Signed) {
4692
577
      Stack.back() = Builder.createSExt(Stack.back(), ExtendTy);
4693
577
    } else {
4694
481
      Stack.back() = Builder.createZExt(Stack.back(), ExtendTy);
4695
481
    }
4696
1.05k
  }
4697
1.19k
  void compileReplaceLaneOp(LLVM::Type VectorTy, unsigned Index) noexcept {
4698
1.19k
    auto Value = Builder.createTrunc(stackPop(), VectorTy.getElementType());
4699
1.19k
    auto Vector = Stack.back();
4700
    if constexpr (Endian::native == Endian::big) {
4701
      Index = VectorTy.getVectorSize() - Index - 1;
4702
    }
4703
1.19k
    Stack.back() = Builder.createBitCast(
4704
1.19k
        Builder.createInsertElement(Builder.createBitCast(Vector, VectorTy),
4705
1.19k
                                    Value, LLContext.getInt64(Index)),
4706
1.19k
        Context.Int64x2Ty);
4707
1.19k
  }
4708
  void compileVectorCompareOp(LLVM::Type VectorTy,
4709
5.82k
                              LLVMIntPredicate Predicate) noexcept {
4710
5.82k
    auto RHS = stackPop();
4711
5.82k
    auto LHS = stackPop();
4712
5.82k
    auto Result = Builder.createSExt(
4713
5.82k
        Builder.createICmp(Predicate, Builder.createBitCast(LHS, VectorTy),
4714
5.82k
                           Builder.createBitCast(RHS, VectorTy)),
4715
5.82k
        VectorTy);
4716
5.82k
    stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
4717
5.82k
  }
4718
  void compileVectorCompareOp(LLVM::Type VectorTy, LLVMRealPredicate Predicate,
4719
3.59k
                              LLVM::Type ResultTy) noexcept {
4720
3.59k
    auto RHS = stackPop();
4721
3.59k
    auto LHS = stackPop();
4722
3.59k
    auto Result = Builder.createSExt(
4723
3.59k
        Builder.createFCmp(Predicate, Builder.createBitCast(LHS, VectorTy),
4724
3.59k
                           Builder.createBitCast(RHS, VectorTy)),
4725
3.59k
        ResultTy);
4726
3.59k
    stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
4727
3.59k
  }
4728
  template <typename Func>
4729
24.8k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
24.8k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
24.8k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
24.8k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorAbs(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorAbs(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
2.09k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
2.09k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
2.09k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
2.09k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorNeg(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorNeg(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
2.33k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
2.33k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
2.33k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
2.33k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorPopcnt()::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorPopcnt()::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
157
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
157
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
157
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
157
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorExtAddPairwise(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorExtAddPairwise(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
2.42k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
2.42k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
2.42k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
2.42k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFAbs(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFAbs(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
565
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
565
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
565
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
565
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFNeg(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFNeg(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
937
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
937
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
937
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
937
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFSqrt(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFSqrt(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
345
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
345
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
345
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
345
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFCeil(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFCeil(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
1.18k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
1.18k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
1.18k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
1.18k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFFloor(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFFloor(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
2.17k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
2.17k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
2.17k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
2.17k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFTrunc(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFTrunc(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
1.62k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
1.62k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
1.62k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
1.62k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorFNearest(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorFNearest(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
344
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
344
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
344
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
344
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorTruncSatS32(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorTruncSatS32(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
1.00k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
1.00k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
1.00k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
1.00k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorTruncSatU32(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorTruncSatU32(WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
5.83k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
5.83k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
5.83k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
5.83k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorConvertS(WasmEdge::LLVM::Type, WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorConvertS(WasmEdge::LLVM::Type, WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
654
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
654
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
654
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
654
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorConvertU(WasmEdge::LLVM::Type, WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorConvertU(WasmEdge::LLVM::Type, WasmEdge::LLVM::Type, bool)::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
2.05k
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
2.05k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
2.05k
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
2.05k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorDemote()::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorDemote()::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
527
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
527
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
527
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
527
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorPromote()::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorPromote()::{lambda(auto:1)#1}&&)
Line
Count
Source
4729
599
  void compileVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4730
599
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4731
599
    Stack.back() = Builder.createBitCast(Op(V), Context.Int64x2Ty);
4732
599
  }
4733
2.09k
  void compileVectorAbs(LLVM::Type VectorTy) noexcept {
4734
2.09k
    compileVectorOp(VectorTy, [this, VectorTy](auto V) noexcept {
4735
2.09k
      auto Zero = LLVM::Value::getConstNull(VectorTy);
4736
2.09k
      auto C = Builder.createICmpSLT(V, Zero);
4737
2.09k
      return Builder.createSelect(C, Builder.createNeg(V), V);
4738
2.09k
    });
4739
2.09k
  }
4740
2.33k
  void compileVectorNeg(LLVM::Type VectorTy) noexcept {
4741
2.33k
    compileVectorOp(VectorTy,
4742
2.33k
                    [this](auto V) noexcept { return Builder.createNeg(V); });
4743
2.33k
  }
4744
157
  void compileVectorPopcnt() noexcept {
4745
157
    compileVectorOp(Context.Int8x16Ty, [this](auto V) noexcept {
4746
157
      assuming(LLVM::Core::Ctpop != LLVM::Core::NotIntrinsic);
4747
157
      return Builder.createUnaryIntrinsic(LLVM::Core::Ctpop, V);
4748
157
    });
4749
157
  }
4750
  template <typename Func>
4751
2.26k
  void compileVectorReduceIOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4752
2.26k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4753
2.26k
    Stack.back() = Builder.createZExt(Op(V), Context.Int32Ty);
4754
2.26k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorReduceIOp<(anonymous namespace)::FunctionCompiler::compileVectorAnyTrue()::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorAnyTrue()::{lambda(auto:1)#1}&&)
Line
Count
Source
4751
107
  void compileVectorReduceIOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4752
107
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4753
107
    Stack.back() = Builder.createZExt(Op(V), Context.Int32Ty);
4754
107
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorReduceIOp<(anonymous namespace)::FunctionCompiler::compileVectorAllTrue(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorAllTrue(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4751
934
  void compileVectorReduceIOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4752
934
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4753
934
    Stack.back() = Builder.createZExt(Op(V), Context.Int32Ty);
4754
934
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorReduceIOp<(anonymous namespace)::FunctionCompiler::compileVectorBitMask(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorBitMask(WasmEdge::LLVM::Type)::{lambda(auto:1)#1}&&)
Line
Count
Source
4751
1.22k
  void compileVectorReduceIOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4752
1.22k
    auto V = Builder.createBitCast(Stack.back(), VectorTy);
4753
1.22k
    Stack.back() = Builder.createZExt(Op(V), Context.Int32Ty);
4754
1.22k
  }
4755
107
  void compileVectorAnyTrue() noexcept {
4756
107
    compileVectorReduceIOp(Context.Int128x1Ty, [this](auto V) noexcept {
4757
107
      auto Zero = LLVM::Value::getConstNull(Context.Int128x1Ty);
4758
107
      return Builder.createBitCast(Builder.createICmpNE(V, Zero),
4759
107
                                   LLContext.getInt1Ty());
4760
107
    });
4761
107
  }
4762
934
  void compileVectorAllTrue(LLVM::Type VectorTy) noexcept {
4763
934
    compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept {
4764
934
      const auto Size = VectorTy.getVectorSize();
4765
934
      auto IntType = LLContext.getIntNTy(Size);
4766
934
      auto Zero = LLVM::Value::getConstNull(VectorTy);
4767
934
      auto Cmp = Builder.createBitCast(Builder.createICmpEQ(V, Zero), IntType);
4768
934
      auto CmpZero = LLVM::Value::getConstInt(IntType, 0);
4769
934
      return Builder.createICmpEQ(Cmp, CmpZero);
4770
934
    });
4771
934
  }
4772
1.22k
  void compileVectorBitMask(LLVM::Type VectorTy) noexcept {
4773
1.22k
    compileVectorReduceIOp(VectorTy, [this, VectorTy](auto V) noexcept {
4774
1.22k
      const auto Size = VectorTy.getVectorSize();
4775
1.22k
      auto IntType = LLContext.getIntNTy(Size);
4776
1.22k
      auto Zero = LLVM::Value::getConstNull(VectorTy);
4777
1.22k
      return Builder.createBitCast(Builder.createICmpSLT(V, Zero), IntType);
4778
1.22k
    });
4779
1.22k
  }
4780
  template <typename Func>
4781
4.97k
  void compileVectorShiftOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4782
4.97k
    const bool Trunc = VectorTy.getElementType().getIntegerBitWidth() < 32;
4783
4.97k
    const uint32_t Mask = VectorTy.getElementType().getIntegerBitWidth() - 1;
4784
4.97k
    auto N = Builder.createAnd(stackPop(), LLContext.getInt32(Mask));
4785
4.97k
    auto RHS = Builder.createVectorSplat(
4786
4.97k
        VectorTy.getVectorSize(),
4787
4.97k
        Trunc ? Builder.createTrunc(N, VectorTy.getElementType())
4788
4.97k
              : Builder.createZExtOrTrunc(N, VectorTy.getElementType()));
4789
4.97k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4790
4.97k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4791
4.97k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorShiftOp<(anonymous namespace)::FunctionCompiler::compileVectorShl(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorShl(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4781
2.18k
  void compileVectorShiftOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4782
2.18k
    const bool Trunc = VectorTy.getElementType().getIntegerBitWidth() < 32;
4783
2.18k
    const uint32_t Mask = VectorTy.getElementType().getIntegerBitWidth() - 1;
4784
2.18k
    auto N = Builder.createAnd(stackPop(), LLContext.getInt32(Mask));
4785
2.18k
    auto RHS = Builder.createVectorSplat(
4786
2.18k
        VectorTy.getVectorSize(),
4787
2.18k
        Trunc ? Builder.createTrunc(N, VectorTy.getElementType())
4788
2.18k
              : Builder.createZExtOrTrunc(N, VectorTy.getElementType()));
4789
2.18k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4790
2.18k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4791
2.18k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorShiftOp<(anonymous namespace)::FunctionCompiler::compileVectorAShr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorAShr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4781
2.45k
  void compileVectorShiftOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4782
2.45k
    const bool Trunc = VectorTy.getElementType().getIntegerBitWidth() < 32;
4783
2.45k
    const uint32_t Mask = VectorTy.getElementType().getIntegerBitWidth() - 1;
4784
2.45k
    auto N = Builder.createAnd(stackPop(), LLContext.getInt32(Mask));
4785
2.45k
    auto RHS = Builder.createVectorSplat(
4786
2.45k
        VectorTy.getVectorSize(),
4787
2.45k
        Trunc ? Builder.createTrunc(N, VectorTy.getElementType())
4788
2.45k
              : Builder.createZExtOrTrunc(N, VectorTy.getElementType()));
4789
2.45k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4790
2.45k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4791
2.45k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorShiftOp<(anonymous namespace)::FunctionCompiler::compileVectorLShr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorLShr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4781
336
  void compileVectorShiftOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4782
336
    const bool Trunc = VectorTy.getElementType().getIntegerBitWidth() < 32;
4783
336
    const uint32_t Mask = VectorTy.getElementType().getIntegerBitWidth() - 1;
4784
336
    auto N = Builder.createAnd(stackPop(), LLContext.getInt32(Mask));
4785
336
    auto RHS = Builder.createVectorSplat(
4786
336
        VectorTy.getVectorSize(),
4787
336
        Trunc ? Builder.createTrunc(N, VectorTy.getElementType())
4788
336
              : Builder.createZExtOrTrunc(N, VectorTy.getElementType()));
4789
336
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4790
336
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4791
336
  }
4792
2.18k
  void compileVectorShl(LLVM::Type VectorTy) noexcept {
4793
2.18k
    compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4794
2.18k
      return Builder.createShl(LHS, RHS);
4795
2.18k
    });
4796
2.18k
  }
4797
336
  void compileVectorLShr(LLVM::Type VectorTy) noexcept {
4798
336
    compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4799
336
      return Builder.createLShr(LHS, RHS);
4800
336
    });
4801
336
  }
4802
2.45k
  void compileVectorAShr(LLVM::Type VectorTy) noexcept {
4803
2.45k
    compileVectorShiftOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4804
2.45k
      return Builder.createAShr(LHS, RHS);
4805
2.45k
    });
4806
2.45k
  }
4807
  template <typename Func>
4808
8.60k
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
8.60k
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
8.60k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
8.60k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
8.60k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorAdd(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorAdd(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
308
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
308
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
308
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
308
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
308
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorAddSat(WasmEdge::LLVM::Type, bool)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorAddSat(WasmEdge::LLVM::Type, bool)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
1.74k
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
1.74k
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
1.74k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
1.74k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
1.74k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorSub(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorSub(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
808
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
808
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
808
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
808
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
808
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorSubSat(WasmEdge::LLVM::Type, bool)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorSubSat(WasmEdge::LLVM::Type, bool)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
403
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
403
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
403
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
403
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
403
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorSMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorSMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
310
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
310
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
310
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
310
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
310
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorUMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorUMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
339
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
339
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
339
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
339
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
339
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorSMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorSMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
422
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
422
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
422
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
422
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
422
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorUMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorUMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
1.06k
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
1.06k
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
1.06k
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
1.06k
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
1.06k
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorUAvgr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorUAvgr(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
299
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
299
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
299
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
299
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
299
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorMul(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorMul(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
457
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
457
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
457
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
457
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
457
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorQ15MulSat()::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorQ15MulSat()::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
203
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
203
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
203
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
203
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
203
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFAdd(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFAdd(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
181
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
181
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
181
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
181
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
181
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFSub(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFSub(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
484
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
484
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
484
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
484
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
484
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFMul(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFMul(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
183
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
183
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
183
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
183
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
183
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFDiv(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFDiv(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
226
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
226
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
226
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
226
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
226
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
289
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
289
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
289
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
289
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
289
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
195
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
195
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
195
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
195
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
195
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFPMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFPMin(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
376
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
376
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
376
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
376
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
376
  }
compiler.cpp:void (anonymous namespace)::FunctionCompiler::compileVectorVectorOp<(anonymous namespace)::FunctionCompiler::compileVectorVectorFPMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}>(WasmEdge::LLVM::Type, (anonymous namespace)::FunctionCompiler::compileVectorVectorFPMax(WasmEdge::LLVM::Type)::{lambda(auto:1, auto:2)#1}&&)
Line
Count
Source
4808
314
  void compileVectorVectorOp(LLVM::Type VectorTy, Func &&Op) noexcept {
4809
314
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
4810
314
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
4811
314
    stackPush(Builder.createBitCast(Op(LHS, RHS), Context.Int64x2Ty));
4812
314
  }
4813
308
  void compileVectorVectorAdd(LLVM::Type VectorTy) noexcept {
4814
308
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4815
308
      return Builder.createAdd(LHS, RHS);
4816
308
    });
4817
308
  }
4818
1.74k
  void compileVectorVectorAddSat(LLVM::Type VectorTy, bool Signed) noexcept {
4819
1.74k
    auto ID = Signed ? LLVM::Core::SAddSat : LLVM::Core::UAddSat;
4820
1.74k
    assuming(ID != LLVM::Core::NotIntrinsic);
4821
1.74k
    compileVectorVectorOp(
4822
1.74k
        VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
4823
1.74k
          return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
4824
1.74k
        });
4825
1.74k
  }
4826
808
  void compileVectorVectorSub(LLVM::Type VectorTy) noexcept {
4827
808
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4828
808
      return Builder.createSub(LHS, RHS);
4829
808
    });
4830
808
  }
4831
403
  void compileVectorVectorSubSat(LLVM::Type VectorTy, bool Signed) noexcept {
4832
403
    auto ID = Signed ? LLVM::Core::SSubSat : LLVM::Core::USubSat;
4833
403
    assuming(ID != LLVM::Core::NotIntrinsic);
4834
403
    compileVectorVectorOp(
4835
403
        VectorTy, [this, VectorTy, ID](auto LHS, auto RHS) noexcept {
4836
403
          return Builder.createIntrinsic(ID, {VectorTy}, {LHS, RHS});
4837
403
        });
4838
403
  }
4839
457
  void compileVectorVectorMul(LLVM::Type VectorTy) noexcept {
4840
457
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4841
457
      return Builder.createMul(LHS, RHS);
4842
457
    });
4843
457
  }
4844
65
  void compileVectorSwizzle() noexcept {
4845
65
    auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
4846
65
    auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty);
4847
4848
65
#if defined(__x86_64__)
4849
65
    if (Context.SupportSSSE3) {
4850
65
      auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112));
4851
65
      auto Added = Builder.createAdd(Index, Magic);
4852
65
      auto NewIndex = Builder.createSelect(
4853
65
          Builder.createICmpUGT(Index, Added),
4854
65
          LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added);
4855
65
      assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic);
4856
65
      stackPush(Builder.createBitCast(
4857
65
          Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {},
4858
65
                                  {Vector, NewIndex}),
4859
65
          Context.Int64x2Ty));
4860
65
      return;
4861
65
    }
4862
0
#endif
4863
4864
#if defined(__aarch64__)
4865
    if (Context.SupportNEON) {
4866
      assuming(LLVM::Core::AArch64NeonTbl1 != LLVM::Core::NotIntrinsic);
4867
      stackPush(Builder.createBitCast(
4868
          Builder.createIntrinsic(LLVM::Core::AArch64NeonTbl1,
4869
                                  {Context.Int8x16Ty}, {Vector, Index}),
4870
          Context.Int64x2Ty));
4871
      return;
4872
    }
4873
#endif
4874
4875
0
    auto Mask = Builder.createVectorSplat(16, LLContext.getInt8(15));
4876
0
    auto Zero = Builder.createVectorSplat(16, LLContext.getInt8(0));
4877
4878
#if defined(__s390x__)
4879
    assuming(LLVM::Core::S390VPerm != LLVM::Core::NotIntrinsic);
4880
    auto Exceed = Builder.createICmpULE(Index, Mask);
4881
    Index = Builder.createSub(Mask, Index);
4882
    auto Result = Builder.createIntrinsic(LLVM::Core::S390VPerm, {},
4883
                                          {Vector, Zero, Index});
4884
    Result = Builder.createSelect(Exceed, Result, Zero);
4885
    stackPush(Builder.createBitCast(Result, Context.Int64x2Ty));
4886
    return;
4887
#endif
4888
4889
    // Fallback case.
4890
    // If the SSSE3 is not supported on the x86_64 platform or
4891
    // the NEON is not supported on the aarch64 platform,
4892
    // then fallback to this.
4893
0
    auto IsOver = Builder.createICmpUGT(Index, Mask);
4894
0
    auto InboundIndex = Builder.createAnd(Index, Mask);
4895
0
    auto Array = Builder.createArray(16, 1);
4896
0
    for (size_t I = 0; I < 16; ++I) {
4897
0
      Builder.createStore(
4898
0
          Builder.createExtractElement(Vector, LLContext.getInt64(I)),
4899
0
          Builder.createInBoundsGEP1(Context.Int8Ty, Array,
4900
0
                                     LLContext.getInt64(I)));
4901
0
    }
4902
0
    LLVM::Value Ret = LLVM::Value::getUndef(Context.Int8x16Ty);
4903
0
    for (size_t I = 0; I < 16; ++I) {
4904
0
      auto Idx =
4905
0
          Builder.createExtractElement(InboundIndex, LLContext.getInt64(I));
4906
0
      auto Value = Builder.createLoad(
4907
0
          Context.Int8Ty,
4908
0
          Builder.createInBoundsGEP1(Context.Int8Ty, Array, Idx));
4909
0
      Ret = Builder.createInsertElement(Ret, Value, LLContext.getInt64(I));
4910
0
    }
4911
0
    Ret = Builder.createSelect(IsOver, Zero, Ret);
4912
0
    stackPush(Builder.createBitCast(Ret, Context.Int64x2Ty));
4913
0
  }
4914
4915
203
  void compileVectorVectorQ15MulSat() noexcept {
4916
203
    compileVectorVectorOp(
4917
203
        Context.Int16x8Ty, [this](auto LHS, auto RHS) noexcept -> LLVM::Value {
4918
203
#if defined(__x86_64__)
4919
203
          if (Context.SupportSSSE3) {
4920
203
            assuming(LLVM::Core::X86SSSE3PMulHrSw128 !=
4921
203
                     LLVM::Core::NotIntrinsic);
4922
203
            auto Result = Builder.createIntrinsic(
4923
203
                LLVM::Core::X86SSSE3PMulHrSw128, {}, {LHS, RHS});
4924
203
            auto IntMaxV = Builder.createVectorSplat(
4925
203
                8, LLContext.getInt16(UINT16_C(0x8000)));
4926
203
            auto NotOver = Builder.createSExt(
4927
203
                Builder.createICmpEQ(Result, IntMaxV), Context.Int16x8Ty);
4928
203
            return Builder.createXor(Result, NotOver);
4929
203
          }
4930
0
#endif
4931
4932
#if defined(__aarch64__)
4933
          if (Context.SupportNEON) {
4934
            assuming(LLVM::Core::AArch64NeonSQRDMulH !=
4935
                     LLVM::Core::NotIntrinsic);
4936
            return Builder.createBinaryIntrinsic(
4937
                LLVM::Core::AArch64NeonSQRDMulH, LHS, RHS);
4938
          }
4939
#endif
4940
4941
          // Fallback case.
4942
          // If the SSSE3 is not supported on the x86_64 platform or
4943
          // the NEON is not supported on the aarch64 platform,
4944
          // then fallback to this.
4945
0
          auto ExtTy = Context.Int16x8Ty.getExtendedElementVectorType();
4946
0
          auto Offset = Builder.createVectorSplat(
4947
0
              8, LLContext.getInt32(UINT32_C(0x4000)));
4948
0
          auto Shift =
4949
0
              Builder.createVectorSplat(8, LLContext.getInt32(UINT32_C(15)));
4950
0
          auto ExtLHS = Builder.createSExt(LHS, ExtTy);
4951
0
          auto ExtRHS = Builder.createSExt(RHS, ExtTy);
4952
0
          auto Result = Builder.createTrunc(
4953
0
              Builder.createAShr(
4954
0
                  Builder.createAdd(Builder.createMul(ExtLHS, ExtRHS), Offset),
4955
0
                  Shift),
4956
0
              Context.Int16x8Ty);
4957
0
          auto IntMaxV = Builder.createVectorSplat(
4958
0
              8, LLContext.getInt16(UINT16_C(0x8000)));
4959
0
          auto NotOver = Builder.createSExt(
4960
0
              Builder.createICmpEQ(Result, IntMaxV), Context.Int16x8Ty);
4961
0
          return Builder.createXor(Result, NotOver);
4962
203
        });
4963
203
  }
4964
310
  void compileVectorVectorSMin(LLVM::Type VectorTy) noexcept {
4965
310
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4966
310
      auto C = Builder.createICmpSLE(LHS, RHS);
4967
310
      return Builder.createSelect(C, LHS, RHS);
4968
310
    });
4969
310
  }
4970
339
  void compileVectorVectorUMin(LLVM::Type VectorTy) noexcept {
4971
339
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4972
339
      auto C = Builder.createICmpULE(LHS, RHS);
4973
339
      return Builder.createSelect(C, LHS, RHS);
4974
339
    });
4975
339
  }
4976
422
  void compileVectorVectorSMax(LLVM::Type VectorTy) noexcept {
4977
422
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4978
422
      auto C = Builder.createICmpSGE(LHS, RHS);
4979
422
      return Builder.createSelect(C, LHS, RHS);
4980
422
    });
4981
422
  }
4982
1.06k
  void compileVectorVectorUMax(LLVM::Type VectorTy) noexcept {
4983
1.06k
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
4984
1.06k
      auto C = Builder.createICmpUGE(LHS, RHS);
4985
1.06k
      return Builder.createSelect(C, LHS, RHS);
4986
1.06k
    });
4987
1.06k
  }
4988
299
  void compileVectorVectorUAvgr(LLVM::Type VectorTy) noexcept {
4989
299
    auto ExtendTy = VectorTy.getExtendedElementVectorType();
4990
299
    compileVectorVectorOp(
4991
299
        VectorTy,
4992
299
        [this, VectorTy, ExtendTy](auto LHS, auto RHS) noexcept -> LLVM::Value {
4993
299
#if defined(__x86_64__)
4994
299
          if (Context.SupportSSE2) {
4995
299
            const auto ID = [VectorTy]() noexcept {
4996
299
              switch (VectorTy.getElementType().getIntegerBitWidth()) {
4997
137
              case 8:
4998
137
                return LLVM::Core::X86SSE2PAvgB;
4999
162
              case 16:
5000
162
                return LLVM::Core::X86SSE2PAvgW;
5001
0
              default:
5002
0
                assumingUnreachable();
5003
299
              }
5004
299
            }();
5005
299
            assuming(ID != LLVM::Core::NotIntrinsic);
5006
299
            return Builder.createIntrinsic(ID, {}, {LHS, RHS});
5007
299
          }
5008
0
#endif
5009
5010
#if defined(__aarch64__)
5011
          if (Context.SupportNEON) {
5012
            assuming(LLVM::Core::AArch64NeonURHAdd != LLVM::Core::NotIntrinsic);
5013
            return Builder.createBinaryIntrinsic(LLVM::Core::AArch64NeonURHAdd,
5014
                                                 LHS, RHS);
5015
          }
5016
#endif
5017
5018
          // Fallback case.
5019
          // If the SSE2 is not supported on the x86_64 platform or
5020
          // the NEON is not supported on the aarch64 platform,
5021
          // then fallback to this.
5022
0
          auto EL = Builder.createZExt(LHS, ExtendTy);
5023
0
          auto ER = Builder.createZExt(RHS, ExtendTy);
5024
0
          auto One = Builder.createZExt(
5025
0
              Builder.createVectorSplat(ExtendTy.getVectorSize(),
5026
0
                                        LLContext.getTrue()),
5027
0
              ExtendTy);
5028
0
          return Builder.createTrunc(
5029
0
              Builder.createLShr(
5030
0
                  Builder.createAdd(Builder.createAdd(EL, ER), One), One),
5031
0
              VectorTy);
5032
299
        });
5033
299
  }
5034
699
  void compileVectorNarrow(LLVM::Type FromTy, bool Signed) noexcept {
5035
699
    auto [MinInt,
5036
699
          MaxInt] = [&]() noexcept -> std::tuple<LLVM::Value, LLVM::Value> {
5037
699
      switch (FromTy.getElementType().getIntegerBitWidth()) {
5038
295
      case 16: {
5039
295
        const auto Min =
5040
295
            static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::min()
5041
295
                                        : std::numeric_limits<uint8_t>::min());
5042
295
        const auto Max =
5043
295
            static_cast<int16_t>(Signed ? std::numeric_limits<int8_t>::max()
5044
295
                                        : std::numeric_limits<uint8_t>::max());
5045
295
        return {LLContext.getInt16(static_cast<uint16_t>(Min)),
5046
295
                LLContext.getInt16(static_cast<uint16_t>(Max))};
5047
0
      }
5048
404
      case 32: {
5049
404
        const auto Min =
5050
404
            static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::min()
5051
404
                                        : std::numeric_limits<uint16_t>::min());
5052
404
        const auto Max =
5053
404
            static_cast<int32_t>(Signed ? std::numeric_limits<int16_t>::max()
5054
404
                                        : std::numeric_limits<uint16_t>::max());
5055
404
        return {LLContext.getInt32(static_cast<uint32_t>(Min)),
5056
404
                LLContext.getInt32(static_cast<uint32_t>(Max))};
5057
0
      }
5058
0
      default:
5059
0
        assumingUnreachable();
5060
699
      }
5061
699
    }();
5062
699
    const auto Count = FromTy.getVectorSize();
5063
699
    auto VMin = Builder.createVectorSplat(Count, MinInt);
5064
699
    auto VMax = Builder.createVectorSplat(Count, MaxInt);
5065
5066
699
    auto TruncTy = FromTy.getTruncatedElementVectorType();
5067
5068
699
    auto F2 = Builder.createBitCast(stackPop(), FromTy);
5069
699
    F2 = Builder.createSelect(Builder.createICmpSLT(F2, VMin), VMin, F2);
5070
699
    F2 = Builder.createSelect(Builder.createICmpSGT(F2, VMax), VMax, F2);
5071
699
    F2 = Builder.createTrunc(F2, TruncTy);
5072
5073
699
    auto F1 = Builder.createBitCast(stackPop(), FromTy);
5074
699
    F1 = Builder.createSelect(Builder.createICmpSLT(F1, VMin), VMin, F1);
5075
699
    F1 = Builder.createSelect(Builder.createICmpSGT(F1, VMax), VMax, F1);
5076
699
    F1 = Builder.createTrunc(F1, TruncTy);
5077
5078
699
    std::vector<uint32_t> Mask(Count * 2);
5079
699
    std::iota(Mask.begin(), Mask.end(), 0);
5080
699
    auto V = Endian::native == Endian::little
5081
699
                 ? Builder.createShuffleVector(
5082
699
                       F1, F2, LLVM::Value::getConstVector32(LLContext, Mask))
5083
699
                 : Builder.createShuffleVector(
5084
0
                       F2, F1, LLVM::Value::getConstVector32(LLContext, Mask));
5085
699
    stackPush(Builder.createBitCast(V, Context.Int64x2Ty));
5086
699
  }
5087
6.09k
  void compileVectorExtend(LLVM::Type FromTy, bool Signed, bool Low) noexcept {
5088
6.09k
    auto ExtTy = FromTy.getExtendedElementVectorType();
5089
6.09k
    const auto Count = FromTy.getVectorSize();
5090
6.09k
    std::vector<uint32_t> Mask(Count / 2);
5091
    if constexpr (Endian::native == Endian::big) {
5092
      Low = !Low;
5093
    }
5094
6.09k
    std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
5095
6.09k
    auto R = Builder.createBitCast(Stack.back(), FromTy);
5096
6.09k
    if (Signed) {
5097
2.74k
      R = Builder.createSExt(R, ExtTy);
5098
3.34k
    } else {
5099
3.34k
      R = Builder.createZExt(R, ExtTy);
5100
3.34k
    }
5101
6.09k
    R = Builder.createShuffleVector(
5102
6.09k
        R, LLVM::Value::getUndef(ExtTy),
5103
6.09k
        LLVM::Value::getConstVector32(LLContext, Mask));
5104
6.09k
    Stack.back() = Builder.createBitCast(R, Context.Int64x2Ty);
5105
6.09k
  }
5106
1.95k
  void compileVectorExtMul(LLVM::Type FromTy, bool Signed, bool Low) noexcept {
5107
1.95k
    auto ExtTy = FromTy.getExtendedElementVectorType();
5108
1.95k
    const auto Count = FromTy.getVectorSize();
5109
1.95k
    std::vector<uint32_t> Mask(Count / 2);
5110
1.95k
    std::iota(Mask.begin(), Mask.end(), Low ? 0 : Count / 2);
5111
3.91k
    auto Extend = [this, FromTy, Signed, ExtTy, &Mask](LLVM::Value R) noexcept {
5112
3.91k
      R = Builder.createBitCast(R, FromTy);
5113
3.91k
      if (Signed) {
5114
1.96k
        R = Builder.createSExt(R, ExtTy);
5115
1.96k
      } else {
5116
1.95k
        R = Builder.createZExt(R, ExtTy);
5117
1.95k
      }
5118
3.91k
      return Builder.createShuffleVector(
5119
3.91k
          R, LLVM::Value::getUndef(ExtTy),
5120
3.91k
          LLVM::Value::getConstVector32(LLContext, Mask));
5121
3.91k
    };
5122
1.95k
    auto RHS = Extend(stackPop());
5123
1.95k
    auto LHS = Extend(stackPop());
5124
1.95k
    stackPush(
5125
1.95k
        Builder.createBitCast(Builder.createMul(RHS, LHS), Context.Int64x2Ty));
5126
1.95k
  }
5127
2.42k
  void compileVectorExtAddPairwise(LLVM::Type VectorTy, bool Signed) noexcept {
5128
2.42k
    compileVectorOp(
5129
2.42k
        VectorTy, [this, VectorTy, Signed](auto V) noexcept -> LLVM::Value {
5130
2.42k
          auto ExtTy = VectorTy.getExtendedElementVectorType()
5131
2.42k
                           .getHalfElementsVectorType();
5132
2.42k
#if defined(__x86_64__)
5133
2.42k
          const auto Count = VectorTy.getVectorSize();
5134
2.42k
          if (Context.SupportXOP) {
5135
0
            const auto ID = [Count, Signed]() noexcept {
5136
0
              switch (Count) {
5137
0
              case 8:
5138
0
                return Signed ? LLVM::Core::X86XOpVPHAddWD
5139
0
                              : LLVM::Core::X86XOpVPHAddUWD;
5140
0
              case 16:
5141
0
                return Signed ? LLVM::Core::X86XOpVPHAddBW
5142
0
                              : LLVM::Core::X86XOpVPHAddUBW;
5143
0
              default:
5144
0
                assumingUnreachable();
5145
0
              }
5146
0
            }();
5147
0
            assuming(ID != LLVM::Core::NotIntrinsic);
5148
0
            return Builder.createUnaryIntrinsic(ID, V);
5149
0
          }
5150
2.42k
          if (Context.SupportSSSE3 && Count == 16) {
5151
606
            assuming(LLVM::Core::X86SSSE3PMAddUbSw128 !=
5152
606
                     LLVM::Core::NotIntrinsic);
5153
606
            if (Signed) {
5154
276
              return Builder.createIntrinsic(
5155
276
                  LLVM::Core::X86SSSE3PMAddUbSw128, {},
5156
276
                  {Builder.createVectorSplat(16, LLContext.getInt8(1)), V});
5157
330
            } else {
5158
330
              return Builder.createIntrinsic(
5159
330
                  LLVM::Core::X86SSSE3PMAddUbSw128, {},
5160
330
                  {V, Builder.createVectorSplat(16, LLContext.getInt8(1))});
5161
330
            }
5162
606
          }
5163
1.81k
          if (Context.SupportSSE2 && Count == 8) {
5164
1.81k
            assuming(LLVM::Core::X86SSE2PMAddWd != LLVM::Core::NotIntrinsic);
5165
1.81k
            if (Signed) {
5166
1.27k
              return Builder.createIntrinsic(
5167
1.27k
                  LLVM::Core::X86SSE2PMAddWd, {},
5168
1.27k
                  {V, Builder.createVectorSplat(8, LLContext.getInt16(1))});
5169
1.27k
            } else {
5170
544
              V = Builder.createXor(
5171
544
                  V, Builder.createVectorSplat(8, LLContext.getInt16(0x8000)));
5172
544
              V = Builder.createIntrinsic(
5173
544
                  LLVM::Core::X86SSE2PMAddWd, {},
5174
544
                  {V, Builder.createVectorSplat(8, LLContext.getInt16(1))});
5175
544
              return Builder.createAdd(
5176
544
                  V, Builder.createVectorSplat(4, LLContext.getInt32(0x10000)));
5177
544
            }
5178
1.81k
          }
5179
0
#endif
5180
5181
#if defined(__aarch64__)
5182
          if (Context.SupportNEON) {
5183
            const auto ID = Signed ? LLVM::Core::AArch64NeonSAddLP
5184
                                   : LLVM::Core::AArch64NeonUAddLP;
5185
            assuming(ID != LLVM::Core::NotIntrinsic);
5186
            return Builder.createIntrinsic(ID, {ExtTy, VectorTy}, {V});
5187
          }
5188
#endif
5189
5190
          // Fallback case.
5191
          // If the XOP, SSSE3, or SSE2 is not supported on the x86_64 platform
5192
          // or the NEON is not supported on the aarch64 platform,
5193
          // then fallback to this.
5194
0
          auto Width = LLVM::Value::getConstInt(
5195
0
              ExtTy.getElementType(),
5196
0
              VectorTy.getElementType().getIntegerBitWidth());
5197
0
          Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width);
5198
0
          auto EV = Builder.createBitCast(V, ExtTy);
5199
0
          LLVM::Value L, R;
5200
0
          if (Signed) {
5201
0
            L = Builder.createAShr(EV, Width);
5202
0
            R = Builder.createAShr(Builder.createShl(EV, Width), Width);
5203
0
          } else {
5204
0
            L = Builder.createLShr(EV, Width);
5205
0
            R = Builder.createLShr(Builder.createShl(EV, Width), Width);
5206
0
          }
5207
0
          return Builder.createAdd(L, R);
5208
1.81k
        });
5209
2.42k
  }
5210
565
  void compileVectorFAbs(LLVM::Type VectorTy) noexcept {
5211
565
    compileVectorOp(VectorTy, [this](auto V) noexcept {
5212
565
      assuming(LLVM::Core::Fabs != LLVM::Core::NotIntrinsic);
5213
565
      return Builder.createUnaryIntrinsic(LLVM::Core::Fabs, V);
5214
565
    });
5215
565
  }
5216
937
  void compileVectorFNeg(LLVM::Type VectorTy) noexcept {
5217
937
    compileVectorOp(VectorTy,
5218
937
                    [this](auto V) noexcept { return Builder.createFNeg(V); });
5219
937
  }
5220
345
  void compileVectorFSqrt(LLVM::Type VectorTy) noexcept {
5221
345
    compileVectorOp(VectorTy, [this](auto V) noexcept {
5222
345
      assuming(LLVM::Core::Sqrt != LLVM::Core::NotIntrinsic);
5223
345
      return Builder.createUnaryIntrinsic(LLVM::Core::Sqrt, V);
5224
345
    });
5225
345
  }
5226
1.18k
  void compileVectorFCeil(LLVM::Type VectorTy) noexcept {
5227
1.18k
    compileVectorOp(VectorTy, [this](auto V) noexcept {
5228
1.18k
      assuming(LLVM::Core::Ceil != LLVM::Core::NotIntrinsic);
5229
1.18k
      return Builder.createUnaryIntrinsic(LLVM::Core::Ceil, V);
5230
1.18k
    });
5231
1.18k
  }
5232
2.17k
  void compileVectorFFloor(LLVM::Type VectorTy) noexcept {
5233
2.17k
    compileVectorOp(VectorTy, [this](auto V) noexcept {
5234
2.17k
      assuming(LLVM::Core::Floor != LLVM::Core::NotIntrinsic);
5235
2.17k
      return Builder.createUnaryIntrinsic(LLVM::Core::Floor, V);
5236
2.17k
    });
5237
2.17k
  }
5238
1.62k
  void compileVectorFTrunc(LLVM::Type VectorTy) noexcept {
5239
1.62k
    compileVectorOp(VectorTy, [this](auto V) noexcept {
5240
1.62k
      assuming(LLVM::Core::Trunc != LLVM::Core::NotIntrinsic);
5241
1.62k
      return Builder.createUnaryIntrinsic(LLVM::Core::Trunc, V);
5242
1.62k
    });
5243
1.62k
  }
5244
344
  void compileVectorFNearest(LLVM::Type VectorTy) noexcept {
5245
344
    compileVectorOp(VectorTy, [&](auto V) noexcept {
5246
344
#if LLVM_VERSION_MAJOR >= 12 && !defined(__s390x__)
5247
344
      assuming(LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic);
5248
344
      if (LLVM::Core::Roundeven != LLVM::Core::NotIntrinsic) {
5249
344
        return Builder.createUnaryIntrinsic(LLVM::Core::Roundeven, V);
5250
344
      }
5251
0
#endif
5252
5253
0
#if defined(__x86_64__)
5254
0
      if (Context.SupportSSE4_1) {
5255
0
        const bool IsFloat = VectorTy.getElementType().isFloatTy();
5256
0
        auto ID =
5257
0
            IsFloat ? LLVM::Core::X86SSE41RoundPs : LLVM::Core::X86SSE41RoundPd;
5258
0
        assuming(ID != LLVM::Core::NotIntrinsic);
5259
0
        return Builder.createIntrinsic(ID, {}, {V, LLContext.getInt32(8)});
5260
0
      }
5261
0
#endif
5262
5263
#if defined(__aarch64__)
5264
      if (Context.SupportNEON &&
5265
          LLVM::Core::AArch64NeonFRIntN != LLVM::Core::NotIntrinsic) {
5266
        return Builder.createUnaryIntrinsic(LLVM::Core::AArch64NeonFRIntN, V);
5267
      }
5268
#endif
5269
5270
      // Fallback case.
5271
      // If the SSE4.1 is not supported on the x86_64 platform or
5272
      // the NEON is not supported on the aarch64 platform,
5273
      // then fallback to this.
5274
0
      assuming(LLVM::Core::Nearbyint != LLVM::Core::NotIntrinsic);
5275
0
      return Builder.createUnaryIntrinsic(LLVM::Core::Nearbyint, V);
5276
0
    });
5277
344
  }
5278
181
  void compileVectorVectorFAdd(LLVM::Type VectorTy) noexcept {
5279
181
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5280
181
      return Builder.createFAdd(LHS, RHS);
5281
181
    });
5282
181
  }
5283
484
  void compileVectorVectorFSub(LLVM::Type VectorTy) noexcept {
5284
484
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5285
484
      return Builder.createFSub(LHS, RHS);
5286
484
    });
5287
484
  }
5288
183
  void compileVectorVectorFMul(LLVM::Type VectorTy) noexcept {
5289
183
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5290
183
      return Builder.createFMul(LHS, RHS);
5291
183
    });
5292
183
  }
5293
226
  void compileVectorVectorFDiv(LLVM::Type VectorTy) noexcept {
5294
226
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5295
226
      return Builder.createFDiv(LHS, RHS);
5296
226
    });
5297
226
  }
5298
289
  void compileVectorVectorFMin(LLVM::Type VectorTy) noexcept {
5299
289
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5300
289
      auto LNaN = Builder.createFCmpUNO(LHS, LHS);
5301
289
      auto RNaN = Builder.createFCmpUNO(RHS, RHS);
5302
289
      auto OLT = Builder.createFCmpOLT(LHS, RHS);
5303
289
      auto OGT = Builder.createFCmpOGT(LHS, RHS);
5304
289
      auto Ret = Builder.createBitCast(
5305
289
          Builder.createOr(Builder.createBitCast(LHS, Context.Int64x2Ty),
5306
289
                           Builder.createBitCast(RHS, Context.Int64x2Ty)),
5307
289
          LHS.getType());
5308
289
      Ret = Builder.createSelect(OGT, RHS, Ret);
5309
289
      Ret = Builder.createSelect(OLT, LHS, Ret);
5310
289
      Ret = Builder.createSelect(RNaN, RHS, Ret);
5311
289
      Ret = Builder.createSelect(LNaN, LHS, Ret);
5312
289
      return Ret;
5313
289
    });
5314
289
  }
5315
195
  void compileVectorVectorFMax(LLVM::Type VectorTy) noexcept {
5316
195
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5317
195
      auto LNaN = Builder.createFCmpUNO(LHS, LHS);
5318
195
      auto RNaN = Builder.createFCmpUNO(RHS, RHS);
5319
195
      auto OLT = Builder.createFCmpOLT(LHS, RHS);
5320
195
      auto OGT = Builder.createFCmpOGT(LHS, RHS);
5321
195
      auto Ret = Builder.createBitCast(
5322
195
          Builder.createAnd(Builder.createBitCast(LHS, Context.Int64x2Ty),
5323
195
                            Builder.createBitCast(RHS, Context.Int64x2Ty)),
5324
195
          LHS.getType());
5325
195
      Ret = Builder.createSelect(OLT, RHS, Ret);
5326
195
      Ret = Builder.createSelect(OGT, LHS, Ret);
5327
195
      Ret = Builder.createSelect(RNaN, RHS, Ret);
5328
195
      Ret = Builder.createSelect(LNaN, LHS, Ret);
5329
195
      return Ret;
5330
195
    });
5331
195
  }
5332
376
  void compileVectorVectorFPMin(LLVM::Type VectorTy) noexcept {
5333
376
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5334
376
      auto Cmp = Builder.createFCmpOLT(RHS, LHS);
5335
376
      return Builder.createSelect(Cmp, RHS, LHS);
5336
376
    });
5337
376
  }
5338
314
  void compileVectorVectorFPMax(LLVM::Type VectorTy) noexcept {
5339
314
    compileVectorVectorOp(VectorTy, [this](auto LHS, auto RHS) noexcept {
5340
314
      auto Cmp = Builder.createFCmpOGT(RHS, LHS);
5341
314
      return Builder.createSelect(Cmp, RHS, LHS);
5342
314
    });
5343
314
  }
5344
1.00k
  void compileVectorTruncSatS32(LLVM::Type VectorTy, bool PadZero) noexcept {
5345
1.00k
    compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
5346
1.00k
      const auto Size = VectorTy.getVectorSize();
5347
1.00k
      auto FPTy = VectorTy.getElementType();
5348
1.00k
      auto IntMin = LLContext.getInt32(
5349
1.00k
          static_cast<uint32_t>(std::numeric_limits<int32_t>::min()));
5350
1.00k
      auto IntMax = LLContext.getInt32(
5351
1.00k
          static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
5352
1.00k
      auto IntMinV = Builder.createVectorSplat(Size, IntMin);
5353
1.00k
      auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
5354
1.00k
      auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType());
5355
1.00k
      auto FPMin = Builder.createSIToFP(IntMin, FPTy);
5356
1.00k
      auto FPMax = Builder.createSIToFP(IntMax, FPTy);
5357
1.00k
      auto FPMinV = Builder.createVectorSplat(Size, FPMin);
5358
1.00k
      auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
5359
5360
1.00k
      auto Normal = Builder.createFCmpORD(V, V);
5361
1.00k
      auto NotUnder = Builder.createFCmpUGE(V, FPMinV);
5362
1.00k
      auto NotOver = Builder.createFCmpULT(V, FPMaxV);
5363
1.00k
      V = Builder.createFPToSI(
5364
1.00k
          V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
5365
1.00k
      V = Builder.createSelect(Normal, V, IntZeroV);
5366
1.00k
      V = Builder.createSelect(NotUnder, V, IntMinV);
5367
1.00k
      V = Builder.createSelect(NotOver, V, IntMaxV);
5368
1.00k
      if (PadZero) {
5369
745
        std::vector<uint32_t> Mask(Size * 2);
5370
745
        std::iota(Mask.begin(), Mask.end(), 0);
5371
745
        if constexpr (Endian::native == Endian::little) {
5372
745
          V = Builder.createShuffleVector(
5373
745
              V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask));
5374
        } else {
5375
          V = Builder.createShuffleVector(
5376
              IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask));
5377
        }
5378
745
      }
5379
1.00k
      return V;
5380
1.00k
    });
5381
1.00k
  }
5382
5.83k
  void compileVectorTruncSatU32(LLVM::Type VectorTy, bool PadZero) noexcept {
5383
5.83k
    compileVectorOp(VectorTy, [this, VectorTy, PadZero](auto V) noexcept {
5384
5.83k
      const auto Size = VectorTy.getVectorSize();
5385
5.83k
      auto FPTy = VectorTy.getElementType();
5386
5.83k
      auto IntMin = LLContext.getInt32(std::numeric_limits<uint32_t>::min());
5387
5.83k
      auto IntMax = LLContext.getInt32(std::numeric_limits<uint32_t>::max());
5388
5.83k
      auto IntMinV = Builder.createVectorSplat(Size, IntMin);
5389
5.83k
      auto IntMaxV = Builder.createVectorSplat(Size, IntMax);
5390
5.83k
      auto FPMin = Builder.createUIToFP(IntMin, FPTy);
5391
5.83k
      auto FPMax = Builder.createUIToFP(IntMax, FPTy);
5392
5.83k
      auto FPMinV = Builder.createVectorSplat(Size, FPMin);
5393
5.83k
      auto FPMaxV = Builder.createVectorSplat(Size, FPMax);
5394
5395
5.83k
      auto NotUnder = Builder.createFCmpOGE(V, FPMinV);
5396
5.83k
      auto NotOver = Builder.createFCmpULT(V, FPMaxV);
5397
5.83k
      V = Builder.createFPToUI(
5398
5.83k
          V, LLVM::Type::getVectorType(LLContext.getInt32Ty(), Size));
5399
5.83k
      V = Builder.createSelect(NotUnder, V, IntMinV);
5400
5.83k
      V = Builder.createSelect(NotOver, V, IntMaxV);
5401
5.83k
      if (PadZero) {
5402
2.13k
        auto IntZeroV = LLVM::Value::getConstNull(IntMinV.getType());
5403
2.13k
        std::vector<uint32_t> Mask(Size * 2);
5404
2.13k
        std::iota(Mask.begin(), Mask.end(), 0);
5405
2.13k
        if constexpr (Endian::native == Endian::little) {
5406
2.13k
          V = Builder.createShuffleVector(
5407
2.13k
              V, IntZeroV, LLVM::Value::getConstVector32(LLContext, Mask));
5408
        } else {
5409
          V = Builder.createShuffleVector(
5410
              IntZeroV, V, LLVM::Value::getConstVector32(LLContext, Mask));
5411
        }
5412
2.13k
      }
5413
5.83k
      return V;
5414
5.83k
    });
5415
5.83k
  }
5416
  void compileVectorConvertS(LLVM::Type VectorTy, LLVM::Type FPVectorTy,
5417
654
                             bool Low) noexcept {
5418
654
    compileVectorOp(VectorTy,
5419
654
                    [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
5420
654
                      if (Low) {
5421
331
                        const auto Size = VectorTy.getVectorSize() / 2;
5422
331
                        std::vector<uint32_t> Mask(Size);
5423
331
                        if constexpr (Endian::native == Endian::little) {
5424
331
                          std::iota(Mask.begin(), Mask.end(), 0);
5425
                        } else {
5426
                          std::iota(Mask.begin(), Mask.end(), Size);
5427
                        }
5428
331
                        V = Builder.createShuffleVector(
5429
331
                            V, LLVM::Value::getUndef(VectorTy),
5430
331
                            LLVM::Value::getConstVector32(LLContext, Mask));
5431
331
                      }
5432
654
                      return Builder.createSIToFP(V, FPVectorTy);
5433
654
                    });
5434
654
  }
5435
  void compileVectorConvertU(LLVM::Type VectorTy, LLVM::Type FPVectorTy,
5436
2.05k
                             bool Low) noexcept {
5437
2.05k
    compileVectorOp(VectorTy,
5438
2.05k
                    [this, VectorTy, FPVectorTy, Low](auto V) noexcept {
5439
2.05k
                      if (Low) {
5440
1.31k
                        const auto Size = VectorTy.getVectorSize() / 2;
5441
1.31k
                        std::vector<uint32_t> Mask(Size);
5442
1.31k
                        if constexpr (Endian::native == Endian::little) {
5443
1.31k
                          std::iota(Mask.begin(), Mask.end(), 0);
5444
                        } else {
5445
                          std::iota(Mask.begin(), Mask.end(), Size);
5446
                        }
5447
1.31k
                        V = Builder.createShuffleVector(
5448
1.31k
                            V, LLVM::Value::getUndef(VectorTy),
5449
1.31k
                            LLVM::Value::getConstVector32(LLContext, Mask));
5450
1.31k
                      }
5451
2.05k
                      return Builder.createUIToFP(V, FPVectorTy);
5452
2.05k
                    });
5453
2.05k
  }
5454
527
  void compileVectorDemote() noexcept {
5455
527
    compileVectorOp(Context.Doublex2Ty, [this](auto V) noexcept {
5456
527
      auto Demoted = Builder.createFPTrunc(
5457
527
          V, LLVM::Type::getVectorType(Context.FloatTy, 2));
5458
527
      auto ZeroV = LLVM::Value::getConstNull(Demoted.getType());
5459
527
      if constexpr (Endian::native == Endian::little) {
5460
527
        return Builder.createShuffleVector(
5461
527
            Demoted, ZeroV,
5462
527
            LLVM::Value::getConstVector32(LLContext, {0u, 1u, 2u, 3u}));
5463
      } else {
5464
        return Builder.createShuffleVector(
5465
            Demoted, ZeroV,
5466
            LLVM::Value::getConstVector32(LLContext, {3u, 2u, 1u, 0u}));
5467
      }
5468
527
    });
5469
527
  }
5470
599
  void compileVectorPromote() noexcept {
5471
599
    compileVectorOp(Context.Floatx4Ty, [this](auto V) noexcept {
5472
599
      auto UndefV = LLVM::Value::getUndef(V.getType());
5473
599
      auto Low = Builder.createShuffleVector(
5474
599
          V, UndefV, LLVM::Value::getConstVector32(LLContext, {0u, 1u}));
5475
599
      return Builder.createFPExt(
5476
599
          Low, LLVM::Type::getVectorType(Context.DoubleTy, 2));
5477
599
    });
5478
599
  }
5479
5480
0
  void compileVectorVectorMAdd(LLVM::Type VectorTy) noexcept {
5481
0
    auto C = Builder.createBitCast(stackPop(), VectorTy);
5482
0
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
5483
0
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
5484
0
    stackPush(Builder.createBitCast(
5485
0
        Builder.createFAdd(Builder.createFMul(LHS, RHS), C),
5486
0
        Context.Int64x2Ty));
5487
0
  }
5488
5489
0
  void compileVectorVectorNMAdd(LLVM::Type VectorTy) noexcept {
5490
0
    auto C = Builder.createBitCast(stackPop(), VectorTy);
5491
0
    auto RHS = Builder.createBitCast(stackPop(), VectorTy);
5492
0
    auto LHS = Builder.createBitCast(stackPop(), VectorTy);
5493
0
    stackPush(Builder.createBitCast(
5494
0
        Builder.createFAdd(Builder.createFMul(Builder.createFNeg(LHS), RHS), C),
5495
0
        Context.Int64x2Ty));
5496
0
  }
5497
5498
0
  void compileVectorRelaxedIntegerDotProduct() noexcept {
5499
0
    auto OriTy = Context.Int8x16Ty;
5500
0
    auto ExtTy = Context.Int16x8Ty;
5501
0
    auto RHS = Builder.createBitCast(stackPop(), OriTy);
5502
0
    auto LHS = Builder.createBitCast(stackPop(), OriTy);
5503
0
#if defined(__x86_64__)
5504
0
    if (Context.SupportSSSE3) {
5505
0
      assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic);
5506
      // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS)
5507
      // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both
5508
      // side to match the WebAssembly spec
5509
0
      return stackPush(Builder.createBitCast(
5510
0
          Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {},
5511
0
                                  {RHS, LHS}),
5512
0
          Context.Int64x2Ty));
5513
0
    }
5514
0
#endif
5515
0
    auto Width = LLVM::Value::getConstInt(
5516
0
        ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth());
5517
0
    Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width);
5518
0
    auto EA = Builder.createBitCast(LHS, ExtTy);
5519
0
    auto EB = Builder.createBitCast(RHS, ExtTy);
5520
5521
0
    LLVM::Value AL, AR, BL, BR;
5522
0
    AL = Builder.createAShr(EA, Width);
5523
0
    AR = Builder.createAShr(Builder.createShl(EA, Width), Width);
5524
0
    BL = Builder.createAShr(EB, Width);
5525
0
    BR = Builder.createAShr(Builder.createShl(EB, Width), Width);
5526
5527
0
    return stackPush(Builder.createBitCast(
5528
0
        Builder.createAdd(Builder.createMul(AL, BL), Builder.createMul(AR, BR)),
5529
0
        Context.Int64x2Ty));
5530
0
  }
5531
5532
0
  void compileVectorRelaxedIntegerDotProductAdd() noexcept {
5533
0
    auto OriTy = Context.Int8x16Ty;
5534
0
    auto ExtTy = Context.Int16x8Ty;
5535
0
    auto FinTy = Context.Int32x4Ty;
5536
0
    auto VC = Builder.createBitCast(stackPop(), FinTy);
5537
0
    auto RHS = Builder.createBitCast(stackPop(), OriTy);
5538
0
    auto LHS = Builder.createBitCast(stackPop(), OriTy);
5539
0
    LLVM::Value IM;
5540
0
#if defined(__x86_64__)
5541
0
    if (Context.SupportSSSE3) {
5542
0
      assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic);
5543
      // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS)
5544
      // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both
5545
      // side to match the WebAssembly spec
5546
0
      IM = Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {},
5547
0
                                   {RHS, LHS});
5548
0
    } else
5549
0
#endif
5550
0
    {
5551
0
      auto Width = LLVM::Value::getConstInt(
5552
0
          ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth());
5553
0
      Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width);
5554
0
      auto EA = Builder.createBitCast(LHS, ExtTy);
5555
0
      auto EB = Builder.createBitCast(RHS, ExtTy);
5556
5557
0
      LLVM::Value AL, AR, BL, BR;
5558
0
      AL = Builder.createAShr(EA, Width);
5559
0
      AR = Builder.createAShr(Builder.createShl(EA, Width), Width);
5560
0
      BL = Builder.createAShr(EB, Width);
5561
0
      BR = Builder.createAShr(Builder.createShl(EB, Width), Width);
5562
0
      IM = Builder.createAdd(Builder.createMul(AL, BL),
5563
0
                             Builder.createMul(AR, BR));
5564
0
    }
5565
5566
0
    auto Width = LLVM::Value::getConstInt(
5567
0
        FinTy.getElementType(), ExtTy.getElementType().getIntegerBitWidth());
5568
0
    Width = Builder.createVectorSplat(FinTy.getVectorSize(), Width);
5569
0
    auto IME = Builder.createBitCast(IM, FinTy);
5570
0
    auto L = Builder.createAShr(IME, Width);
5571
0
    auto R = Builder.createAShr(Builder.createShl(IME, Width), Width);
5572
5573
0
    return stackPush(Builder.createBitCast(
5574
0
        Builder.createAdd(Builder.createAdd(L, R), VC), Context.Int64x2Ty));
5575
0
  }
5576
5577
  void
5578
  enterBlock(LLVM::BasicBlock JumpBlock, LLVM::BasicBlock NextBlock,
5579
             LLVM::BasicBlock ElseBlock, std::vector<LLVM::Value> Args,
5580
             std::pair<std::vector<ValType>, std::vector<ValType>> Type,
5581
             std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
5582
21.2k
                 ReturnPHI = {}) noexcept {
5583
21.2k
    assuming(Type.first.size() == Args.size());
5584
21.2k
    for (auto &Value : Args) {
5585
4.47k
      stackPush(Value);
5586
4.47k
    }
5587
21.2k
    const auto Unreachable = isUnreachable();
5588
21.2k
    ControlStack.emplace_back(Stack.size() - Args.size(), Unreachable,
5589
21.2k
                              JumpBlock, NextBlock, ElseBlock, std::move(Args),
5590
21.2k
                              std::move(Type), std::move(ReturnPHI));
5591
21.2k
  }
5592
5593
21.2k
  Control leaveBlock() noexcept {
5594
21.2k
    Control Entry = std::move(ControlStack.back());
5595
21.2k
    ControlStack.pop_back();
5596
5597
21.2k
    auto NextBlock = Entry.NextBlock ? Entry.NextBlock : Entry.JumpBlock;
5598
21.2k
    if (!Entry.Unreachable) {
5599
13.3k
      const auto &ReturnType = Entry.Type.second;
5600
13.3k
      if (!ReturnType.empty()) {
5601
10.2k
        std::vector<LLVM::Value> Rets(ReturnType.size());
5602
20.8k
        for (size_t I = 0; I < Rets.size(); ++I) {
5603
10.6k
          const size_t J = Rets.size() - 1 - I;
5604
10.6k
          Rets[J] = stackPop();
5605
10.6k
        }
5606
10.2k
        Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
5607
10.2k
      }
5608
13.3k
      Builder.createBr(NextBlock);
5609
13.3k
    } else {
5610
7.89k
      Builder.createUnreachable();
5611
7.89k
    }
5612
21.2k
    Builder.positionAtEnd(NextBlock);
5613
21.2k
    Stack.erase(Stack.begin() + static_cast<int64_t>(Entry.StackSize),
5614
21.2k
                Stack.end());
5615
21.2k
    return Entry;
5616
21.2k
  }
5617
5618
5.11k
  void checkStop() noexcept {
5619
5.11k
    if (!Interruptible) {
5620
5.11k
      return;
5621
5.11k
    }
5622
0
    auto NotStopBB = LLVM::BasicBlock::create(LLContext, F.Fn, "NotStop");
5623
0
    auto StopToken = Builder.createAtomicRMW(
5624
0
        LLVMAtomicRMWBinOpXchg, Context.getStopToken(Builder, ExecCtx),
5625
0
        LLContext.getInt32(0), LLVMAtomicOrderingMonotonic);
5626
#if LLVM_VERSION_MAJOR >= 13
5627
    StopToken.setAlignment(32);
5628
#endif
5629
0
    auto NotStop = Builder.createLikely(
5630
0
        Builder.createICmpEQ(StopToken, LLContext.getInt32(0)));
5631
0
    Builder.createCondBr(NotStop, NotStopBB,
5632
0
                         getTrapBB(ErrCode::Value::Interrupted));
5633
5634
0
    Builder.positionAtEnd(NotStopBB);
5635
0
  }
5636
5637
5.63k
  void setUnreachable() noexcept {
5638
5.63k
    if (ControlStack.empty()) {
5639
0
      IsUnreachable = true;
5640
5.63k
    } else {
5641
5.63k
      ControlStack.back().Unreachable = true;
5642
5.63k
    }
5643
5.63k
  }
5644
5645
1.57M
  bool isUnreachable() const noexcept {
5646
1.57M
    if (ControlStack.empty()) {
5647
10.7k
      return IsUnreachable;
5648
1.56M
    } else {
5649
1.56M
      return ControlStack.back().Unreachable;
5650
1.56M
    }
5651
1.57M
  }
5652
5653
  void
5654
  buildPHI(Span<const ValType> RetType,
5655
           Span<const std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
5656
18.5k
               Incomings) noexcept {
5657
18.5k
    if (isVoidReturn(RetType)) {
5658
5.70k
      return;
5659
5.70k
    }
5660
12.8k
    std::vector<LLVM::Value> Nodes;
5661
12.8k
    if (Incomings.size() == 0) {
5662
2.46k
      const auto &Types = toLLVMTypeVector(LLContext, RetType);
5663
2.46k
      Nodes.reserve(Types.size());
5664
2.80k
      for (LLVM::Type Type : Types) {
5665
2.80k
        Nodes.push_back(LLVM::Value::getUndef(Type));
5666
2.80k
      }
5667
10.4k
    } else if (Incomings.size() == 1) {
5668
9.31k
      Nodes = std::move(std::get<0>(Incomings.front()));
5669
9.31k
    } else {
5670
1.10k
      const auto &Types = toLLVMTypeVector(LLContext, RetType);
5671
1.10k
      Nodes.reserve(Types.size());
5672
2.31k
      for (size_t I = 0; I < Types.size(); ++I) {
5673
1.20k
        auto PHIRet = Builder.createPHI(Types[I]);
5674
3.26k
        for (auto &[Value, BB] : Incomings) {
5675
3.26k
          assuming(Value.size() == Types.size());
5676
3.26k
          PHIRet.addIncoming(Value[I], BB);
5677
3.26k
        }
5678
1.20k
        Nodes.push_back(PHIRet);
5679
1.20k
      }
5680
1.10k
    }
5681
13.6k
    for (auto &Val : Nodes) {
5682
13.6k
      stackPush(Val);
5683
13.6k
    }
5684
12.8k
  }
5685
5686
37.7k
  void setLableJumpPHI(unsigned int Index) noexcept {
5687
37.7k
    assuming(Index < ControlStack.size());
5688
37.7k
    auto &Entry = *(ControlStack.rbegin() + Index);
5689
37.7k
    if (Entry.NextBlock) { // is loop
5690
2.22k
      std::vector<LLVM::Value> Args(Entry.Type.first.size());
5691
4.23k
      for (size_t I = 0; I < Args.size(); ++I) {
5692
2.01k
        const size_t J = Args.size() - 1 - I;
5693
2.01k
        Args[J] = stackPop();
5694
2.01k
      }
5695
4.23k
      for (size_t I = 0; I < Args.size(); ++I) {
5696
2.01k
        Entry.Args[I].addIncoming(Args[I], Builder.getInsertBlock());
5697
2.01k
        stackPush(Args[I]);
5698
2.01k
      }
5699
35.5k
    } else if (!Entry.Type.second.empty()) { // has return value
5700
2.14k
      std::vector<LLVM::Value> Rets(Entry.Type.second.size());
5701
4.42k
      for (size_t I = 0; I < Rets.size(); ++I) {
5702
2.27k
        const size_t J = Rets.size() - 1 - I;
5703
2.27k
        Rets[J] = stackPop();
5704
2.27k
      }
5705
4.42k
      for (size_t I = 0; I < Rets.size(); ++I) {
5706
2.27k
        stackPush(Rets[I]);
5707
2.27k
      }
5708
2.14k
      Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
5709
2.14k
    }
5710
37.7k
  }
5711
5712
37.7k
  LLVM::BasicBlock getLabel(unsigned int Index) const noexcept {
5713
37.7k
    return (ControlStack.rbegin() + Index)->JumpBlock;
5714
37.7k
  }
5715
5716
972k
  void stackPush(LLVM::Value Value) noexcept { Stack.push_back(Value); }
5717
368k
  LLVM::Value stackPop() noexcept {
5718
368k
    assuming(!ControlStack.empty() || !Stack.empty());
5719
368k
    assuming(ControlStack.empty() ||
5720
368k
             Stack.size() > ControlStack.back().StackSize);
5721
368k
    auto Value = Stack.back();
5722
368k
    Stack.pop_back();
5723
368k
    return Value;
5724
368k
  }
5725
5726
23.6k
  LLVM::Value switchEndian(LLVM::Value Value) {
5727
    if constexpr (Endian::native == Endian::big) {
5728
      auto Type = Value.getType();
5729
      if ((Type.isIntegerTy() && Type.getIntegerBitWidth() > 8) ||
5730
          (Type.isVectorTy() && Type.getVectorSize() == 1)) {
5731
        return Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
5732
      }
5733
      if (Type.isVectorTy()) {
5734
        LLVM::Type VecType = Type.getElementType().getIntegerBitWidth() == 128
5735
                                 ? Context.Int128Ty
5736
                                 : Context.Int64Ty;
5737
        Value = Builder.createBitCast(Value, VecType);
5738
        Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
5739
        return Builder.createBitCast(Value, Type);
5740
      }
5741
      if (Type.isFloatTy() || Type.isDoubleTy()) {
5742
        LLVM::Type IntType =
5743
            Type.isFloatTy() ? Context.Int32Ty : Context.Int64Ty;
5744
        Value = Builder.createBitCast(Value, IntType);
5745
        Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
5746
        return Builder.createBitCast(Value, Type);
5747
      }
5748
    }
5749
23.6k
    return Value;
5750
23.6k
  }
5751
5752
  LLVM::Compiler::CompileContext &Context;
5753
  LLVM::Context LLContext;
5754
  std::vector<std::pair<LLVM::Type, LLVM::Value>> Local;
5755
  std::vector<LLVM::Value> Stack;
5756
  LLVM::Value LocalInstrCount = nullptr;
5757
  LLVM::Value LocalGas = nullptr;
5758
  std::unordered_map<ErrCode::Value, LLVM::BasicBlock> TrapBB;
5759
  bool IsUnreachable = false;
5760
  bool Interruptible = false;
5761
  struct Control {
5762
    size_t StackSize;
5763
    bool Unreachable;
5764
    LLVM::BasicBlock JumpBlock;
5765
    LLVM::BasicBlock NextBlock;
5766
    LLVM::BasicBlock ElseBlock;
5767
    std::vector<LLVM::Value> Args;
5768
    std::pair<std::vector<ValType>, std::vector<ValType>> Type;
5769
    std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
5770
        ReturnPHI;
5771
    Control(size_t S, bool U, LLVM::BasicBlock J, LLVM::BasicBlock N,
5772
            LLVM::BasicBlock E, std::vector<LLVM::Value> A,
5773
            std::pair<std::vector<ValType>, std::vector<ValType>> T,
5774
            std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
5775
                R) noexcept
5776
21.2k
        : StackSize(S), Unreachable(U), JumpBlock(J), NextBlock(N),
5777
21.2k
          ElseBlock(E), Args(std::move(A)), Type(std::move(T)),
5778
21.2k
          ReturnPHI(std::move(R)) {}
5779
    Control(const Control &) = default;
5780
26.2k
    Control(Control &&) = default;
5781
    Control &operator=(const Control &) = default;
5782
949
    Control &operator=(Control &&) = default;
5783
  };
5784
  std::vector<Control> ControlStack;
5785
  LLVM::FunctionCallee F;
5786
  LLVM::Value ExecCtx;
5787
  LLVM::Builder Builder;
5788
};
5789
5790
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
5791
392
                                      LLVM::Value Struct) noexcept {
5792
392
  const auto N = Struct.getType().getStructNumElements();
5793
392
  std::vector<LLVM::Value> Ret;
5794
392
  Ret.reserve(N);
5795
1.41k
  for (unsigned I = 0; I < N; ++I) {
5796
1.02k
    Ret.push_back(Builder.createExtractValue(Struct, I));
5797
1.02k
  }
5798
392
  return Ret;
5799
392
}
5800
5801
} // namespace
5802
5803
namespace WasmEdge {
5804
namespace LLVM {
5805
5806
2.00k
Expect<void> Compiler::checkConfigure() noexcept {
5807
2.00k
  if (Conf.hasProposal(Proposal::ExceptionHandling)) {
5808
0
    spdlog::error(ErrCode::Value::InvalidConfigure);
5809
0
    spdlog::error(
5810
0
        "    Proposal ExceptionHandling is not yet supported in LLVM backend");
5811
0
    return Unexpect(ErrCode::Value::InvalidConfigure);
5812
0
  }
5813
2.00k
  return {};
5814
2.00k
}
5815
5816
2.00k
Expect<Data> Compiler::compile(const AST::Module &Module) noexcept {
5817
  // Check the module is validated.
5818
2.00k
  if (unlikely(!Module.getIsValidated())) {
5819
0
    spdlog::error(ErrCode::Value::NotValidated);
5820
0
    return Unexpect(ErrCode::Value::NotValidated);
5821
0
  }
5822
5823
2.00k
  std::unique_lock Lock(Mutex);
5824
2.00k
  spdlog::info("compile start"sv);
5825
5826
2.00k
  LLVM::Core::init();
5827
5828
2.00k
  LLVM::Data D;
5829
2.00k
  auto LLContext = D.extract().getLLContext();
5830
2.00k
  auto &LLModule = D.extract().LLModule;
5831
2.00k
  LLModule.setTarget(LLVM::getDefaultTargetTriple().unwrap());
5832
2.00k
  LLModule.addFlag(LLVMModuleFlagBehaviorError, "PIC Level"sv, 2);
5833
5834
2.00k
  CompileContext NewContext(LLContext, LLModule,
5835
2.00k
                            Conf.getCompilerConfigure().isGenericBinary());
5836
2.00k
  struct RAIICleanup {
5837
2.00k
    RAIICleanup(CompileContext *&Context, CompileContext &NewContext)
5838
2.00k
        : Context(Context) {
5839
2.00k
      Context = &NewContext;
5840
2.00k
    }
5841
2.00k
    ~RAIICleanup() { Context = nullptr; }
5842
2.00k
    CompileContext *&Context;
5843
2.00k
  };
5844
2.00k
  RAIICleanup Cleanup(Context, NewContext);
5845
5846
  // Compile Function Types
5847
2.00k
  compile(Module.getTypeSection());
5848
  // Compile ImportSection
5849
2.00k
  compile(Module.getImportSection());
5850
  // Compile GlobalSection
5851
2.00k
  compile(Module.getGlobalSection());
5852
  // Compile MemorySection (MemorySec, DataSec)
5853
2.00k
  compile(Module.getMemorySection(), Module.getDataSection());
5854
  // Compile TableSection (TableSec, ElemSec)
5855
2.00k
  compile(Module.getTableSection(), Module.getElementSection());
5856
  // compile Functions in module. (FunctionSec, CodeSec)
5857
2.00k
  compile(Module.getFunctionSection(), Module.getCodeSection());
5858
  // Compile ExportSection
5859
2.00k
  compile(Module.getExportSection());
5860
  // StartSection is not required to compile
5861
5862
2.00k
  spdlog::info("verify start"sv);
5863
2.00k
  LLModule.verify(LLVMPrintMessageAction);
5864
5865
2.00k
  spdlog::info("optimize start"sv);
5866
2.00k
  auto &TM = D.extract().TM;
5867
2.00k
  {
5868
2.00k
    auto Triple = LLModule.getTarget();
5869
2.00k
    auto [TheTarget, ErrorMessage] = LLVM::Target::getFromTriple(Triple);
5870
2.00k
    if (ErrorMessage) {
5871
0
      spdlog::error("getFromTriple failed:{}"sv, ErrorMessage.string_view());
5872
0
      return Unexpect(ErrCode::Value::IllegalPath);
5873
2.00k
    } else {
5874
2.00k
      std::string CPUName;
5875
#if defined(__riscv) && __riscv_xlen == 64
5876
      CPUName = "generic-rv64"s;
5877
#else
5878
2.00k
      if (!Conf.getCompilerConfigure().isGenericBinary()) {
5879
2.00k
        CPUName = LLVM::getHostCPUName().string_view();
5880
2.00k
      } else {
5881
0
        CPUName = "generic"s;
5882
0
      }
5883
2.00k
#endif
5884
5885
2.00k
      TM = LLVM::TargetMachine::create(
5886
2.00k
          TheTarget, Triple, CPUName.c_str(),
5887
2.00k
          LLVM::getHostCPUFeatures().unwrap(),
5888
2.00k
          toLLVMCodeGenLevel(
5889
2.00k
              Conf.getCompilerConfigure().getOptimizationLevel()),
5890
2.00k
          LLVMRelocPIC, LLVMCodeModelDefault);
5891
2.00k
    }
5892
5893
#if LLVM_VERSION_MAJOR >= 13
5894
    auto PBO = LLVM::PassBuilderOptions::create();
5895
    if (auto Error = PBO.runPasses(
5896
            LLModule,
5897
            toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel()),
5898
            TM)) {
5899
      spdlog::error("{}"sv, Error.message().string_view());
5900
    }
5901
#else
5902
2.00k
    auto FP = LLVM::PassManager::createForModule(LLModule);
5903
2.00k
    auto MP = LLVM::PassManager::create();
5904
5905
2.00k
    TM.addAnalysisPasses(MP);
5906
2.00k
    TM.addAnalysisPasses(FP);
5907
2.00k
    {
5908
2.00k
      auto PMB = LLVM::PassManagerBuilder::create();
5909
2.00k
      auto [OptLevel, SizeLevel] =
5910
2.00k
          toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel());
5911
2.00k
      PMB.setOptLevel(OptLevel);
5912
2.00k
      PMB.setSizeLevel(SizeLevel);
5913
2.00k
      PMB.populateFunctionPassManager(FP);
5914
2.00k
      PMB.populateModulePassManager(MP);
5915
2.00k
    }
5916
2.00k
    switch (Conf.getCompilerConfigure().getOptimizationLevel()) {
5917
0
    case CompilerConfigure::OptimizationLevel::O0:
5918
0
    case CompilerConfigure::OptimizationLevel::O1:
5919
0
      FP.addTailCallEliminationPass();
5920
0
      break;
5921
2.00k
    default:
5922
2.00k
      break;
5923
2.00k
    }
5924
5925
2.00k
    FP.initializeFunctionPassManager();
5926
23.0k
    for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) {
5927
21.0k
      FP.runFunctionPassManager(Fn);
5928
21.0k
    }
5929
2.00k
    FP.finalizeFunctionPassManager();
5930
2.00k
    MP.runPassManager(LLModule);
5931
2.00k
#endif
5932
2.00k
  }
5933
5934
  // Set initializer for constant value
5935
2.00k
  if (auto IntrinsicsTable = LLModule.getNamedGlobal("intrinsics")) {
5936
1.14k
    IntrinsicsTable.setInitializer(
5937
1.14k
        LLVM::Value::getConstNull(IntrinsicsTable.getType()));
5938
1.14k
    IntrinsicsTable.setGlobalConstant(false);
5939
1.14k
  } else {
5940
859
    auto IntrinsicsTableTy = LLVM::Type::getArrayType(
5941
859
        LLContext.getInt8Ty().getPointerTo(),
5942
859
        static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax));
5943
859
    LLModule.addGlobal(
5944
859
        IntrinsicsTableTy.getPointerTo(), false, LLVMExternalLinkage,
5945
859
        LLVM::Value::getConstNull(IntrinsicsTableTy), "intrinsics");
5946
859
  }
5947
5948
2.00k
  spdlog::info("optimize done"sv);
5949
2.00k
  return Expect<Data>{std::move(D)};
5950
2.00k
}
5951
5952
2.00k
void Compiler::compile(const AST::TypeSection &TypeSec) noexcept {
5953
2.00k
  auto WrapperTy =
5954
2.00k
      LLVM::Type::getFunctionType(Context->VoidTy,
5955
2.00k
                                  {Context->ExecCtxPtrTy, Context->Int8PtrTy,
5956
2.00k
                                   Context->Int8PtrTy, Context->Int8PtrTy},
5957
2.00k
                                  false);
5958
2.00k
  auto SubTypes = TypeSec.getContent();
5959
2.00k
  const auto Size = SubTypes.size();
5960
2.00k
  if (Size == 0) {
5961
110
    return;
5962
110
  }
5963
1.89k
  Context->CompositeTypes.reserve(Size);
5964
1.89k
  Context->FunctionWrappers.reserve(Size);
5965
5966
  // Iterate and compile types.
5967
5.88k
  for (size_t I = 0; I < Size; ++I) {
5968
3.99k
    const auto &CompType = SubTypes[I].getCompositeType();
5969
3.99k
    const auto Name = fmt::format("t{}"sv, Context->CompositeTypes.size());
5970
3.99k
    if (CompType.isFunc()) {
5971
      // Check function type is unique
5972
3.99k
      {
5973
3.99k
        bool Unique = true;
5974
14.8k
        for (size_t J = 0; J < I; ++J) {
5975
11.0k
          if (Context->CompositeTypes[J] &&
5976
11.0k
              Context->CompositeTypes[J]->isFunc()) {
5977
11.0k
            const auto &OldFuncType = Context->CompositeTypes[J]->getFuncType();
5978
11.0k
            if (OldFuncType == CompType.getFuncType()) {
5979
128
              Unique = false;
5980
128
              Context->CompositeTypes.push_back(Context->CompositeTypes[J]);
5981
128
              auto F = Context->FunctionWrappers[J];
5982
128
              Context->FunctionWrappers.push_back(F);
5983
128
              auto A = Context->LLModule.addAlias(WrapperTy, F, Name.c_str());
5984
128
              A.setLinkage(LLVMExternalLinkage);
5985
128
              A.setVisibility(LLVMProtectedVisibility);
5986
128
              A.setDSOLocal(true);
5987
128
              A.setDLLStorageClass(LLVMDLLExportStorageClass);
5988
128
              break;
5989
128
            }
5990
11.0k
          }
5991
11.0k
        }
5992
3.99k
        if (!Unique) {
5993
128
          continue;
5994
128
        }
5995
3.99k
      }
5996
5997
      // Create Wrapper
5998
3.86k
      auto F = Context->LLModule.addFunction(WrapperTy, LLVMExternalLinkage,
5999
3.86k
                                             Name.c_str());
6000
3.86k
      {
6001
3.86k
        F.setVisibility(LLVMProtectedVisibility);
6002
3.86k
        F.setDSOLocal(true);
6003
3.86k
        F.setDLLStorageClass(LLVMDLLExportStorageClass);
6004
3.86k
        F.addFnAttr(Context->NoStackArgProbe);
6005
3.86k
        F.addFnAttr(Context->StrictFP);
6006
3.86k
        F.addFnAttr(Context->UWTable);
6007
3.86k
        F.addParamAttr(0, Context->ReadOnly);
6008
3.86k
        F.addParamAttr(0, Context->NoAlias);
6009
3.86k
        F.addParamAttr(1, Context->NoAlias);
6010
3.86k
        F.addParamAttr(2, Context->NoAlias);
6011
3.86k
        F.addParamAttr(3, Context->NoAlias);
6012
6013
3.86k
        LLVM::Builder Builder(Context->LLContext);
6014
3.86k
        Builder.positionAtEnd(
6015
3.86k
            LLVM::BasicBlock::create(Context->LLContext, F, "entry"));
6016
6017
3.86k
        auto FTy = toLLVMType(Context->LLContext, Context->ExecCtxPtrTy,
6018
3.86k
                              CompType.getFuncType());
6019
3.86k
        auto RTy = FTy.getReturnType();
6020
3.86k
        std::vector<LLVM::Type> FPTy(FTy.getNumParams());
6021
3.86k
        FTy.getParamTypes(FPTy);
6022
6023
3.86k
        const size_t ArgCount = FPTy.size() - 1;
6024
3.86k
        auto ExecCtxPtr = F.getFirstParam();
6025
3.86k
        auto RawFunc = LLVM::FunctionCallee{
6026
3.86k
            FTy, Builder.createBitCast(ExecCtxPtr.getNextParam(),
6027
3.86k
                                       FTy.getPointerTo())};
6028
3.86k
        auto RawArgs = ExecCtxPtr.getNextParam().getNextParam();
6029
3.86k
        auto RawRets = RawArgs.getNextParam();
6030
6031
3.86k
        std::vector<LLVM::Value> Args;
6032
3.86k
        Args.reserve(FTy.getNumParams());
6033
3.86k
        Args.push_back(ExecCtxPtr);
6034
8.11k
        for (size_t J = 0; J < ArgCount; ++J) {
6035
4.25k
          Args.push_back(Builder.createValuePtrLoad(
6036
4.25k
              FPTy[J + 1], RawArgs, Context->Int8Ty, J * kValSize));
6037
4.25k
        }
6038
6039
3.86k
        auto Ret = Builder.createCall(RawFunc, Args);
6040
3.86k
        if (RTy.isVoidTy()) {
6041
          // nothing to do
6042
2.55k
        } else if (RTy.isStructTy()) {
6043
309
          auto Rets = unpackStruct(Builder, Ret);
6044
309
          Builder.createArrayPtrStore(Rets, RawRets, Context->Int8Ty, kValSize);
6045
2.24k
        } else {
6046
2.24k
          Builder.createValuePtrStore(Ret, RawRets, Context->Int8Ty);
6047
2.24k
        }
6048
3.86k
        Builder.createRetVoid();
6049
3.86k
      }
6050
      // Copy wrapper, param and return lists to module instance.
6051
3.86k
      Context->FunctionWrappers.push_back(F);
6052
3.86k
    } else {
6053
      // Non function type case. Create empty wrapper.
6054
0
      auto F = Context->LLModule.addFunction(WrapperTy, LLVMExternalLinkage,
6055
0
                                             Name.c_str());
6056
0
      {
6057
0
        F.setVisibility(LLVMProtectedVisibility);
6058
0
        F.setDSOLocal(true);
6059
0
        F.setDLLStorageClass(LLVMDLLExportStorageClass);
6060
0
        F.addFnAttr(Context->NoStackArgProbe);
6061
0
        F.addFnAttr(Context->StrictFP);
6062
0
        F.addFnAttr(Context->UWTable);
6063
0
        F.addParamAttr(0, Context->ReadOnly);
6064
0
        F.addParamAttr(0, Context->NoAlias);
6065
0
        F.addParamAttr(1, Context->NoAlias);
6066
0
        F.addParamAttr(2, Context->NoAlias);
6067
0
        F.addParamAttr(3, Context->NoAlias);
6068
6069
0
        LLVM::Builder Builder(Context->LLContext);
6070
0
        Builder.positionAtEnd(
6071
0
            LLVM::BasicBlock::create(Context->LLContext, F, "entry"));
6072
0
        Builder.createRetVoid();
6073
0
      }
6074
0
      Context->FunctionWrappers.push_back(F);
6075
0
    }
6076
3.86k
    Context->CompositeTypes.push_back(&CompType);
6077
3.86k
  }
6078
1.89k
}
6079
6080
2.00k
void Compiler::compile(const AST::ImportSection &ImportSec) noexcept {
6081
  // Iterate and compile import descriptions.
6082
2.00k
  for (const auto &ImpDesc : ImportSec.getContent()) {
6083
    // Get data from import description.
6084
369
    const auto &ExtType = ImpDesc.getExternalType();
6085
6086
    // Add the imports into module instance.
6087
369
    switch (ExtType) {
6088
272
    case ExternalType::Function: // Function type index
6089
272
    {
6090
272
      const auto FuncID = static_cast<uint32_t>(Context->Functions.size());
6091
      // Get the function type index in module.
6092
272
      uint32_t TypeIdx = ImpDesc.getExternalFuncTypeIdx();
6093
272
      assuming(TypeIdx < Context->CompositeTypes.size());
6094
272
      assuming(Context->CompositeTypes[TypeIdx]->isFunc());
6095
272
      const auto &FuncType = Context->CompositeTypes[TypeIdx]->getFuncType();
6096
272
      auto FTy =
6097
272
          toLLVMType(Context->LLContext, Context->ExecCtxPtrTy, FuncType);
6098
272
      auto RTy = FTy.getReturnType();
6099
272
      auto F = LLVM::FunctionCallee{
6100
272
          FTy,
6101
272
          Context->LLModule.addFunction(FTy, LLVMInternalLinkage,
6102
272
                                        fmt::format("f{}"sv, FuncID).c_str())};
6103
272
      F.Fn.setDSOLocal(true);
6104
272
      F.Fn.addFnAttr(Context->NoStackArgProbe);
6105
272
      F.Fn.addFnAttr(Context->StrictFP);
6106
272
      F.Fn.addFnAttr(Context->UWTable);
6107
272
      F.Fn.addParamAttr(0, Context->ReadOnly);
6108
272
      F.Fn.addParamAttr(0, Context->NoAlias);
6109
6110
272
      LLVM::Builder Builder(Context->LLContext);
6111
272
      Builder.positionAtEnd(
6112
272
          LLVM::BasicBlock::create(Context->LLContext, F.Fn, "entry"));
6113
6114
272
      const auto ArgSize = FuncType.getParamTypes().size();
6115
272
      const auto RetSize =
6116
272
          RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
6117
6118
272
      LLVM::Value Args = Builder.createArray(ArgSize, kValSize);
6119
272
      LLVM::Value Rets = Builder.createArray(RetSize, kValSize);
6120
6121
272
      auto Arg = F.Fn.getFirstParam();
6122
399
      for (unsigned I = 0; I < ArgSize; ++I) {
6123
127
        Arg = Arg.getNextParam();
6124
127
        Builder.createValuePtrStore(Arg, Args, Context->Int8Ty, I * kValSize);
6125
127
      }
6126
6127
272
      Builder.createCall(
6128
272
          Context->getIntrinsic(
6129
272
              Builder, Executable::Intrinsics::kCall,
6130
272
              LLVM::Type::getFunctionType(
6131
272
                  Context->VoidTy,
6132
272
                  {Context->Int32Ty, Context->Int8PtrTy, Context->Int8PtrTy},
6133
272
                  false)),
6134
272
          {Context->LLContext.getInt32(FuncID), Args, Rets});
6135
6136
272
      if (RetSize == 0) {
6137
152
        Builder.createRetVoid();
6138
152
      } else if (RetSize == 1) {
6139
93
        Builder.createRet(
6140
93
            Builder.createValuePtrLoad(RTy, Rets, Context->Int8Ty));
6141
93
      } else {
6142
27
        Builder.createAggregateRet(Builder.createArrayPtrLoad(
6143
27
            RetSize, RTy, Rets, Context->Int8Ty, kValSize));
6144
27
      }
6145
6146
272
      Context->Functions.emplace_back(TypeIdx, F, nullptr);
6147
272
      break;
6148
272
    }
6149
48
    case ExternalType::Table: // Table type
6150
48
    {
6151
      // Nothing to do.
6152
48
      break;
6153
272
    }
6154
10
    case ExternalType::Memory: // Memory type
6155
10
    {
6156
      // Nothing to do.
6157
10
      break;
6158
272
    }
6159
39
    case ExternalType::Global: // Global type
6160
39
    {
6161
      // Get global type. External type checked in validation.
6162
39
      const auto &GlobType = ImpDesc.getExternalGlobalType();
6163
39
      const auto &ValType = GlobType.getValType();
6164
39
      auto Type = toLLVMType(Context->LLContext, ValType);
6165
39
      Context->Globals.push_back(Type);
6166
39
      break;
6167
272
    }
6168
0
    default:
6169
0
      break;
6170
369
    }
6171
369
  }
6172
2.00k
}
6173
6174
2.00k
void Compiler::compile(const AST::ExportSection &) noexcept {}
6175
6176
2.00k
void Compiler::compile(const AST::GlobalSection &GlobalSec) noexcept {
6177
2.00k
  for (const auto &GlobalSeg : GlobalSec.getContent()) {
6178
111
    const auto &ValType = GlobalSeg.getGlobalType().getValType();
6179
111
    auto Type = toLLVMType(Context->LLContext, ValType);
6180
111
    Context->Globals.push_back(Type);
6181
111
  }
6182
2.00k
}
6183
6184
void Compiler::compile(const AST::MemorySection &,
6185
2.00k
                       const AST::DataSection &) noexcept {}
6186
6187
void Compiler::compile(const AST::TableSection &,
6188
2.00k
                       const AST::ElementSection &) noexcept {}
6189
6190
void Compiler::compile(const AST::FunctionSection &FuncSec,
6191
2.00k
                       const AST::CodeSection &CodeSec) noexcept {
6192
2.00k
  const auto &TypeIdxs = FuncSec.getContent();
6193
2.00k
  const auto &CodeSegs = CodeSec.getContent();
6194
2.00k
  if (TypeIdxs.size() == 0 || CodeSegs.size() == 0) {
6195
190
    return;
6196
190
  }
6197
6198
12.6k
  for (size_t I = 0; I < TypeIdxs.size() && I < CodeSegs.size(); ++I) {
6199
10.7k
    const auto &TypeIdx = TypeIdxs[I];
6200
10.7k
    const auto &Code = CodeSegs[I];
6201
10.7k
    assuming(TypeIdx < Context->CompositeTypes.size());
6202
10.7k
    assuming(Context->CompositeTypes[TypeIdx]->isFunc());
6203
10.7k
    const auto &FuncType = Context->CompositeTypes[TypeIdx]->getFuncType();
6204
10.7k
    const auto FuncID = Context->Functions.size();
6205
10.7k
    auto FTy = toLLVMType(Context->LLContext, Context->ExecCtxPtrTy, FuncType);
6206
10.7k
    LLVM::FunctionCallee F = {FTy, Context->LLModule.addFunction(
6207
10.7k
                                       FTy, LLVMExternalLinkage,
6208
10.7k
                                       fmt::format("f{}"sv, FuncID).c_str())};
6209
10.7k
    F.Fn.setVisibility(LLVMProtectedVisibility);
6210
10.7k
    F.Fn.setDSOLocal(true);
6211
10.7k
    F.Fn.setDLLStorageClass(LLVMDLLExportStorageClass);
6212
10.7k
    F.Fn.addFnAttr(Context->NoStackArgProbe);
6213
10.7k
    F.Fn.addFnAttr(Context->StrictFP);
6214
10.7k
    F.Fn.addFnAttr(Context->UWTable);
6215
10.7k
    F.Fn.addParamAttr(0, Context->ReadOnly);
6216
10.7k
    F.Fn.addParamAttr(0, Context->NoAlias);
6217
6218
10.7k
    Context->Functions.emplace_back(TypeIdx, F, &Code);
6219
10.7k
  }
6220
6221
10.9k
  for (auto [T, F, Code] : Context->Functions) {
6222
10.9k
    if (!Code) {
6223
111
      continue;
6224
111
    }
6225
6226
10.7k
    std::vector<ValType> Locals;
6227
10.7k
    for (const auto &Local : Code->getLocals()) {
6228
2.63M
      for (unsigned I = 0; I < Local.first; ++I) {
6229
2.63M
        Locals.push_back(Local.second);
6230
2.63M
      }
6231
1.46k
    }
6232
10.7k
    FunctionCompiler FC(*Context, F, Locals,
6233
10.7k
                        Conf.getCompilerConfigure().isInterruptible(),
6234
10.7k
                        Conf.getStatisticsConfigure().isInstructionCounting(),
6235
10.7k
                        Conf.getStatisticsConfigure().isCostMeasuring());
6236
10.7k
    auto Type = Context->resolveBlockType(T);
6237
10.7k
    FC.compile(*Code, std::move(Type));
6238
10.7k
    F.Fn.eliminateUnreachableBlocks();
6239
10.7k
  }
6240
1.81k
}
6241
6242
} // namespace LLVM
6243
} // namespace WasmEdge