Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler/function_compiler.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "compiler/function_compiler.h"
5
6
#include "runtime/instance/function.h"
7
8
#include <algorithm>
9
#include <array>
10
#include <limits>
11
12
using namespace std::literals;
13
14
namespace WasmEdge {
15
16
FunctionCompiler::FunctionCompiler(LLVM::Compiler::CompileContext &Context,
17
                                   LLVM::FunctionCallee F,
18
                                   Span<const ValType> Locals,
19
                                   bool Interruptible, bool InstructionCounting,
20
                                   bool GasMeasuring, bool IsLazyJIT,
21
                                   bool StackCheck) noexcept
22
10.6k
    : Context(Context), LLContext(Context.LLContext),
23
10.6k
      Interruptible(Interruptible), IsLazyJIT(IsLazyJIT), F(F),
24
10.6k
      Builder(LLContext) {
25
10.6k
  if (F.Fn) {
26
10.6k
    Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "entry"));
27
10.6k
    ModCtx = Builder.createLoad(Context.ModCtxTy, F.Fn.getFirstParam());
28
10.6k
    ExecCtx = Builder.createLoad(Context.ExecCtxTy,
29
10.6k
                                 F.Fn.getFirstParam().getNextParam());
30
31
    // Create every frame slot first so nothing writes the frame before the
32
    // stack check.
33
10.6k
    if (InstructionCounting) {
34
0
      LocalInstrCount = Builder.createAlloca(Context.Int64Ty);
35
0
    }
36
10.6k
    if (GasMeasuring) {
37
0
      LocalGas = Builder.createAlloca(Context.Int64Ty);
38
0
    }
39
10.6k
    CalleeCtxSlot = Builder.createAlloca(Context.ModCtxPtrTy);
40
10.6k
    TmpValues = Builder.createArray(1, LLVM::kValSize);
41
10.6k
    TmpValuesSize = 1;
42
10.6k
    for (LLVM::Value Arg = F.Fn.getFirstParam().getNextParam().getNextParam();
43
20.4k
         Arg; Arg = Arg.getNextParam()) {
44
9.86k
      LLVM::Type Ty = Arg.getType();
45
9.86k
      Local.emplace_back(Ty, Builder.createAlloca(Ty));
46
9.86k
    }
47
4.33M
    for (const auto &Type : Locals) {
48
4.33M
      LLVM::Type Ty = toLLVMType(LLContext, Type);
49
4.33M
      Local.emplace_back(Ty, Builder.createAlloca(Ty));
50
4.33M
    }
51
52
10.6k
    if (StackCheck) {
53
2.89k
      checkStackLimit();
54
2.89k
    }
55
56
10.6k
    if (LocalInstrCount) {
57
0
      Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
58
0
    }
59
10.6k
    if (LocalGas) {
60
0
      Builder.createStore(LLContext.getInt64(0), LocalGas);
61
0
    }
62
10.6k
    auto LocalIt = Local.begin();
63
10.6k
    for (LLVM::Value Arg = F.Fn.getFirstParam().getNextParam().getNextParam();
64
20.4k
         Arg; Arg = Arg.getNextParam()) {
65
9.86k
      Builder.createStore(Arg, (LocalIt++)->second);
66
9.86k
    }
67
4.33M
    for (const auto &Type : Locals) {
68
4.33M
      Builder.createStore(
69
4.33M
          toLLVMConstantZero(LLContext, Type, Context.CompositeTypes),
70
4.33M
          (LocalIt++)->second);
71
4.33M
    }
72
10.6k
  }
73
10.6k
}
74
75
35.3k
LLVM::BasicBlock FunctionCompiler::getTrapBB(ErrCode::Value Error) noexcept {
76
35.3k
  if (auto Iter = TrapBB.find(Error); Iter != TrapBB.end()) {
77
29.0k
    return Iter->second;
78
29.0k
  }
79
6.25k
  auto BB = LLVM::BasicBlock::create(LLContext, F.Fn, "trap");
80
6.25k
  TrapBB.emplace(Error, BB);
81
6.25k
  return BB;
82
35.3k
}
83
84
2.06k
LLVM::Value FunctionCompiler::getTmpValues(size_t Num) noexcept {
85
2.06k
  if (Num > TmpValuesSize) {
86
603
    LLVM::Builder EntryBuilder(LLContext);
87
603
    EntryBuilder.positionBefore(TmpValues);
88
603
    auto Values = EntryBuilder.createArray(Num, LLVM::kValSize);
89
603
    TmpValues.replaceAllUsesWith(Values);
90
603
    TmpValues.eraseFromParent();
91
603
    TmpValues = Values;
92
603
    TmpValuesSize = Num;
93
603
  }
94
2.06k
  TmpValuesUsed = static_cast<uint64_t>(Num) * LLVM::kValSize;
95
2.06k
  Builder.createLifetimeStart(TmpValues, TmpValuesUsed);
96
2.06k
  return TmpValues;
97
2.06k
}
98
99
2.06k
void FunctionCompiler::endTmpValues() noexcept {
100
2.06k
  Builder.createLifetimeEnd(TmpValues, TmpValuesUsed);
101
2.06k
}
102
103
Expect<void> FunctionCompiler::compile(
104
    const AST::CodeSegment &Code,
105
10.6k
    std::pair<std::vector<ValType>, std::vector<ValType>> Type) noexcept {
106
10.6k
  auto RetBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ret");
107
10.6k
  Type.first.clear();
108
10.6k
  enterBlock(RetBB, {}, {}, {}, std::move(Type));
109
10.6k
  EXPECTED_TRY(compile(Code.getExpr().getInstrs()));
110
10.6k
  assuming(ControlStack.empty());
111
10.6k
  compileReturn();
112
113
10.6k
  for (auto &[Error, BB] : TrapBB) {
114
6.25k
    Builder.positionAtEnd(BB);
115
6.25k
    updateInstrCount();
116
6.25k
    updateGasAtTrap();
117
6.25k
    auto CallTrap = Builder.createCall(
118
6.25k
        Context.Trap, {LLContext.getInt32(static_cast<uint32_t>(Error))});
119
6.25k
    CallTrap.addCallSiteAttribute(Context.NoReturn);
120
6.25k
    Builder.createUnreachable();
121
6.25k
  }
122
123
10.6k
  if (UnwindBB) {
124
    // Escape path for uncaught exceptions: return with the pending state
125
    // set; the caller never reads the results.
126
1.98k
    Builder.positionAtEnd(UnwindBB);
127
1.98k
    updateInstrCount();
128
1.98k
    updateGasAtTrap();
129
1.98k
    auto Ty = F.Ty.getReturnType();
130
1.98k
    if (Ty.isVoidTy()) {
131
488
      Builder.createRetVoid();
132
1.49k
    } else {
133
1.49k
      Builder.createRet(LLVM::Value::getUndef(Ty));
134
1.49k
    }
135
1.98k
  }
136
10.6k
  return {};
137
10.6k
}
138
139
10.6k
Expect<void> FunctionCompiler::compile(AST::InstrView Instrs) noexcept {
140
1.50M
  auto Dispatch = [this](const AST::Instruction &Instr) -> Expect<void> {
141
1.50M
    switch (Instr.getOpCode()) {
142
    // Control instructions (for blocks)
143
3.59k
    case OpCode::Block: {
144
3.59k
      auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "block");
145
3.59k
      auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "block.end");
146
3.59k
      Builder.createBr(Block);
147
148
3.59k
      Builder.positionAtEnd(Block);
149
3.59k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
150
3.59k
      const auto Arity = Type.first.size();
151
3.59k
      std::vector<LLVM::Value> Args(Arity);
152
3.59k
      if (isUnreachable()) {
153
1.11k
        for (size_t I = 0; I < Arity; ++I) {
154
259
          auto Ty = toLLVMType(LLContext, Type.first[I]);
155
259
          Args[I] = LLVM::Value::getUndef(Ty);
156
259
        }
157
2.74k
      } else {
158
3.05k
        for (size_t I = 0; I < Arity; ++I) {
159
305
          const size_t J = Arity - 1 - I;
160
305
          Args[J] = stackPop();
161
305
        }
162
2.74k
      }
163
3.59k
      enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
164
3.59k
      checkStop();
165
3.59k
      updateGas();
166
3.59k
      return {};
167
0
    }
168
2.05k
    case OpCode::Loop: {
169
2.05k
      auto Curr = Builder.getInsertBlock();
170
2.05k
      auto Loop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop");
171
2.05k
      auto EndLoop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop.end");
172
2.05k
      Builder.createBr(Loop);
173
174
2.05k
      Builder.positionAtEnd(Loop);
175
2.05k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
176
2.05k
      const auto Arity = Type.first.size();
177
2.05k
      std::vector<LLVM::Value> Args(Arity);
178
2.05k
      if (isUnreachable()) {
179
1.10k
        for (size_t I = 0; I < Arity; ++I) {
180
421
          auto Ty = toLLVMType(LLContext, Type.first[I]);
181
421
          auto Value = LLVM::Value::getUndef(Ty);
182
421
          auto PHINode = Builder.createPHI(Ty);
183
421
          PHINode.addIncoming(Value, Curr);
184
421
          Args[I] = PHINode;
185
421
        }
186
1.37k
      } else {
187
2.13k
        for (size_t I = 0; I < Arity; ++I) {
188
758
          const size_t J = Arity - 1 - I;
189
758
          auto Value = stackPop();
190
758
          auto PHINode = Builder.createPHI(Value.getType());
191
758
          PHINode.addIncoming(Value, Curr);
192
758
          Args[J] = PHINode;
193
758
        }
194
1.37k
      }
195
2.05k
      enterBlock(Loop, EndLoop, {}, std::move(Args), std::move(Type));
196
2.05k
      checkStop();
197
2.05k
      updateGas();
198
2.05k
      return {};
199
0
    }
200
3.02k
    case OpCode::If: {
201
3.02k
      auto Then = LLVM::BasicBlock::create(LLContext, F.Fn, "then");
202
3.02k
      auto Else = LLVM::BasicBlock::create(LLContext, F.Fn, "else");
203
3.02k
      auto EndIf = LLVM::BasicBlock::create(LLContext, F.Fn, "if.end");
204
3.02k
      LLVM::Value Cond;
205
3.02k
      if (isUnreachable()) {
206
758
        Cond = LLVM::Value::getUndef(LLContext.getInt1Ty());
207
2.27k
      } else {
208
2.27k
        Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
209
2.27k
      }
210
3.02k
      Builder.createCondBr(Cond, Then, Else);
211
212
3.02k
      Builder.positionAtEnd(Then);
213
3.02k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
214
3.02k
      const auto Arity = Type.first.size();
215
3.02k
      std::vector<LLVM::Value> Args(Arity);
216
3.02k
      if (isUnreachable()) {
217
1.21k
        for (size_t I = 0; I < Arity; ++I) {
218
457
          auto Ty = toLLVMType(LLContext, Type.first[I]);
219
457
          Args[I] = LLVM::Value::getUndef(Ty);
220
457
        }
221
2.27k
      } else {
222
3.11k
        for (size_t I = 0; I < Arity; ++I) {
223
843
          const size_t J = Arity - 1 - I;
224
843
          Args[J] = stackPop();
225
843
        }
226
2.27k
      }
227
3.02k
      enterBlock(EndIf, {}, Else, std::move(Args), std::move(Type));
228
3.02k
      return {};
229
0
    }
230
402
    case OpCode::Try_table:
231
402
      compileTryTableOp(Instr);
232
402
      return {};
233
19.7k
    case OpCode::End: {
234
19.7k
      auto Entry = leaveBlock();
235
19.7k
      if (Entry.ElseBlock) {
236
1.46k
        auto Block = Builder.getInsertBlock();
237
1.46k
        Builder.positionAtEnd(Entry.ElseBlock);
238
1.46k
        enterBlock(Block, {}, {}, std::move(Entry.Args), std::move(Entry.Type),
239
1.46k
                   std::move(Entry.ReturnPHI));
240
1.46k
        Entry = leaveBlock();
241
1.46k
      }
242
19.7k
      buildPHI(Entry.Type.second, Entry.ReturnPHI);
243
19.7k
      return {};
244
0
    }
245
1.56k
    case OpCode::Else: {
246
1.56k
      auto Entry = leaveBlock();
247
1.56k
      Builder.positionAtEnd(Entry.ElseBlock);
248
1.56k
      enterBlock(Entry.JumpBlock, {}, {}, std::move(Entry.Args),
249
1.56k
                 std::move(Entry.Type), std::move(Entry.ReturnPHI));
250
1.56k
      return {};
251
0
    }
252
1.47M
    default:
253
1.47M
      break;
254
1.50M
    }
255
256
1.47M
    if (isUnreachable()) {
257
514k
      return {};
258
514k
    }
259
260
961k
    switch (Instr.getOpCode()) {
261
    // Control instructions
262
3.69k
    case OpCode::Unreachable:
263
3.69k
      Builder.createBr(getTrapBB(ErrCode::Value::Unreachable));
264
3.69k
      setUnreachable();
265
3.69k
      Builder.positionAtEnd(
266
3.69k
          LLVM::BasicBlock::create(LLContext, F.Fn, "unreachable.end"));
267
3.69k
      break;
268
42.2k
    case OpCode::Nop:
269
42.2k
      break;
270
1
    case OpCode::Throw:
271
1
      updateInstrCount();
272
1
      updateGas();
273
1
      compileThrowOp(Instr.getTargetIndex());
274
1
      break;
275
5
    case OpCode::Throw_ref:
276
5
      updateInstrCount();
277
5
      updateGas();
278
5
      compileThrowRefOp();
279
5
      break;
280
722
    case OpCode::Br: {
281
722
      const auto Label = Instr.getJump().TargetIndex;
282
722
      setLableJumpPHI(Label);
283
722
      Builder.createBr(getLabel(Label));
284
722
      setUnreachable();
285
722
      Builder.positionAtEnd(
286
722
          LLVM::BasicBlock::create(LLContext, F.Fn, "br.end"));
287
722
      break;
288
0
    }
289
364
    case OpCode::Br_if: {
290
364
      const auto Label = Instr.getJump().TargetIndex;
291
364
      auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
292
364
      setLableJumpPHI(Label);
293
364
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_if.end");
294
364
      Builder.createCondBr(Cond, getLabel(Label), Next);
295
364
      Builder.positionAtEnd(Next);
296
364
      break;
297
0
    }
298
1.01k
    case OpCode::Br_table: {
299
1.01k
      auto LabelTable = Instr.getLabelList();
300
1.01k
      assuming(LabelTable.size() <= std::numeric_limits<uint32_t>::max());
301
1.01k
      const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
302
1.01k
      auto Value = stackPop();
303
1.01k
      setLableJumpPHI(LabelTable[LabelTableSize].TargetIndex);
304
1.01k
      auto Switch = Builder.createSwitch(
305
1.01k
          Value, getLabel(LabelTable[LabelTableSize].TargetIndex),
306
1.01k
          LabelTableSize);
307
36.4k
      for (uint32_t I = 0; I < LabelTableSize; ++I) {
308
35.4k
        setLableJumpPHI(LabelTable[I].TargetIndex);
309
35.4k
        Switch.addCase(LLContext.getInt32(I),
310
35.4k
                       getLabel(LabelTable[I].TargetIndex));
311
35.4k
      }
312
1.01k
      setUnreachable();
313
1.01k
      Builder.positionAtEnd(
314
1.01k
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_table.end"));
315
1.01k
      break;
316
1.01k
    }
317
42
    case OpCode::Br_on_null: {
318
42
      const auto Label = Instr.getJump().TargetIndex;
319
42
      auto Value = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
320
42
      auto Cond = Builder.createICmpEQ(
321
42
          Builder.createExtractElement(Value, LLContext.getInt64(1)),
322
42
          LLContext.getInt64(0));
323
42
      setLableJumpPHI(Label);
324
42
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_null.end");
325
42
      Builder.createCondBr(Cond, getLabel(Label), Next);
326
42
      Builder.positionAtEnd(Next);
327
42
      stackPush(Value);
328
42
      break;
329
1.01k
    }
330
10
    case OpCode::Br_on_non_null: {
331
10
      const auto Label = Instr.getJump().TargetIndex;
332
10
      auto Cond = Builder.createICmpNE(
333
10
          Builder.createExtractElement(
334
10
              Builder.createBitCast(Stack.back(), Context.Int64x2Ty),
335
10
              LLContext.getInt64(1)),
336
10
          LLContext.getInt64(0));
337
10
      setLableJumpPHI(Label);
338
10
      auto Next =
339
10
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_non_null.end");
340
10
      Builder.createCondBr(Cond, getLabel(Label), Next);
341
10
      Builder.positionAtEnd(Next);
342
10
      stackPop();
343
10
      break;
344
1.01k
    }
345
0
    case OpCode::Br_on_cast:
346
0
    case OpCode::Br_on_cast_fail: {
347
0
      auto Ref = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
348
0
      const auto Label = Instr.getBrCast().Jump.TargetIndex;
349
0
      std::array<uint8_t, 16> Buf = {0};
350
0
      std::copy_n(Instr.getBrCast().RType2.getRawData().cbegin(), 8,
351
0
                  Buf.begin());
352
0
      auto VType = Builder.createExtractElement(
353
0
          Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
354
0
                                Context.Int64x2Ty),
355
0
          LLContext.getInt64(0));
356
0
      auto IsRefTest = Builder.createCall(
357
0
          Context.getIntrinsic(
358
0
              Builder, Executable::Intrinsics::kRefTest,
359
0
              LLVM::Type::getFunctionType(
360
0
                  Context.Int32Ty,
361
0
                  {Context.Int8PtrTy, Context.Int64x2Ty, Context.Int64Ty},
362
0
                  false)),
363
0
          {Context.getModuleInst(Builder, ModCtx), Ref, VType});
364
0
      auto Cond = (Instr.getOpCode() == OpCode::Br_on_cast)
365
0
                      ? Builder.createICmpNE(IsRefTest, LLContext.getInt32(0))
366
0
                      : Builder.createICmpEQ(IsRefTest, LLContext.getInt32(0));
367
0
      setLableJumpPHI(Label);
368
0
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_cast.end");
369
0
      Builder.createCondBr(Cond, getLabel(Label), Next);
370
0
      Builder.positionAtEnd(Next);
371
0
      break;
372
0
    }
373
725
    case OpCode::Return:
374
725
      compileReturn();
375
725
      setUnreachable();
376
725
      Builder.positionAtEnd(
377
725
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret.end"));
378
725
      break;
379
3.04k
    case OpCode::Call:
380
3.04k
      updateInstrCount();
381
3.04k
      updateGas();
382
3.04k
      compileCallOp(Instr.getTargetIndex());
383
3.04k
      break;
384
1.06k
    case OpCode::Call_indirect:
385
1.06k
      updateInstrCount();
386
1.06k
      updateGas();
387
1.06k
      compileIndirectCallOp(Instr.getSourceIndex(), Instr.getTargetIndex());
388
1.06k
      break;
389
77
    case OpCode::Return_call:
390
77
      updateInstrCount();
391
77
      updateGas();
392
77
      compileReturnCallOp(Instr.getTargetIndex());
393
77
      setUnreachable();
394
77
      Builder.positionAtEnd(
395
77
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call.end"));
396
77
      break;
397
142
    case OpCode::Return_call_indirect:
398
142
      updateInstrCount();
399
142
      updateGas();
400
142
      compileReturnIndirectCallOp(Instr.getSourceIndex(),
401
142
                                  Instr.getTargetIndex());
402
142
      setUnreachable();
403
142
      Builder.positionAtEnd(
404
142
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_indir.end"));
405
142
      break;
406
207
    case OpCode::Call_ref:
407
207
      updateInstrCount();
408
207
      updateGas();
409
207
      compileCallRefOp(Instr.getTargetIndex());
410
207
      break;
411
58
    case OpCode::Return_call_ref:
412
58
      updateInstrCount();
413
58
      updateGas();
414
58
      compileReturnCallRefOp(Instr.getTargetIndex());
415
58
      setUnreachable();
416
58
      Builder.positionAtEnd(
417
58
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_ref.end"));
418
58
      break;
419
420
    // Reference Instructions
421
5.90k
    case OpCode::Ref__null:
422
8.38k
    case OpCode::Ref__is_null:
423
8.49k
    case OpCode::Ref__func:
424
8.53k
    case OpCode::Ref__eq:
425
8.90k
    case OpCode::Ref__as_non_null:
426
8.97k
    case OpCode::Struct__new:
427
9.03k
    case OpCode::Struct__new_default:
428
9.03k
    case OpCode::Struct__get:
429
9.03k
    case OpCode::Struct__get_u:
430
9.03k
    case OpCode::Struct__get_s:
431
9.03k
    case OpCode::Struct__set:
432
9.16k
    case OpCode::Array__new:
433
9.19k
    case OpCode::Array__new_default:
434
9.28k
    case OpCode::Array__new_fixed:
435
9.28k
    case OpCode::Array__new_data:
436
9.28k
    case OpCode::Array__new_elem:
437
9.42k
    case OpCode::Array__get:
438
9.46k
    case OpCode::Array__get_u:
439
9.54k
    case OpCode::Array__get_s:
440
9.58k
    case OpCode::Array__set:
441
9.64k
    case OpCode::Array__len:
442
9.65k
    case OpCode::Array__fill:
443
9.66k
    case OpCode::Array__copy:
444
9.66k
    case OpCode::Array__init_data:
445
9.66k
    case OpCode::Array__init_elem:
446
9.67k
    case OpCode::Ref__test:
447
9.70k
    case OpCode::Ref__test_null:
448
9.74k
    case OpCode::Ref__cast:
449
9.76k
    case OpCode::Ref__cast_null:
450
9.77k
    case OpCode::Any__convert_extern:
451
9.82k
    case OpCode::Extern__convert_any:
452
9.92k
    case OpCode::Ref__i31:
453
9.96k
    case OpCode::I31__get_s:
454
10.0k
    case OpCode::I31__get_u:
455
13.4k
    case OpCode::Drop:
456
14.1k
    case OpCode::Select:
457
14.5k
    case OpCode::Select_t:
458
14.5k
      return compileRefOp(Instr);
459
11.2k
    case OpCode::Local__get: {
460
11.2k
      const auto &L = Local[Instr.getTargetIndex()];
461
11.2k
      stackPush(Builder.createLoad(L.first, L.second));
462
11.2k
      break;
463
14.1k
    }
464
3.11k
    case OpCode::Local__set:
465
3.11k
      Builder.createStore(stackPop(), Local[Instr.getTargetIndex()].second);
466
3.11k
      break;
467
829
    case OpCode::Local__tee:
468
829
      Builder.createStore(Stack.back(), Local[Instr.getTargetIndex()].second);
469
829
      break;
470
416
    case OpCode::Global__get: {
471
416
      const auto G = Context.getGlobal(Builder, ModCtx, Instr.getTargetIndex());
472
416
      stackPush(Builder.createLoad(G.first, G.second));
473
416
      break;
474
14.1k
    }
475
128
    case OpCode::Global__set:
476
128
      Builder.createStore(
477
128
          stackPop(),
478
128
          Context.getGlobal(Builder, ModCtx, Instr.getTargetIndex()).second);
479
128
      break;
480
481
    // Table Instructions
482
58
    case OpCode::Table__get: {
483
58
      const auto TableIndex = Instr.getTargetIndex();
484
58
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
485
58
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_get.ok");
486
58
      Builder.createCondBr(
487
58
          Builder.createLikely(Builder.createICmpULT(
488
58
              Off, Context.getTableSize(Builder, ModCtx, TableIndex))),
489
58
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
490
58
      Builder.positionAtEnd(OkBB);
491
58
      stackPush(Builder.createLoad(
492
58
          Context.Int64x2Ty,
493
58
          Builder.createInBoundsGEP1(
494
58
              Context.Int64x2Ty, Context.getTable(Builder, ModCtx, TableIndex),
495
58
              Off)));
496
58
      break;
497
14.1k
    }
498
40
    case OpCode::Table__set: {
499
40
      const auto TableIndex = Instr.getTargetIndex();
500
40
      auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
501
40
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
502
40
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_set.ok");
503
40
      Builder.createCondBr(
504
40
          Builder.createLikely(Builder.createICmpULT(
505
40
              Off, Context.getTableSize(Builder, ModCtx, TableIndex))),
506
40
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
507
40
      Builder.positionAtEnd(OkBB);
508
40
      Builder.createStore(
509
40
          Ref, Builder.createInBoundsGEP1(
510
40
                   Context.Int64x2Ty,
511
40
                   Context.getTable(Builder, ModCtx, TableIndex), Off));
512
40
      break;
513
14.1k
    }
514
23
    case OpCode::Table__init: {
515
23
      auto Len = stackPop();
516
23
      auto Src = stackPop();
517
23
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
518
23
      Builder.createCall(
519
23
          Context.getIntrinsic(
520
23
              Builder, Executable::Intrinsics::kTableInit,
521
23
              LLVM::Type::getFunctionType(Context.VoidTy,
522
23
                                          {Context.Int8PtrTy, Context.Int32Ty,
523
23
                                           Context.Int32Ty, Context.Int64Ty,
524
23
                                           Context.Int32Ty, Context.Int32Ty},
525
23
                                          false)),
526
23
          {Context.getModuleInst(Builder, ModCtx),
527
23
           LLContext.getInt32(Instr.getTargetIndex()),
528
23
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
529
23
      break;
530
14.1k
    }
531
34
    case OpCode::Elem__drop: {
532
34
      Builder.createCall(
533
34
          Context.getIntrinsic(
534
34
              Builder, Executable::Intrinsics::kElemDrop,
535
34
              LLVM::Type::getFunctionType(
536
34
                  Context.VoidTy, {Context.Int8PtrTy, Context.Int32Ty}, false)),
537
34
          {Context.getModuleInst(Builder, ModCtx),
538
34
           LLContext.getInt32(Instr.getTargetIndex())});
539
34
      break;
540
14.1k
    }
541
14
    case OpCode::Table__copy: {
542
14
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
543
14
      auto Src = Builder.createZExt(stackPop(), Context.Int64Ty);
544
14
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
545
14
      Builder.createCall(
546
14
          Context.getIntrinsic(
547
14
              Builder, Executable::Intrinsics::kTableCopy,
548
14
              LLVM::Type::getFunctionType(Context.VoidTy,
549
14
                                          {Context.Int8PtrTy, Context.Int32Ty,
550
14
                                           Context.Int32Ty, Context.Int64Ty,
551
14
                                           Context.Int64Ty, Context.Int64Ty},
552
14
                                          false)),
553
14
          {Context.getModuleInst(Builder, ModCtx),
554
14
           LLContext.getInt32(Instr.getTargetIndex()),
555
14
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
556
14
      break;
557
14.1k
    }
558
16
    case OpCode::Table__grow: {
559
16
      auto NewSize = Builder.createZExt(stackPop(), Context.Int64Ty);
560
16
      auto Val = stackPop();
561
16
      stackPush(Builder.createTrunc(
562
16
          Builder.createCall(
563
16
              Context.getIntrinsic(Builder, Executable::Intrinsics::kTableGrow,
564
16
                                   LLVM::Type::getFunctionType(
565
16
                                       Context.Int64Ty,
566
16
                                       {Context.Int8PtrTy, Context.Int32Ty,
567
16
                                        Context.Int64x2Ty, Context.Int64Ty},
568
16
                                       false)),
569
16
              {Context.getModuleInst(Builder, ModCtx),
570
16
               LLContext.getInt32(Instr.getTargetIndex()), Val, NewSize}),
571
16
          Context.TableAddrTypes[Instr.getTargetIndex()]));
572
16
      break;
573
14.1k
    }
574
15
    case OpCode::Table__size: {
575
15
      stackPush(Builder.createTrunc(
576
15
          Context.getTableSize(Builder, ModCtx, Instr.getTargetIndex()),
577
15
          Context.TableAddrTypes[Instr.getTargetIndex()]));
578
15
      break;
579
14.1k
    }
580
3
    case OpCode::Table__fill: {
581
3
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
582
3
      auto Val = stackPop();
583
3
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
584
3
      Builder.createCall(
585
3
          Context.getIntrinsic(
586
3
              Builder, Executable::Intrinsics::kTableFill,
587
3
              LLVM::Type::getFunctionType(Context.Int32Ty,
588
3
                                          {Context.Int8PtrTy, Context.Int32Ty,
589
3
                                           Context.Int64Ty, Context.Int64x2Ty,
590
3
                                           Context.Int64Ty},
591
3
                                          false)),
592
3
          {Context.getModuleInst(Builder, ModCtx),
593
3
           LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
594
3
      break;
595
14.1k
    }
596
597
    // Memory Instructions
598
1.08k
    case OpCode::I32__load:
599
3.53k
    case OpCode::I64__load:
600
3.64k
    case OpCode::F32__load:
601
3.88k
    case OpCode::F64__load:
602
4.41k
    case OpCode::I32__load8_s:
603
4.82k
    case OpCode::I32__load8_u:
604
5.13k
    case OpCode::I32__load16_s:
605
6.66k
    case OpCode::I32__load16_u:
606
7.35k
    case OpCode::I64__load8_s:
607
7.79k
    case OpCode::I64__load8_u:
608
8.11k
    case OpCode::I64__load16_s:
609
8.69k
    case OpCode::I64__load16_u:
610
9.05k
    case OpCode::I64__load32_s:
611
9.53k
    case OpCode::I64__load32_u:
612
9.95k
    case OpCode::I32__store:
613
11.3k
    case OpCode::I64__store:
614
11.3k
    case OpCode::F32__store:
615
11.4k
    case OpCode::F64__store:
616
11.7k
    case OpCode::I32__store8:
617
11.7k
    case OpCode::I64__store8:
618
11.9k
    case OpCode::I32__store16:
619
12.0k
    case OpCode::I64__store16:
620
12.1k
    case OpCode::I64__store32:
621
12.8k
    case OpCode::Memory__size:
622
13.6k
    case OpCode::Memory__grow:
623
13.7k
    case OpCode::Memory__init:
624
13.7k
    case OpCode::Data__drop:
625
13.9k
    case OpCode::Memory__copy:
626
14.6k
    case OpCode::Memory__fill:
627
531k
    case OpCode::I32__const:
628
601k
    case OpCode::I64__const:
629
615k
    case OpCode::F32__const:
630
621k
    case OpCode::F64__const:
631
621k
      return compileMemoryOp(Instr);
632
    // Unary Numeric Instructions
633
7.19k
    case OpCode::I32__eqz:
634
8.44k
    case OpCode::I64__eqz:
635
10.4k
    case OpCode::I32__clz:
636
10.7k
    case OpCode::I64__clz:
637
12.7k
    case OpCode::I32__ctz:
638
13.3k
    case OpCode::I64__ctz:
639
28.9k
    case OpCode::I32__popcnt:
640
30.8k
    case OpCode::I64__popcnt:
641
31.6k
    case OpCode::F32__abs:
642
32.2k
    case OpCode::F64__abs:
643
33.0k
    case OpCode::F32__neg:
644
33.6k
    case OpCode::F64__neg:
645
35.1k
    case OpCode::F32__ceil:
646
37.3k
    case OpCode::F64__ceil:
647
38.0k
    case OpCode::F32__floor:
648
38.4k
    case OpCode::F64__floor:
649
39.0k
    case OpCode::F32__trunc:
650
39.3k
    case OpCode::F64__trunc:
651
39.9k
    case OpCode::F32__nearest:
652
40.3k
    case OpCode::F64__nearest:
653
40.7k
    case OpCode::F32__sqrt:
654
41.9k
    case OpCode::F64__sqrt:
655
42.2k
    case OpCode::I32__wrap_i64:
656
43.5k
    case OpCode::I32__trunc_f32_s:
657
43.8k
    case OpCode::I32__trunc_f64_s:
658
43.9k
    case OpCode::I32__trunc_f32_u:
659
45.0k
    case OpCode::I32__trunc_f64_u:
660
47.1k
    case OpCode::I64__extend_i32_s:
661
47.5k
    case OpCode::I64__extend_i32_u:
662
47.6k
    case OpCode::I64__trunc_f32_s:
663
47.9k
    case OpCode::I64__trunc_f64_s:
664
49.0k
    case OpCode::I64__trunc_f32_u:
665
50.6k
    case OpCode::I64__trunc_f64_u:
666
52.1k
    case OpCode::F32__convert_i32_s:
667
52.5k
    case OpCode::F32__convert_i64_s:
668
53.1k
    case OpCode::F32__convert_i32_u:
669
54.4k
    case OpCode::F32__convert_i64_u:
670
55.8k
    case OpCode::F64__convert_i32_s:
671
59.7k
    case OpCode::F64__convert_i64_s:
672
61.9k
    case OpCode::F64__convert_i32_u:
673
62.0k
    case OpCode::F64__convert_i64_u:
674
62.2k
    case OpCode::F32__demote_f64:
675
62.3k
    case OpCode::F64__promote_f32:
676
62.9k
    case OpCode::I32__reinterpret_f32:
677
63.5k
    case OpCode::I64__reinterpret_f64:
678
67.5k
    case OpCode::F32__reinterpret_i32:
679
68.6k
    case OpCode::F64__reinterpret_i64:
680
71.2k
    case OpCode::I32__extend8_s:
681
74.0k
    case OpCode::I32__extend16_s:
682
74.4k
    case OpCode::I64__extend8_s:
683
75.0k
    case OpCode::I64__extend16_s:
684
75.6k
    case OpCode::I64__extend32_s:
685
76.7k
    case OpCode::I32__eq:
686
76.9k
    case OpCode::I64__eq:
687
77.6k
    case OpCode::I32__ne:
688
77.7k
    case OpCode::I64__ne:
689
82.0k
    case OpCode::I32__lt_s:
690
82.5k
    case OpCode::I64__lt_s:
691
88.4k
    case OpCode::I32__lt_u:
692
88.7k
    case OpCode::I64__lt_u:
693
89.6k
    case OpCode::I32__gt_s:
694
90.1k
    case OpCode::I64__gt_s:
695
95.6k
    case OpCode::I32__gt_u:
696
95.8k
    case OpCode::I64__gt_u:
697
97.6k
    case OpCode::I32__le_s:
698
98.5k
    case OpCode::I64__le_s:
699
99.0k
    case OpCode::I32__le_u:
700
100k
    case OpCode::I64__le_u:
701
101k
    case OpCode::I32__ge_s:
702
101k
    case OpCode::I64__ge_s:
703
102k
    case OpCode::I32__ge_u:
704
103k
    case OpCode::I64__ge_u:
705
103k
    case OpCode::F32__eq:
706
103k
    case OpCode::F64__eq:
707
103k
    case OpCode::F32__ne:
708
103k
    case OpCode::F64__ne:
709
103k
    case OpCode::F32__lt:
710
103k
    case OpCode::F64__lt:
711
103k
    case OpCode::F32__gt:
712
103k
    case OpCode::F64__gt:
713
103k
    case OpCode::F32__le:
714
104k
    case OpCode::F64__le:
715
104k
    case OpCode::F32__ge:
716
104k
    case OpCode::F64__ge:
717
105k
    case OpCode::I32__add:
718
105k
    case OpCode::I64__add:
719
107k
    case OpCode::I32__sub:
720
107k
    case OpCode::I64__sub:
721
108k
    case OpCode::I32__mul:
722
108k
    case OpCode::I64__mul:
723
110k
    case OpCode::I32__div_s:
724
110k
    case OpCode::I64__div_s:
725
113k
    case OpCode::I32__div_u:
726
113k
    case OpCode::I64__div_u:
727
114k
    case OpCode::I32__rem_s:
728
115k
    case OpCode::I64__rem_s:
729
116k
    case OpCode::I32__rem_u:
730
117k
    case OpCode::I64__rem_u:
731
118k
    case OpCode::I32__and:
732
119k
    case OpCode::I64__and:
733
120k
    case OpCode::I32__or:
734
120k
    case OpCode::I64__or:
735
122k
    case OpCode::I32__xor:
736
122k
    case OpCode::I64__xor:
737
124k
    case OpCode::I32__shl:
738
124k
    case OpCode::I64__shl:
739
126k
    case OpCode::I32__shr_s:
740
126k
    case OpCode::I64__shr_s:
741
130k
    case OpCode::I32__shr_u:
742
130k
    case OpCode::I64__shr_u:
743
133k
    case OpCode::I32__rotl:
744
134k
    case OpCode::I32__rotr:
745
135k
    case OpCode::I64__rotl:
746
136k
    case OpCode::I64__rotr:
747
136k
    case OpCode::F32__add:
748
137k
    case OpCode::F64__add:
749
137k
    case OpCode::F32__sub:
750
137k
    case OpCode::F64__sub:
751
137k
    case OpCode::F32__mul:
752
138k
    case OpCode::F64__mul:
753
138k
    case OpCode::F32__div:
754
138k
    case OpCode::F64__div:
755
138k
    case OpCode::F32__min:
756
139k
    case OpCode::F64__min:
757
139k
    case OpCode::F32__max:
758
139k
    case OpCode::F64__max:
759
140k
    case OpCode::F32__copysign:
760
140k
    case OpCode::F64__copysign:
761
140k
    case OpCode::I32__trunc_sat_f32_s:
762
141k
    case OpCode::I32__trunc_sat_f32_u:
763
141k
    case OpCode::I32__trunc_sat_f64_s:
764
142k
    case OpCode::I32__trunc_sat_f64_u:
765
142k
    case OpCode::I64__trunc_sat_f32_s:
766
142k
    case OpCode::I64__trunc_sat_f32_u:
767
142k
    case OpCode::I64__trunc_sat_f64_s:
768
143k
    case OpCode::I64__trunc_sat_f64_u:
769
143k
      return compileNumericOp(Instr);
770
4.31k
    case OpCode::V128__load:
771
4.47k
    case OpCode::V128__load8x8_s:
772
4.52k
    case OpCode::V128__load8x8_u:
773
4.83k
    case OpCode::V128__load16x4_s:
774
5.28k
    case OpCode::V128__load16x4_u:
775
5.41k
    case OpCode::V128__load32x2_s:
776
5.59k
    case OpCode::V128__load32x2_u:
777
5.67k
    case OpCode::V128__load8_splat:
778
5.79k
    case OpCode::V128__load16_splat:
779
5.96k
    case OpCode::V128__load32_splat:
780
6.09k
    case OpCode::V128__load64_splat:
781
6.17k
    case OpCode::V128__load32_zero:
782
6.31k
    case OpCode::V128__load64_zero:
783
6.53k
    case OpCode::V128__store:
784
6.67k
    case OpCode::V128__load8_lane:
785
6.79k
    case OpCode::V128__load16_lane:
786
6.89k
    case OpCode::V128__load32_lane:
787
6.92k
    case OpCode::V128__load64_lane:
788
7.07k
    case OpCode::V128__store8_lane:
789
7.15k
    case OpCode::V128__store16_lane:
790
7.21k
    case OpCode::V128__store32_lane:
791
7.24k
    case OpCode::V128__store64_lane:
792
7.58k
    case OpCode::V128__const:
793
7.60k
    case OpCode::I8x16__shuffle:
794
7.66k
    case OpCode::I8x16__extract_lane_s:
795
7.68k
    case OpCode::I8x16__extract_lane_u:
796
7.91k
    case OpCode::I8x16__replace_lane:
797
8.36k
    case OpCode::I16x8__extract_lane_s:
798
8.76k
    case OpCode::I16x8__extract_lane_u:
799
9.02k
    case OpCode::I16x8__replace_lane:
800
9.09k
    case OpCode::I32x4__extract_lane:
801
9.31k
    case OpCode::I32x4__replace_lane:
802
9.44k
    case OpCode::I64x2__extract_lane:
803
9.46k
    case OpCode::I64x2__replace_lane:
804
9.52k
    case OpCode::F32x4__extract_lane:
805
9.55k
    case OpCode::F32x4__replace_lane:
806
9.61k
    case OpCode::F64x2__extract_lane:
807
9.63k
    case OpCode::F64x2__replace_lane:
808
9.73k
    case OpCode::I8x16__swizzle:
809
44.2k
    case OpCode::I8x16__splat:
810
52.5k
    case OpCode::I16x8__splat:
811
53.7k
    case OpCode::I32x4__splat:
812
54.2k
    case OpCode::I64x2__splat:
813
54.5k
    case OpCode::F32x4__splat:
814
54.6k
    case OpCode::F64x2__splat:
815
54.7k
    case OpCode::I8x16__eq:
816
55.0k
    case OpCode::I8x16__ne:
817
55.1k
    case OpCode::I8x16__lt_s:
818
55.1k
    case OpCode::I8x16__lt_u:
819
55.3k
    case OpCode::I8x16__gt_s:
820
55.6k
    case OpCode::I8x16__gt_u:
821
55.7k
    case OpCode::I8x16__le_s:
822
55.8k
    case OpCode::I8x16__le_u:
823
56.4k
    case OpCode::I8x16__ge_s:
824
56.4k
    case OpCode::I8x16__ge_u:
825
56.6k
    case OpCode::I16x8__eq:
826
56.8k
    case OpCode::I16x8__ne:
827
56.8k
    case OpCode::I16x8__lt_s:
828
57.1k
    case OpCode::I16x8__lt_u:
829
57.3k
    case OpCode::I16x8__gt_s:
830
57.4k
    case OpCode::I16x8__gt_u:
831
57.5k
    case OpCode::I16x8__le_s:
832
57.6k
    case OpCode::I16x8__le_u:
833
57.7k
    case OpCode::I16x8__ge_s:
834
57.8k
    case OpCode::I16x8__ge_u:
835
57.8k
    case OpCode::I32x4__eq:
836
57.9k
    case OpCode::I32x4__ne:
837
58.0k
    case OpCode::I32x4__lt_s:
838
58.1k
    case OpCode::I32x4__lt_u:
839
58.3k
    case OpCode::I32x4__gt_s:
840
58.5k
    case OpCode::I32x4__gt_u:
841
58.7k
    case OpCode::I32x4__le_s:
842
59.0k
    case OpCode::I32x4__le_u:
843
59.0k
    case OpCode::I32x4__ge_s:
844
59.2k
    case OpCode::I32x4__ge_u:
845
59.3k
    case OpCode::I64x2__eq:
846
59.3k
    case OpCode::I64x2__ne:
847
59.4k
    case OpCode::I64x2__lt_s:
848
59.5k
    case OpCode::I64x2__gt_s:
849
59.6k
    case OpCode::I64x2__le_s:
850
59.7k
    case OpCode::I64x2__ge_s:
851
60.9k
    case OpCode::F32x4__eq:
852
60.9k
    case OpCode::F32x4__ne:
853
61.6k
    case OpCode::F32x4__lt:
854
61.7k
    case OpCode::F32x4__gt:
855
62.0k
    case OpCode::F32x4__le:
856
62.1k
    case OpCode::F32x4__ge:
857
62.2k
    case OpCode::F64x2__eq:
858
62.3k
    case OpCode::F64x2__ne:
859
62.4k
    case OpCode::F64x2__lt:
860
62.5k
    case OpCode::F64x2__gt:
861
62.6k
    case OpCode::F64x2__le:
862
62.7k
    case OpCode::F64x2__ge:
863
63.0k
    case OpCode::V128__not:
864
63.1k
    case OpCode::V128__and:
865
63.2k
    case OpCode::V128__andnot:
866
63.4k
    case OpCode::V128__or:
867
63.4k
    case OpCode::V128__xor:
868
63.6k
    case OpCode::V128__bitselect:
869
63.7k
    case OpCode::V128__any_true:
870
64.9k
    case OpCode::I8x16__abs:
871
67.1k
    case OpCode::I8x16__neg:
872
67.2k
    case OpCode::I8x16__popcnt:
873
67.5k
    case OpCode::I8x16__all_true:
874
68.1k
    case OpCode::I8x16__bitmask:
875
68.2k
    case OpCode::I8x16__narrow_i16x8_s:
876
68.4k
    case OpCode::I8x16__narrow_i16x8_u:
877
68.5k
    case OpCode::I8x16__shl:
878
69.6k
    case OpCode::I8x16__shr_s:
879
69.7k
    case OpCode::I8x16__shr_u:
880
69.7k
    case OpCode::I8x16__add:
881
70.1k
    case OpCode::I8x16__add_sat_s:
882
70.2k
    case OpCode::I8x16__add_sat_u:
883
70.2k
    case OpCode::I8x16__sub:
884
70.4k
    case OpCode::I8x16__sub_sat_s:
885
70.5k
    case OpCode::I8x16__sub_sat_u:
886
70.6k
    case OpCode::I8x16__min_s:
887
70.6k
    case OpCode::I8x16__min_u:
888
70.9k
    case OpCode::I8x16__max_s:
889
71.0k
    case OpCode::I8x16__max_u:
890
71.2k
    case OpCode::I8x16__avgr_u:
891
71.4k
    case OpCode::I16x8__abs:
892
71.6k
    case OpCode::I16x8__neg:
893
71.7k
    case OpCode::I16x8__all_true:
894
71.8k
    case OpCode::I16x8__bitmask:
895
71.8k
    case OpCode::I16x8__narrow_i32x4_s:
896
72.2k
    case OpCode::I16x8__narrow_i32x4_u:
897
73.2k
    case OpCode::I16x8__extend_low_i8x16_s:
898
73.3k
    case OpCode::I16x8__extend_high_i8x16_s:
899
73.7k
    case OpCode::I16x8__extend_low_i8x16_u:
900
73.7k
    case OpCode::I16x8__extend_high_i8x16_u:
901
73.8k
    case OpCode::I16x8__shl:
902
74.1k
    case OpCode::I16x8__shr_s:
903
74.2k
    case OpCode::I16x8__shr_u:
904
74.3k
    case OpCode::I16x8__add:
905
74.3k
    case OpCode::I16x8__add_sat_s:
906
74.7k
    case OpCode::I16x8__add_sat_u:
907
75.0k
    case OpCode::I16x8__sub:
908
75.0k
    case OpCode::I16x8__sub_sat_s:
909
75.1k
    case OpCode::I16x8__sub_sat_u:
910
75.3k
    case OpCode::I16x8__mul:
911
75.4k
    case OpCode::I16x8__min_s:
912
75.5k
    case OpCode::I16x8__min_u:
913
75.6k
    case OpCode::I16x8__max_s:
914
76.1k
    case OpCode::I16x8__max_u:
915
76.2k
    case OpCode::I16x8__avgr_u:
916
76.3k
    case OpCode::I16x8__extmul_low_i8x16_s:
917
76.5k
    case OpCode::I16x8__extmul_high_i8x16_s:
918
76.6k
    case OpCode::I16x8__extmul_low_i8x16_u:
919
77.0k
    case OpCode::I16x8__extmul_high_i8x16_u:
920
77.1k
    case OpCode::I16x8__q15mulr_sat_s:
921
77.5k
    case OpCode::I16x8__extadd_pairwise_i8x16_s:
922
77.8k
    case OpCode::I16x8__extadd_pairwise_i8x16_u:
923
77.9k
    case OpCode::I32x4__abs:
924
78.1k
    case OpCode::I32x4__neg:
925
78.2k
    case OpCode::I32x4__all_true:
926
78.3k
    case OpCode::I32x4__bitmask:
927
78.4k
    case OpCode::I32x4__extend_low_i16x8_s:
928
78.9k
    case OpCode::I32x4__extend_high_i16x8_s:
929
80.9k
    case OpCode::I32x4__extend_low_i16x8_u:
930
81.0k
    case OpCode::I32x4__extend_high_i16x8_u:
931
82.0k
    case OpCode::I32x4__shl:
932
82.1k
    case OpCode::I32x4__shr_s:
933
82.6k
    case OpCode::I32x4__shr_u:
934
82.7k
    case OpCode::I32x4__add:
935
82.8k
    case OpCode::I32x4__sub:
936
83.0k
    case OpCode::I32x4__mul:
937
83.1k
    case OpCode::I32x4__min_s:
938
83.2k
    case OpCode::I32x4__min_u:
939
83.3k
    case OpCode::I32x4__max_s:
940
83.3k
    case OpCode::I32x4__max_u:
941
83.4k
    case OpCode::I32x4__extmul_low_i16x8_s:
942
83.5k
    case OpCode::I32x4__extmul_high_i16x8_s:
943
83.7k
    case OpCode::I32x4__extmul_low_i16x8_u:
944
83.9k
    case OpCode::I32x4__extmul_high_i16x8_u:
945
85.0k
    case OpCode::I32x4__extadd_pairwise_i16x8_s:
946
85.8k
    case OpCode::I32x4__extadd_pairwise_i16x8_u:
947
85.9k
    case OpCode::I32x4__dot_i16x8_s:
948
86.8k
    case OpCode::I64x2__abs:
949
87.4k
    case OpCode::I64x2__neg:
950
87.6k
    case OpCode::I64x2__all_true:
951
87.9k
    case OpCode::I64x2__bitmask:
952
88.2k
    case OpCode::I64x2__extend_low_i32x4_s:
953
89.0k
    case OpCode::I64x2__extend_high_i32x4_s:
954
89.2k
    case OpCode::I64x2__extend_low_i32x4_u:
955
89.7k
    case OpCode::I64x2__extend_high_i32x4_u:
956
89.9k
    case OpCode::I64x2__shl:
957
90.2k
    case OpCode::I64x2__shr_s:
958
90.3k
    case OpCode::I64x2__shr_u:
959
90.3k
    case OpCode::I64x2__add:
960
90.5k
    case OpCode::I64x2__sub:
961
90.6k
    case OpCode::I64x2__mul:
962
90.6k
    case OpCode::I64x2__extmul_low_i32x4_s:
963
91.0k
    case OpCode::I64x2__extmul_high_i32x4_s:
964
91.1k
    case OpCode::I64x2__extmul_low_i32x4_u:
965
91.2k
    case OpCode::I64x2__extmul_high_i32x4_u:
966
91.3k
    case OpCode::F32x4__abs:
967
91.5k
    case OpCode::F32x4__neg:
968
91.7k
    case OpCode::F32x4__sqrt:
969
91.8k
    case OpCode::F32x4__add:
970
92.1k
    case OpCode::F32x4__sub:
971
92.1k
    case OpCode::F32x4__mul:
972
92.2k
    case OpCode::F32x4__div:
973
92.4k
    case OpCode::F32x4__min:
974
92.4k
    case OpCode::F32x4__max:
975
92.5k
    case OpCode::F32x4__pmin:
976
92.7k
    case OpCode::F32x4__pmax:
977
93.7k
    case OpCode::F32x4__ceil:
978
95.6k
    case OpCode::F32x4__floor:
979
97.4k
    case OpCode::F32x4__trunc:
980
97.7k
    case OpCode::F32x4__nearest:
981
98.2k
    case OpCode::F64x2__abs:
982
98.8k
    case OpCode::F64x2__neg:
983
98.8k
    case OpCode::F64x2__sqrt:
984
98.9k
    case OpCode::F64x2__add:
985
99.1k
    case OpCode::F64x2__sub:
986
99.3k
    case OpCode::F64x2__mul:
987
99.3k
    case OpCode::F64x2__div:
988
99.5k
    case OpCode::F64x2__min:
989
99.6k
    case OpCode::F64x2__max:
990
99.9k
    case OpCode::F64x2__pmin:
991
100k
    case OpCode::F64x2__pmax:
992
100k
    case OpCode::F64x2__ceil:
993
101k
    case OpCode::F64x2__floor:
994
101k
    case OpCode::F64x2__trunc:
995
101k
    case OpCode::F64x2__nearest:
996
101k
    case OpCode::I32x4__trunc_sat_f32x4_s:
997
105k
    case OpCode::I32x4__trunc_sat_f32x4_u:
998
105k
    case OpCode::F32x4__convert_i32x4_s:
999
106k
    case OpCode::F32x4__convert_i32x4_u:
1000
107k
    case OpCode::I32x4__trunc_sat_f64x2_s_zero:
1001
109k
    case OpCode::I32x4__trunc_sat_f64x2_u_zero:
1002
109k
    case OpCode::F64x2__convert_low_i32x4_s:
1003
110k
    case OpCode::F64x2__convert_low_i32x4_u:
1004
111k
    case OpCode::F32x4__demote_f64x2_zero:
1005
112k
    case OpCode::F64x2__promote_low_f32x4:
1006
112k
    case OpCode::I8x16__relaxed_swizzle:
1007
112k
    case OpCode::I32x4__relaxed_trunc_f32x4_s:
1008
112k
    case OpCode::I32x4__relaxed_trunc_f32x4_u:
1009
112k
    case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
1010
112k
    case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
1011
112k
    case OpCode::F32x4__relaxed_madd:
1012
112k
    case OpCode::F32x4__relaxed_nmadd:
1013
112k
    case OpCode::F64x2__relaxed_madd:
1014
112k
    case OpCode::F64x2__relaxed_nmadd:
1015
112k
    case OpCode::I8x16__relaxed_laneselect:
1016
112k
    case OpCode::I16x8__relaxed_laneselect:
1017
112k
    case OpCode::I32x4__relaxed_laneselect:
1018
112k
    case OpCode::I64x2__relaxed_laneselect:
1019
112k
    case OpCode::F32x4__relaxed_min:
1020
112k
    case OpCode::F32x4__relaxed_max:
1021
112k
    case OpCode::F64x2__relaxed_min:
1022
112k
    case OpCode::F64x2__relaxed_max:
1023
112k
    case OpCode::I16x8__relaxed_q15mulr_s:
1024
112k
    case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
1025
112k
    case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
1026
112k
      return compileVectorOp(Instr);
1027
192
    case OpCode::Atomic__fence:
1028
261
    case OpCode::Memory__atomic__notify:
1029
265
    case OpCode::Memory__atomic__wait32:
1030
267
    case OpCode::Memory__atomic__wait64:
1031
267
    case OpCode::I32__atomic__load:
1032
267
    case OpCode::I64__atomic__load:
1033
267
    case OpCode::I32__atomic__load8_u:
1034
267
    case OpCode::I32__atomic__load16_u:
1035
267
    case OpCode::I64__atomic__load8_u:
1036
267
    case OpCode::I64__atomic__load16_u:
1037
267
    case OpCode::I64__atomic__load32_u:
1038
267
    case OpCode::I32__atomic__store:
1039
267
    case OpCode::I64__atomic__store:
1040
267
    case OpCode::I32__atomic__store8:
1041
267
    case OpCode::I32__atomic__store16:
1042
267
    case OpCode::I64__atomic__store8:
1043
267
    case OpCode::I64__atomic__store16:
1044
267
    case OpCode::I64__atomic__store32:
1045
267
    case OpCode::I32__atomic__rmw__add:
1046
267
    case OpCode::I64__atomic__rmw__add:
1047
267
    case OpCode::I32__atomic__rmw8__add_u:
1048
267
    case OpCode::I32__atomic__rmw16__add_u:
1049
267
    case OpCode::I64__atomic__rmw8__add_u:
1050
267
    case OpCode::I64__atomic__rmw16__add_u:
1051
267
    case OpCode::I64__atomic__rmw32__add_u:
1052
267
    case OpCode::I32__atomic__rmw__sub:
1053
267
    case OpCode::I64__atomic__rmw__sub:
1054
267
    case OpCode::I32__atomic__rmw8__sub_u:
1055
267
    case OpCode::I32__atomic__rmw16__sub_u:
1056
267
    case OpCode::I64__atomic__rmw8__sub_u:
1057
267
    case OpCode::I64__atomic__rmw16__sub_u:
1058
267
    case OpCode::I64__atomic__rmw32__sub_u:
1059
267
    case OpCode::I32__atomic__rmw__and:
1060
267
    case OpCode::I64__atomic__rmw__and:
1061
267
    case OpCode::I32__atomic__rmw8__and_u:
1062
267
    case OpCode::I32__atomic__rmw16__and_u:
1063
267
    case OpCode::I64__atomic__rmw8__and_u:
1064
267
    case OpCode::I64__atomic__rmw16__and_u:
1065
267
    case OpCode::I64__atomic__rmw32__and_u:
1066
267
    case OpCode::I32__atomic__rmw__or:
1067
267
    case OpCode::I64__atomic__rmw__or:
1068
267
    case OpCode::I32__atomic__rmw8__or_u:
1069
267
    case OpCode::I32__atomic__rmw16__or_u:
1070
267
    case OpCode::I64__atomic__rmw8__or_u:
1071
267
    case OpCode::I64__atomic__rmw16__or_u:
1072
267
    case OpCode::I64__atomic__rmw32__or_u:
1073
267
    case OpCode::I32__atomic__rmw__xor:
1074
267
    case OpCode::I64__atomic__rmw__xor:
1075
267
    case OpCode::I32__atomic__rmw8__xor_u:
1076
267
    case OpCode::I32__atomic__rmw16__xor_u:
1077
267
    case OpCode::I64__atomic__rmw8__xor_u:
1078
267
    case OpCode::I64__atomic__rmw16__xor_u:
1079
267
    case OpCode::I64__atomic__rmw32__xor_u:
1080
267
    case OpCode::I32__atomic__rmw__xchg:
1081
267
    case OpCode::I64__atomic__rmw__xchg:
1082
267
    case OpCode::I32__atomic__rmw8__xchg_u:
1083
267
    case OpCode::I32__atomic__rmw16__xchg_u:
1084
267
    case OpCode::I64__atomic__rmw8__xchg_u:
1085
267
    case OpCode::I64__atomic__rmw16__xchg_u:
1086
267
    case OpCode::I64__atomic__rmw32__xchg_u:
1087
267
    case OpCode::I32__atomic__rmw__cmpxchg:
1088
267
    case OpCode::I64__atomic__rmw__cmpxchg:
1089
267
    case OpCode::I32__atomic__rmw8__cmpxchg_u:
1090
267
    case OpCode::I32__atomic__rmw16__cmpxchg_u:
1091
267
    case OpCode::I64__atomic__rmw8__cmpxchg_u:
1092
267
    case OpCode::I64__atomic__rmw16__cmpxchg_u:
1093
267
    case OpCode::I64__atomic__rmw32__cmpxchg_u:
1094
267
      return compileAtomicOp(Instr);
1095
1096
    // Wide Arithmetic Instructions
1097
0
    case OpCode::I64__add128:
1098
0
    case OpCode::I64__sub128:
1099
0
    case OpCode::I64__mul_wide_s:
1100
0
    case OpCode::I64__mul_wide_u:
1101
0
      return compileNumericOp(Instr);
1102
1103
0
    default:
1104
0
      assumingUnreachable();
1105
961k
    }
1106
69.3k
    return {};
1107
961k
  };
1108
1109
1.50M
  for (const auto &Instr : Instrs) {
1110
    // Update instruction count
1111
1.50M
    if (LocalInstrCount) {
1112
0
      Builder.createStore(Builder.createAdd(Builder.createLoad(Context.Int64Ty,
1113
0
                                                               LocalInstrCount),
1114
0
                                            LLContext.getInt64(1)),
1115
0
                          LocalInstrCount);
1116
0
    }
1117
1.50M
    if (LocalGas) {
1118
0
      auto NewGas = Builder.createAdd(
1119
0
          Builder.createLoad(Context.Int64Ty, LocalGas),
1120
0
          Builder.createLoad(
1121
0
              Context.Int64Ty,
1122
0
              Builder.createConstInBoundsGEP2_64(
1123
0
                  LLVM::Type::getArrayType(Context.Int64Ty, UINT16_MAX + 1),
1124
0
                  Context.getCostTable(Builder, ExecCtx), 0,
1125
0
                  uint16_t(Instr.getOpCode()))));
1126
0
      Builder.createStore(NewGas, LocalGas);
1127
0
    }
1128
1129
    // Make the instruction node according to Code.
1130
1.50M
    EXPECTED_TRY(Dispatch(Instr));
1131
1.50M
  }
1132
10.6k
  return {};
1133
10.6k
}
1134
1135
11.3k
void FunctionCompiler::compileReturn() noexcept {
1136
11.3k
  updateInstrCount();
1137
11.3k
  updateGas();
1138
11.3k
  auto Ty = F.Ty.getReturnType();
1139
11.3k
  if (Ty.isVoidTy()) {
1140
2.40k
    Builder.createRetVoid();
1141
8.93k
  } else if (Ty.isStructTy()) {
1142
389
    const auto Count = Ty.getStructNumElements();
1143
389
    std::vector<LLVM::Value> Ret(Count);
1144
1.53k
    for (unsigned I = 0; I < Count; ++I) {
1145
1.14k
      const unsigned J = Count - 1 - I;
1146
1.14k
      Ret[J] = stackPop();
1147
1.14k
    }
1148
389
    Builder.createAggregateRet(Ret);
1149
8.54k
  } else {
1150
8.54k
    Builder.createRet(stackPop());
1151
8.54k
  }
1152
11.3k
}
1153
1154
2.89k
void FunctionCompiler::checkStackLimit() noexcept {
1155
  // Trap if the allocated but not yet written frame reaches below the limit.
1156
2.89k
  auto SP = Builder.createPtrToInt(Builder.createStackSave(Context.Int8PtrTy),
1157
2.89k
                                   Context.Int64Ty);
1158
2.89k
  auto Limit = Builder.createPtrToInt(Context.getStackLimit(Builder, ExecCtx),
1159
2.89k
                                      Context.Int64Ty);
1160
2.89k
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "stack_ok");
1161
2.89k
  auto IsOk = Builder.createLikely(Builder.createICmpULE(Limit, SP));
1162
2.89k
  Builder.createCondBr(IsOk, OkBB,
1163
2.89k
                       getTrapBB(ErrCode::Value::CallStackExhausted));
1164
2.89k
  Builder.positionAtEnd(OkBB);
1165
2.89k
}
1166
1167
24.1k
void FunctionCompiler::updateInstrCount() noexcept {
1168
24.1k
  if (LocalInstrCount) {
1169
0
    auto Store [[maybe_unused]] = Builder.createAtomicRMW(
1170
0
        LLVMAtomicRMWBinOpAdd, Context.getInstrCount(Builder, ExecCtx),
1171
0
        Builder.createLoad(Context.Int64Ty, LocalInstrCount),
1172
0
        LLVMAtomicOrderingMonotonic);
1173
0
#if LLVM_VERSION_MAJOR < 13
1174
#else
1175
    Store.setAlignment(8);
1176
#endif
1177
0
    Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
1178
0
  }
1179
24.1k
}
1180
1181
21.9k
void FunctionCompiler::updateGas() noexcept {
1182
21.9k
  if (LocalGas) {
1183
0
    auto CurrBB = Builder.getInsertBlock();
1184
0
    auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_check");
1185
0
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_ok");
1186
0
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_end");
1187
1188
0
    auto Cost = Builder.createLoad(Context.Int64Ty, LocalGas);
1189
0
    Cost.setAlignment(64);
1190
0
    auto GasPtr = Context.getGas(Builder, ExecCtx);
1191
0
    auto GasLimit = Context.getGasLimit(Builder, ExecCtx);
1192
0
    auto Gas = Builder.createLoad(Context.Int64Ty, GasPtr);
1193
0
    Gas.setAlignment(64);
1194
0
    Gas.setOrdering(LLVMAtomicOrderingMonotonic);
1195
0
    Builder.createBr(CheckBB);
1196
0
    Builder.positionAtEnd(CheckBB);
1197
1198
0
    auto PHIOldGas = Builder.createPHI(Context.Int64Ty);
1199
0
    auto NewGas = Builder.createAdd(PHIOldGas, Cost);
1200
0
    auto IsGasRemain =
1201
0
        Builder.createLikely(Builder.createICmpULE(NewGas, GasLimit));
1202
0
    Builder.createCondBr(IsGasRemain, OkBB,
1203
0
                         getTrapBB(ErrCode::Value::CostLimitExceeded));
1204
0
    Builder.positionAtEnd(OkBB);
1205
1206
0
    auto RGasAndSucceed = Builder.createAtomicCmpXchg(
1207
0
        GasPtr, PHIOldGas, NewGas, LLVMAtomicOrderingMonotonic,
1208
0
        LLVMAtomicOrderingMonotonic);
1209
0
#if LLVM_VERSION_MAJOR < 13
1210
#else
1211
    RGasAndSucceed.setAlignment(8);
1212
#endif
1213
0
    RGasAndSucceed.setWeak(true);
1214
0
    auto RGas = Builder.createExtractValue(RGasAndSucceed, 0);
1215
0
    auto Succeed = Builder.createExtractValue(RGasAndSucceed, 1);
1216
0
    Builder.createCondBr(Builder.createLikely(Succeed), EndBB, CheckBB);
1217
0
    Builder.positionAtEnd(EndBB);
1218
1219
0
    Builder.createStore(LLContext.getInt64(0), LocalGas);
1220
1221
0
    PHIOldGas.addIncoming(Gas, CurrBB);
1222
0
    PHIOldGas.addIncoming(RGas, OkBB);
1223
0
  }
1224
21.9k
}
1225
1226
8.23k
void FunctionCompiler::updateGasAtTrap() noexcept {
1227
8.23k
  if (LocalGas) {
1228
0
    auto Update [[maybe_unused]] = Builder.createAtomicRMW(
1229
0
        LLVMAtomicRMWBinOpAdd, Context.getGas(Builder, ExecCtx),
1230
0
        Builder.createLoad(Context.Int64Ty, LocalGas),
1231
0
        LLVMAtomicOrderingMonotonic);
1232
0
#if LLVM_VERSION_MAJOR < 13
1233
#else
1234
    Update.setAlignment(8);
1235
#endif
1236
0
  }
1237
8.23k
}
1238
1239
void FunctionCompiler::compileTryTableOp(
1240
402
    const AST::Instruction &Instr) noexcept {
1241
402
  const auto &TryDesc = Instr.getTryCatch();
1242
402
  auto Type = Context.resolveBlockType(TryDesc.ResType);
1243
402
  const auto Arity = Type.first.size();
1244
402
  std::vector<LLVM::Value> Args(Arity);
1245
1246
402
  auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "try_table");
1247
402
  auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "try_table.end");
1248
1249
402
  if (isUnreachable()) {
1250
    // The body is dead code, therefore no dispatch block is emitted and no
1251
    // pending checks inside will target it.
1252
411
    for (size_t I = 0; I < Arity; ++I) {
1253
204
      auto Ty = toLLVMType(LLContext, Type.first[I]);
1254
204
      Args[I] = LLVM::Value::getUndef(Ty);
1255
204
    }
1256
207
    Builder.createBr(Block);
1257
207
    Builder.positionAtEnd(Block);
1258
207
    enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
1259
207
    checkStop();
1260
207
    updateGas();
1261
207
    return;
1262
207
  }
1263
1264
381
  for (size_t I = 0; I < Arity; ++I) {
1265
186
    const size_t J = Arity - 1 - I;
1266
186
    Args[J] = stackPop();
1267
186
  }
1268
195
  Builder.createBr(Block);
1269
1270
195
  LLVM::BasicBlock DispatchBB = {};
1271
195
  const auto &Catch = TryDesc.Catch;
1272
195
  if (!Catch.empty()) {
1273
    // Emit the dispatch in the outer label context: the catch clause label
1274
    // indices are relative to the block enclosing this try_table.
1275
1
    DispatchBB = LLVM::BasicBlock::create(LLContext, F.Fn, "try.dispatch");
1276
1
    Builder.positionAtEnd(DispatchBB);
1277
1278
    // Clauses after a catch_all can never match, so no check is emitted for
1279
    // them.
1280
1
    auto PendingTagInst = Builder.createLoad(
1281
1
        Context.Int8PtrTy, Context.getPendingExnTagAddr(Builder, ExecCtx));
1282
1
    std::vector<
1283
1
        std::pair<const AST::Instruction::CatchDescriptor *, LLVM::BasicBlock>>
1284
1
        Cases;
1285
1
    bool HasCatchAll = false;
1286
1
    for (const auto &C : Catch) {
1287
1
      auto CaseBB = LLVM::BasicBlock::create(LLContext, F.Fn, "catch");
1288
1
      Cases.emplace_back(&C, CaseBB);
1289
1
      if (C.IsAll) {
1290
1
        Builder.createBr(CaseBB);
1291
1
        HasCatchAll = true;
1292
1
        break;
1293
1
      }
1294
0
      assuming(C.TagIndex < Context.Tags.size());
1295
0
      auto NextBB =
1296
0
          LLVM::BasicBlock::create(LLContext, F.Fn, "try.dispatch.next");
1297
0
      auto IsMatch = Builder.createICmpEQ(
1298
0
          PendingTagInst, Context.getTag(Builder, ModCtx, C.TagIndex));
1299
0
      Builder.createCondBr(IsMatch, CaseBB, NextBB);
1300
0
      Builder.positionAtEnd(NextBB);
1301
0
    }
1302
1
    if (!HasCatchAll) {
1303
0
      Builder.createBr(getEHDispatchTarget());
1304
0
    }
1305
1306
1
    for (const auto &[C, CaseBB] : Cases) {
1307
1
      Builder.positionAtEnd(CaseBB);
1308
1309
1
      const size_t StackSizeBefore = Stack.size();
1310
1
      uint32_t PayloadNum = 0;
1311
1
      if (!C->IsAll) {
1312
0
        const auto &TagFuncType =
1313
0
            Context.CompositeTypes[Context.Tags[C->TagIndex]]->getFuncType();
1314
0
        PayloadNum = static_cast<uint32_t>(TagFuncType.getParamTypes().size());
1315
0
      }
1316
1
      const uint32_t OutNum = PayloadNum + (C->IsRef ? 1U : 0U);
1317
1
      LLVM::Value Out = getTmpValues(OutNum);
1318
1
      Builder.createCall(
1319
1
          Context.getIntrinsic(
1320
1
              Builder, Executable::Intrinsics::kCatchPop,
1321
1
              LLVM::Type::getFunctionType(Context.VoidTy,
1322
1
                                          {Context.Int8PtrTy, Context.Int8PtrTy,
1323
1
                                           Context.Int32Ty, Context.Int32Ty},
1324
1
                                          false)),
1325
1
          {Context.getModuleInst(Builder, ModCtx), Out,
1326
1
           LLContext.getInt32(C->IsAll ? 0 : 1),
1327
1
           LLContext.getInt32(C->IsRef ? 1 : 0)});
1328
1329
1
      uint32_t OutIdx = 0;
1330
1
      if (!C->IsAll) {
1331
0
        const auto &TagFuncType =
1332
0
            Context.CompositeTypes[Context.Tags[C->TagIndex]]->getFuncType();
1333
0
        for (const auto &PType : TagFuncType.getParamTypes()) {
1334
0
          stackPush(Builder.createValuePtrLoad(
1335
0
              toLLVMType(LLContext, PType), Out, Context.Int8Ty,
1336
0
              static_cast<uint64_t>(OutIdx) * LLVM::kValSize));
1337
0
          ++OutIdx;
1338
0
        }
1339
0
      }
1340
1
      if (C->IsRef) {
1341
0
        stackPush(Builder.createValuePtrLoad(
1342
0
            Context.Int64x2Ty, Out, Context.Int8Ty,
1343
0
            static_cast<uint64_t>(OutIdx) * LLVM::kValSize));
1344
0
      }
1345
1
      endTmpValues();
1346
1
      setLableJumpPHI(C->LabelIndex);
1347
1
      Builder.createBr(getLabel(C->LabelIndex));
1348
1
      Stack.erase(Stack.begin() + static_cast<int64_t>(StackSizeBefore),
1349
1
                  Stack.end());
1350
1
    }
1351
1
  }
1352
1353
195
  Builder.positionAtEnd(Block);
1354
195
  enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
1355
195
  ControlStack.back().TryDispatchBB = DispatchBB;
1356
195
  checkStop();
1357
195
  updateGas();
1358
195
}
1359
1360
1
void FunctionCompiler::compileThrowOp(const uint32_t TagIndex) noexcept {
1361
1
  assuming(TagIndex < Context.Tags.size());
1362
1
  const auto &TagFuncType =
1363
1
      Context.CompositeTypes[Context.Tags[TagIndex]]->getFuncType();
1364
1
  const auto Arity = static_cast<uint32_t>(TagFuncType.getParamTypes().size());
1365
1366
1
  std::vector<LLVM::Value> Payload(Arity);
1367
1
  for (uint32_t I = 0; I < Arity; ++I) {
1368
0
    Payload[Arity - 1 - I] = stackPop();
1369
0
  }
1370
1
  LLVM::Value Vals = getTmpValues(Arity);
1371
1
  Builder.createArrayPtrStore(Payload, Vals, Context.Int8Ty, LLVM::kValSize);
1372
1373
1
  Builder.createCall(
1374
1
      Context.getIntrinsic(
1375
1
          Builder, Executable::Intrinsics::kThrow,
1376
1
          LLVM::Type::getFunctionType(Context.VoidTy,
1377
1
                                      {Context.Int8PtrTy, Context.Int32Ty,
1378
1
                                       Context.Int8PtrTy, Context.Int32Ty},
1379
1
                                      false)),
1380
1
      {Context.getModuleInst(Builder, ModCtx), LLContext.getInt32(TagIndex),
1381
1
       Vals, LLContext.getInt32(Arity)});
1382
1
  endTmpValues();
1383
1384
1
  Builder.createBr(getEHDispatchTarget());
1385
1
  setUnreachable();
1386
1
  Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "throw.end"));
1387
1
}
1388
1389
5
void FunctionCompiler::compileThrowRefOp() noexcept {
1390
5
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1391
5
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "throw_ref.ok");
1392
5
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1393
5
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1394
5
      LLContext.getInt64(0)));
1395
5
  Builder.createCondBr(IsRefNotNull, OkBB,
1396
5
                       getTrapBB(ErrCode::Value::AccessNullException));
1397
5
  Builder.positionAtEnd(OkBB);
1398
1399
5
  Builder.createCall(
1400
5
      Context.getIntrinsic(Builder, Executable::Intrinsics::kThrowRef,
1401
5
                           LLVM::Type::getFunctionType(
1402
5
                               Context.VoidTy, {Context.Int64x2Ty}, false)),
1403
5
      {Ref});
1404
1405
5
  Builder.createBr(getEHDispatchTarget());
1406
5
  setUnreachable();
1407
5
  Builder.positionAtEnd(
1408
5
      LLVM::BasicBlock::create(LLContext, F.Fn, "throw_ref.end"));
1409
5
}
1410
1411
3.04k
void FunctionCompiler::compileCallOp(const unsigned int FuncIndex) noexcept {
1412
3.04k
  const auto &FuncType =
1413
3.04k
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1414
3.04k
          ->getFuncType();
1415
3.04k
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1416
3.04k
  const auto &ParamTypes = FuncType.getParamTypes();
1417
1418
3.04k
  std::vector<LLVM::Value> Args(ParamTypes.size() + 2);
1419
3.04k
  Args[0] = F.Fn.getFirstParam();
1420
3.04k
  Args[1] = F.Fn.getFirstParam().getNextParam();
1421
3.76k
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1422
728
    const size_t J = ParamTypes.size() - 1 - I;
1423
728
    Args[J + 2] = stackPop();
1424
728
  }
1425
1426
3.04k
  LLVM::Value Ret;
1427
3.04k
  if (IsLazyJIT) {
1428
0
    bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1429
0
    if (IsImport) {
1430
0
      Ret = Builder.createCall(Function, Args);
1431
0
    } else {
1432
0
      auto FTy = toLLVMType(LLContext, Context.ModCtxPtrTy,
1433
0
                            Context.ExecCtxPtrTy, FuncType);
1434
1435
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1436
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1437
0
      }
1438
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1439
0
      if (!CacheVar) {
1440
0
        CacheVar = Context.LLModule.get().addGlobal(
1441
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1442
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1443
0
      }
1444
1445
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.check");
1446
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.resolve");
1447
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.call");
1448
1449
0
      Builder.createBr(CheckBB);
1450
0
      Builder.positionAtEnd(CheckBB);
1451
1452
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1453
0
      CachedPtr.setAlignment(8);
1454
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1455
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1456
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1457
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1458
1459
0
      Builder.positionAtEnd(ResolveBB);
1460
0
      auto FPtr = Builder.createCall(
1461
0
          Context.getIntrinsic(
1462
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1463
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(),
1464
0
                                          {Context.Int8PtrTy, Context.Int32Ty},
1465
0
                                          false)),
1466
0
          {Context.getModuleInst(Builder, ModCtx),
1467
0
           LLContext.getInt32(FuncIndex)});
1468
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1469
0
      Store.setAlignment(8);
1470
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1471
0
      Builder.createBr(CallBB);
1472
1473
0
      Builder.positionAtEnd(CallBB);
1474
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1475
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1476
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1477
1478
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1479
0
    }
1480
3.04k
  } else {
1481
3.04k
    Ret = Builder.createCall(Function, Args);
1482
3.04k
  }
1483
  // A wasm call keeps its frame, so LLVM cannot turn recursion into a loop that
1484
  // never exhausts the stack.
1485
3.04k
  Ret.setNoTailCall();
1486
1487
3.04k
  auto Ty = Ret.getType();
1488
3.04k
  if (Ty.isVoidTy()) {
1489
    // nothing to do
1490
1.64k
  } else if (Ty.isStructTy()) {
1491
179
    for (auto Val : unpackStruct(Builder, Ret)) {
1492
179
      stackPush(Val);
1493
179
    }
1494
1.32k
  } else {
1495
1.32k
    stackPush(Ret);
1496
1.32k
  }
1497
1498
3.04k
  checkPendingException();
1499
3.04k
}
1500
1501
void FunctionCompiler::compileIndirectCallOp(
1502
1.06k
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1503
1.06k
  auto TryFastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.tryfast");
1504
1.06k
  auto NonNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.nonnull");
1505
1.06k
  auto FastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.fast");
1506
1.06k
  auto SlowBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.slow");
1507
1.06k
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1508
1.06k
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1509
1.06k
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1510
1511
1.06k
  LLVM::Value FuncIndex = stackPop();
1512
1.06k
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1513
1.06k
  auto FTy = toLLVMType(Context.LLContext, Context.ModCtxPtrTy,
1514
1.06k
                        Context.ExecCtxPtrTy, FuncType);
1515
1.06k
  auto RTy = FTy.getReturnType();
1516
1.06k
  auto FPtrTy = FTy.getPointerTo();
1517
1.06k
  auto TableIdx = LLContext.getInt32(TableIndex);
1518
1.06k
  auto TypeIdx = LLContext.getInt32(FuncTypeIndex);
1519
1520
1.06k
  const size_t ArgSize = FuncType.getParamTypes().size();
1521
1.06k
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1522
1.06k
  std::vector<LLVM::Value> ArgsVec(ArgSize + 2, nullptr);
1523
1.06k
  ArgsVec[0] = F.Fn.getFirstParam();
1524
1.06k
  ArgsVec[1] = F.Fn.getFirstParam().getNextParam();
1525
1.99k
  for (size_t I = 0; I < ArgSize; ++I) {
1526
929
    const size_t J = ArgSize - I + 1;
1527
929
    ArgsVec[J] = stackPop();
1528
929
  }
1529
2.12k
  auto UnpackRets = [&](LLVM::Value Ret) -> std::vector<LLVM::Value> {
1530
2.12k
    if (RetSize == 0) {
1531
536
      return {};
1532
1.59k
    } else if (RetSize == 1) {
1533
1.55k
      return {Ret};
1534
1.55k
    } else {
1535
40
      return unpackStruct(Builder, Ret);
1536
40
    }
1537
2.12k
  };
1538
1539
1.06k
  auto Idx64 = Builder.createZExt(FuncIndex, Context.Int64Ty);
1540
1541
  // Fast path: an in-bounds funcref defined in the running module with the
1542
  // call site's type index and compiled code is called directly.
1543
1.06k
  std::vector<LLVM::Value> FastRetsVec;
1544
1.06k
  {
1545
1.06k
    Builder.createCondBr(
1546
1.06k
        Builder.createLikely(Builder.createICmpULT(
1547
1.06k
            Idx64, Context.getTableSize(Builder, ModCtx, TableIndex))),
1548
1.06k
        TryFastBB, SlowBB);
1549
1.06k
    Builder.positionAtEnd(TryFastBB);
1550
1551
1.06k
    auto FuncRef = Builder.createLoad(
1552
1.06k
        Context.Int64x2Ty,
1553
1.06k
        Builder.createInBoundsGEP1(
1554
1.06k
            Context.Int64x2Ty, Context.getTable(Builder, ModCtx, TableIndex),
1555
1.06k
            Idx64));
1556
1.06k
    auto FuncInstInt =
1557
1.06k
        Builder.createExtractElement(FuncRef, LLContext.getInt64(1));
1558
1.06k
    Builder.createCondBr(Builder.createLikely(Builder.createICmpNE(
1559
1.06k
                             FuncInstInt, LLContext.getInt64(0))),
1560
1.06k
                         NonNullBB, SlowBB);
1561
1.06k
    Builder.positionAtEnd(NonNullBB);
1562
1563
1.06k
    auto FuncInstPtr = Builder.createIntToPtr(FuncInstInt, Context.Int8PtrTy);
1564
3.18k
    auto LoadField = [&](uint64_t Off, LLVM::Type Ty) {
1565
3.18k
      return Builder.createLoad(
1566
3.18k
          Ty, Builder.createBitCast(
1567
3.18k
                  Builder.createInBoundsGEP1(Context.Int8Ty, FuncInstPtr,
1568
3.18k
                                             LLContext.getInt64(Off)),
1569
3.18k
                  Ty.getPointerTo()));
1570
3.18k
    };
1571
1.06k
    using Runtime::Instance::FunctionInstance;
1572
1.06k
    auto DefModule =
1573
1.06k
        LoadField(FunctionInstance::getModuleOffset(), Context.Int8PtrTy);
1574
1.06k
    auto CalleeTypeIdx =
1575
1.06k
        LoadField(FunctionInstance::getTypeIndexOffset(), Context.Int32Ty);
1576
1.06k
    auto Code =
1577
1.06k
        LoadField(FunctionInstance::getCompiledCodeOffset(), Context.Int8PtrTy);
1578
1.06k
    auto Hit = Builder.createAnd(
1579
1.06k
        Builder.createAnd(Builder.createICmpEQ(DefModule, Context.getModuleInst(
1580
1.06k
                                                              Builder, ModCtx)),
1581
1.06k
                          Builder.createICmpEQ(CalleeTypeIdx, TypeIdx)),
1582
1.06k
        Builder.createNot(Builder.createIsNull(Code)));
1583
1.06k
    Builder.createCondBr(Builder.createLikely(Hit), FastBB, SlowBB);
1584
1585
1.06k
    Builder.positionAtEnd(FastBB);
1586
1.06k
    auto FastRet = Builder.createCall(
1587
1.06k
        LLVM::FunctionCallee{FTy, Builder.createBitCast(Code, FPtrTy)},
1588
1.06k
        ArgsVec);
1589
1.06k
    FastRet.setNoTailCall();
1590
1.06k
    FastRetsVec = UnpackRets(FastRet);
1591
1.06k
    Builder.createBr(EndBB);
1592
1.06k
  }
1593
1594
  // Slow path: resolve through the runtime, which handles cross-module, host,
1595
  // subtype, uninitialized, and not-yet-compiled cases.
1596
1.06k
  Builder.positionAtEnd(SlowBB);
1597
1.06k
  std::vector<LLVM::Value> FPtrRetsVec;
1598
1.06k
  {
1599
1.06k
    auto FPtr = Builder.createCall(
1600
1.06k
        Context.getIntrinsic(
1601
1.06k
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1602
1.06k
            LLVM::Type::getFunctionType(FPtrTy,
1603
1.06k
                                        {Context.Int8PtrTy, Context.Int32Ty,
1604
1.06k
                                         Context.Int32Ty, Context.Int64Ty,
1605
1.06k
                                         Context.ModCtxPtrTy.getPointerTo()},
1606
1.06k
                                        false)),
1607
1.06k
        {Context.getModuleInst(Builder, ModCtx), TableIdx, TypeIdx, Idx64,
1608
1.06k
         CalleeCtxSlot});
1609
1.06k
    Builder.createCondBr(
1610
1.06k
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1611
1.06k
        NotNullBB, IsNullBB);
1612
1.06k
    Builder.positionAtEnd(NotNullBB);
1613
1614
1.06k
    auto Returned = Builder.createLoad(Context.ModCtxPtrTy, CalleeCtxSlot);
1615
1.06k
    std::vector<LLVM::Value> SlowArgsVec = ArgsVec;
1616
1.06k
    SlowArgsVec[0] = Builder.createSelect(Builder.createIsNull(Returned),
1617
1.06k
                                          F.Fn.getFirstParam(), Returned);
1618
1.06k
    auto FPtrRet =
1619
1.06k
        Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, SlowArgsVec);
1620
1.06k
    FPtrRet.setNoTailCall();
1621
1.06k
    FPtrRetsVec = UnpackRets(FPtrRet);
1622
1.06k
  }
1623
1624
1.06k
  Builder.createBr(EndBB);
1625
1.06k
  Builder.positionAtEnd(IsNullBB);
1626
1627
1.06k
  std::vector<LLVM::Value> RetsVec;
1628
1.06k
  {
1629
1.06k
    LLVM::Value Args = getTmpValues(ArgSize + RetSize);
1630
1.06k
    LLVM::Value Rets = Builder.createConstInBoundsGEP1_64(
1631
1.06k
        Context.Int8Ty, Args, ArgSize * LLVM::kValSize);
1632
1.06k
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 2, ArgSize),
1633
1.06k
                                Args, Context.Int8Ty, LLVM::kValSize);
1634
1635
1.06k
    Builder.createCall(
1636
1.06k
        Context.getIntrinsic(
1637
1.06k
            Builder, Executable::Intrinsics::kCallIndirect,
1638
1.06k
            LLVM::Type::getFunctionType(Context.VoidTy,
1639
1.06k
                                        {Context.Int8PtrTy, Context.Int32Ty,
1640
1.06k
                                         Context.Int32Ty, Context.Int64Ty,
1641
1.06k
                                         Context.Int8PtrTy, Context.Int8PtrTy},
1642
1.06k
                                        false)),
1643
1.06k
        {Context.getModuleInst(Builder, ModCtx), TableIdx, TypeIdx, Idx64, Args,
1644
1.06k
         Rets});
1645
1646
1.06k
    if (RetSize == 0) {
1647
      // nothing to do
1648
795
    } else if (RetSize == 1) {
1649
775
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1650
775
    } else {
1651
20
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1652
20
                                           LLVM::kValSize);
1653
20
    }
1654
1.06k
    endTmpValues();
1655
1.06k
    Builder.createBr(EndBB);
1656
1.06k
    Builder.positionAtEnd(EndBB);
1657
1.06k
  }
1658
1659
1.87k
  for (unsigned I = 0; I < RetSize; ++I) {
1660
815
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1661
815
    PHIRet.addIncoming(FastRetsVec[I], FastBB);
1662
815
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1663
815
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1664
815
    stackPush(PHIRet);
1665
815
  }
1666
1667
1.06k
  checkPendingException();
1668
1.06k
}
1669
1670
void FunctionCompiler::compileReturnCallOp(
1671
77
    const unsigned int FuncIndex) noexcept {
1672
77
  const auto &FuncType =
1673
77
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1674
77
          ->getFuncType();
1675
77
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1676
77
  const auto &ParamTypes = FuncType.getParamTypes();
1677
1678
77
  std::vector<LLVM::Value> Args(ParamTypes.size() + 2);
1679
77
  Args[0] = F.Fn.getFirstParam();
1680
77
  Args[1] = F.Fn.getFirstParam().getNextParam();
1681
126
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1682
49
    const size_t J = ParamTypes.size() - 1 - I;
1683
49
    Args[J + 2] = stackPop();
1684
49
  }
1685
1686
77
  const bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1687
77
  auto FTy = toLLVMType(LLContext, Context.ModCtxPtrTy, Context.ExecCtxPtrTy,
1688
77
                        FuncType);
1689
1690
  // Known limitation: musttail is only valid when the caller and callee
1691
  // prototypes match. A differing signature falls back to the tail hint, which
1692
  // LLVM may decline, so such a tail call is not guaranteed constant-space.
1693
86
  auto CreateTailRet = [&](LLVM::Value Ret) {
1694
86
    if (Ret.getInstructionCalledFunctionType().unwrap() == F.Ty.unwrap()) {
1695
58
      Ret.setMustTailCall();
1696
58
    } else {
1697
28
      Ret.setTailCall();
1698
28
    }
1699
86
    if (Ret.getType().isVoidTy()) {
1700
31
      Builder.createRetVoid();
1701
55
    } else {
1702
55
      Builder.createRet(Ret);
1703
55
    }
1704
86
  };
1705
1706
77
  if (IsImport) {
1707
9
    auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.not_null");
1708
9
    auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.is_null");
1709
9
    auto Ref = Builder.createCall(
1710
9
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc,
1711
9
                             LLVM::Type::getFunctionType(
1712
9
                                 Context.Int64x2Ty,
1713
9
                                 {Context.Int8PtrTy, Context.Int32Ty}, false)),
1714
9
        {Context.getModuleInst(Builder, ModCtx),
1715
9
         LLContext.getInt32(FuncIndex)});
1716
9
    auto FPtr = Builder.createCall(
1717
9
        Context.getIntrinsic(
1718
9
            Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1719
9
            LLVM::Type::getFunctionType(FTy.getPointerTo(),
1720
9
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
1721
9
                                         Context.ModCtxPtrTy.getPointerTo()},
1722
9
                                        false)),
1723
9
        {Context.getModuleInst(Builder, ModCtx), Ref, CalleeCtxSlot});
1724
9
    Builder.createCondBr(
1725
9
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1726
9
        NotNullBB, IsNullBB);
1727
9
    Builder.positionAtEnd(NotNullBB);
1728
1729
9
    auto Returned = Builder.createLoad(Context.ModCtxPtrTy, CalleeCtxSlot);
1730
9
    std::vector<LLVM::Value> SlowArgsVec = Args;
1731
9
    SlowArgsVec[0] = Builder.createSelect(Builder.createIsNull(Returned),
1732
9
                                          F.Fn.getFirstParam(), Returned);
1733
9
    CreateTailRet(
1734
9
        Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), SlowArgsVec));
1735
1736
9
    Builder.positionAtEnd(IsNullBB);
1737
9
  }
1738
1739
77
  LLVM::Value Ret;
1740
77
  if (IsLazyJIT) {
1741
0
    if (IsImport) {
1742
0
      Ret = Builder.createCall(Function, Args);
1743
0
    } else {
1744
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1745
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1746
0
      }
1747
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1748
0
      if (!CacheVar) {
1749
0
        CacheVar = Context.LLModule.get().addGlobal(
1750
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1751
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1752
0
      }
1753
1754
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.check");
1755
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.resolve");
1756
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.call");
1757
1758
0
      Builder.createBr(CheckBB);
1759
0
      Builder.positionAtEnd(CheckBB);
1760
1761
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1762
0
      CachedPtr.setAlignment(8);
1763
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1764
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1765
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1766
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1767
1768
0
      Builder.positionAtEnd(ResolveBB);
1769
0
      auto FPtr = Builder.createCall(
1770
0
          Context.getIntrinsic(
1771
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1772
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(),
1773
0
                                          {Context.Int8PtrTy, Context.Int32Ty},
1774
0
                                          false)),
1775
0
          {Context.getModuleInst(Builder, ModCtx),
1776
0
           LLContext.getInt32(FuncIndex)});
1777
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1778
0
      Store.setAlignment(8);
1779
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1780
0
      Builder.createBr(CallBB);
1781
1782
0
      Builder.positionAtEnd(CallBB);
1783
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1784
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1785
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1786
1787
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1788
0
    }
1789
77
  } else {
1790
77
    Ret = Builder.createCall(Function, Args);
1791
77
  }
1792
1793
77
  CreateTailRet(Ret);
1794
77
}
1795
1796
void FunctionCompiler::compileReturnIndirectCallOp(
1797
142
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1798
142
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1799
142
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1800
1801
142
  LLVM::Value FuncIndex = stackPop();
1802
142
  auto Idx64 = Builder.createZExt(FuncIndex, Context.Int64Ty);
1803
142
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1804
142
  auto FTy = toLLVMType(Context.LLContext, Context.ModCtxPtrTy,
1805
142
                        Context.ExecCtxPtrTy, FuncType);
1806
142
  auto RTy = FTy.getReturnType();
1807
1808
142
  const size_t ArgSize = FuncType.getParamTypes().size();
1809
142
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1810
142
  std::vector<LLVM::Value> ArgsVec(ArgSize + 2, nullptr);
1811
142
  ArgsVec[0] = F.Fn.getFirstParam();
1812
142
  ArgsVec[1] = F.Fn.getFirstParam().getNextParam();
1813
314
  for (size_t I = 0; I < ArgSize; ++I) {
1814
172
    const size_t J = ArgSize - I + 1;
1815
172
    ArgsVec[J] = stackPop();
1816
172
  }
1817
1818
142
  {
1819
142
    auto FPtr = Builder.createCall(
1820
142
        Context.getIntrinsic(
1821
142
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1822
142
            LLVM::Type::getFunctionType(FTy.getPointerTo(),
1823
142
                                        {Context.Int8PtrTy, Context.Int32Ty,
1824
142
                                         Context.Int32Ty, Context.Int64Ty,
1825
142
                                         Context.ModCtxPtrTy.getPointerTo()},
1826
142
                                        false)),
1827
142
        {Context.getModuleInst(Builder, ModCtx), LLContext.getInt32(TableIndex),
1828
142
         LLContext.getInt32(FuncTypeIndex), Idx64, CalleeCtxSlot});
1829
142
    Builder.createCondBr(
1830
142
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1831
142
        NotNullBB, IsNullBB);
1832
142
    Builder.positionAtEnd(NotNullBB);
1833
1834
142
    auto Returned = Builder.createLoad(Context.ModCtxPtrTy, CalleeCtxSlot);
1835
142
    std::vector<LLVM::Value> SlowArgsVec = ArgsVec;
1836
142
    SlowArgsVec[0] = Builder.createSelect(Builder.createIsNull(Returned),
1837
142
                                          F.Fn.getFirstParam(), Returned);
1838
142
    auto FPtrRet =
1839
142
        Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), SlowArgsVec);
1840
    // Known limitation: a mismatched prototype rules musttail out and the tail
1841
    // hint may be declined, so this tail call is not guaranteed constant-space.
1842
142
    if (FPtrRet.getInstructionCalledFunctionType().unwrap() == F.Ty.unwrap()) {
1843
54
      FPtrRet.setMustTailCall();
1844
88
    } else {
1845
88
      FPtrRet.setTailCall();
1846
88
    }
1847
142
    if (RetSize == 0) {
1848
44
      Builder.createRetVoid();
1849
98
    } else {
1850
98
      Builder.createRet(FPtrRet);
1851
98
    }
1852
142
  }
1853
1854
142
  Builder.positionAtEnd(IsNullBB);
1855
1856
142
  {
1857
142
    LLVM::Value Args = getTmpValues(ArgSize + RetSize);
1858
142
    LLVM::Value Rets = Builder.createConstInBoundsGEP1_64(
1859
142
        Context.Int8Ty, Args, ArgSize * LLVM::kValSize);
1860
142
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 2, ArgSize),
1861
142
                                Args, Context.Int8Ty, LLVM::kValSize);
1862
1863
142
    Builder.createCall(
1864
142
        Context.getIntrinsic(
1865
142
            Builder, Executable::Intrinsics::kCallIndirect,
1866
142
            LLVM::Type::getFunctionType(Context.VoidTy,
1867
142
                                        {Context.Int8PtrTy, Context.Int32Ty,
1868
142
                                         Context.Int32Ty, Context.Int64Ty,
1869
142
                                         Context.Int8PtrTy, Context.Int8PtrTy},
1870
142
                                        false)),
1871
142
        {Context.getModuleInst(Builder, ModCtx), LLContext.getInt32(TableIndex),
1872
142
         LLContext.getInt32(FuncTypeIndex), Idx64, Args, Rets});
1873
1874
142
    if (RetSize == 0) {
1875
44
      endTmpValues();
1876
44
      Builder.createRetVoid();
1877
98
    } else if (RetSize == 1) {
1878
86
      auto Ret = Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty);
1879
86
      endTmpValues();
1880
86
      Builder.createRet(Ret);
1881
86
    } else {
1882
12
      auto Ret = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1883
12
                                            LLVM::kValSize);
1884
12
      endTmpValues();
1885
12
      Builder.createAggregateRet(Ret);
1886
12
    }
1887
142
  }
1888
142
}
1889
1890
207
void FunctionCompiler::compileCallRefOp(const unsigned int TypeIndex) noexcept {
1891
207
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1892
207
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
1893
207
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1894
1895
207
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1896
207
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
1897
207
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1898
207
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1899
207
      LLContext.getInt64(0)));
1900
207
  Builder.createCondBr(IsRefNotNull, OkBB,
1901
207
                       getTrapBB(ErrCode::Value::AccessNullFunc));
1902
207
  Builder.positionAtEnd(OkBB);
1903
1904
207
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
1905
207
  auto FTy = toLLVMType(Context.LLContext, Context.ModCtxPtrTy,
1906
207
                        Context.ExecCtxPtrTy, FuncType);
1907
207
  auto RTy = FTy.getReturnType();
1908
1909
207
  const size_t ArgSize = FuncType.getParamTypes().size();
1910
207
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1911
207
  std::vector<LLVM::Value> ArgsVec(ArgSize + 2, nullptr);
1912
207
  ArgsVec[0] = F.Fn.getFirstParam();
1913
207
  ArgsVec[1] = F.Fn.getFirstParam().getNextParam();
1914
405
  for (size_t I = 0; I < ArgSize; ++I) {
1915
198
    const size_t J = ArgSize - I + 1;
1916
198
    ArgsVec[J] = stackPop();
1917
198
  }
1918
1919
207
  std::vector<LLVM::Value> FPtrRetsVec;
1920
207
  FPtrRetsVec.reserve(RetSize);
1921
207
  {
1922
207
    auto FPtr = Builder.createCall(
1923
207
        Context.getIntrinsic(
1924
207
            Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1925
207
            LLVM::Type::getFunctionType(FTy.getPointerTo(),
1926
207
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
1927
207
                                         Context.ModCtxPtrTy.getPointerTo()},
1928
207
                                        false)),
1929
207
        {Context.getModuleInst(Builder, ModCtx), Ref, CalleeCtxSlot});
1930
207
    Builder.createCondBr(
1931
207
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1932
207
        NotNullBB, IsNullBB);
1933
207
    Builder.positionAtEnd(NotNullBB);
1934
1935
207
    auto Returned = Builder.createLoad(Context.ModCtxPtrTy, CalleeCtxSlot);
1936
207
    std::vector<LLVM::Value> SlowArgsVec = ArgsVec;
1937
207
    SlowArgsVec[0] = Builder.createSelect(Builder.createIsNull(Returned),
1938
207
                                          F.Fn.getFirstParam(), Returned);
1939
207
    auto FPtrRet =
1940
207
        Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, SlowArgsVec);
1941
207
    FPtrRet.setNoTailCall();
1942
207
    if (RetSize == 0) {
1943
      // nothing to do
1944
108
    } else if (RetSize == 1) {
1945
88
      FPtrRetsVec.push_back(FPtrRet);
1946
88
    } else {
1947
22
      for (auto Val : unpackStruct(Builder, FPtrRet)) {
1948
22
        FPtrRetsVec.push_back(Val);
1949
22
      }
1950
11
    }
1951
207
  }
1952
1953
207
  Builder.createBr(EndBB);
1954
207
  Builder.positionAtEnd(IsNullBB);
1955
1956
207
  std::vector<LLVM::Value> RetsVec;
1957
207
  {
1958
207
    LLVM::Value Args = getTmpValues(ArgSize + RetSize);
1959
207
    LLVM::Value Rets = Builder.createConstInBoundsGEP1_64(
1960
207
        Context.Int8Ty, Args, ArgSize * LLVM::kValSize);
1961
207
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 2, ArgSize),
1962
207
                                Args, Context.Int8Ty, LLVM::kValSize);
1963
1964
207
    Builder.createCall(
1965
207
        Context.getIntrinsic(
1966
207
            Builder, Executable::Intrinsics::kCallRef,
1967
207
            LLVM::Type::getFunctionType(Context.VoidTy,
1968
207
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
1969
207
                                         Context.Int8PtrTy, Context.Int8PtrTy},
1970
207
                                        false)),
1971
207
        {Context.getModuleInst(Builder, ModCtx), Ref, Args, Rets});
1972
1973
207
    if (RetSize == 0) {
1974
      // nothing to do
1975
108
    } else if (RetSize == 1) {
1976
88
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1977
88
    } else {
1978
11
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1979
11
                                           LLVM::kValSize);
1980
11
    }
1981
207
    endTmpValues();
1982
207
    Builder.createBr(EndBB);
1983
207
    Builder.positionAtEnd(EndBB);
1984
207
  }
1985
1986
317
  for (unsigned I = 0; I < RetSize; ++I) {
1987
110
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1988
110
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1989
110
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1990
110
    stackPush(PHIRet);
1991
110
  }
1992
1993
207
  checkPendingException();
1994
207
}
1995
1996
void FunctionCompiler::compileReturnCallRefOp(
1997
58
    const unsigned int TypeIndex) noexcept {
1998
58
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1999
58
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
2000
2001
58
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
2002
58
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
2003
58
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
2004
58
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
2005
58
      LLContext.getInt64(0)));
2006
58
  Builder.createCondBr(IsRefNotNull, OkBB,
2007
58
                       getTrapBB(ErrCode::Value::AccessNullFunc));
2008
58
  Builder.positionAtEnd(OkBB);
2009
2010
58
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
2011
58
  auto FTy = toLLVMType(Context.LLContext, Context.ModCtxPtrTy,
2012
58
                        Context.ExecCtxPtrTy, FuncType);
2013
58
  auto RTy = FTy.getReturnType();
2014
2015
58
  const size_t ArgSize = FuncType.getParamTypes().size();
2016
58
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
2017
58
  std::vector<LLVM::Value> ArgsVec(ArgSize + 2, nullptr);
2018
58
  ArgsVec[0] = F.Fn.getFirstParam();
2019
58
  ArgsVec[1] = F.Fn.getFirstParam().getNextParam();
2020
92
  for (size_t I = 0; I < ArgSize; ++I) {
2021
34
    const size_t J = ArgSize - I + 1;
2022
34
    ArgsVec[J] = stackPop();
2023
34
  }
2024
2025
58
  {
2026
58
    auto FPtr = Builder.createCall(
2027
58
        Context.getIntrinsic(
2028
58
            Builder, Executable::Intrinsics::kRefGetFuncSymbol,
2029
58
            LLVM::Type::getFunctionType(FTy.getPointerTo(),
2030
58
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
2031
58
                                         Context.ModCtxPtrTy.getPointerTo()},
2032
58
                                        false)),
2033
58
        {Context.getModuleInst(Builder, ModCtx), Ref, CalleeCtxSlot});
2034
58
    Builder.createCondBr(
2035
58
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
2036
58
        NotNullBB, IsNullBB);
2037
58
    Builder.positionAtEnd(NotNullBB);
2038
2039
58
    auto Returned = Builder.createLoad(Context.ModCtxPtrTy, CalleeCtxSlot);
2040
58
    std::vector<LLVM::Value> SlowArgsVec = ArgsVec;
2041
58
    SlowArgsVec[0] = Builder.createSelect(Builder.createIsNull(Returned),
2042
58
                                          F.Fn.getFirstParam(), Returned);
2043
58
    auto FPtrRet =
2044
58
        Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), SlowArgsVec);
2045
    // Known limitation: a mismatched prototype rules musttail out and the tail
2046
    // hint may be declined, so this tail call is not guaranteed constant-space.
2047
58
    if (FPtrRet.getInstructionCalledFunctionType().unwrap() == F.Ty.unwrap()) {
2048
57
      FPtrRet.setMustTailCall();
2049
57
    } else {
2050
1
      FPtrRet.setTailCall();
2051
1
    }
2052
58
    if (RetSize == 0) {
2053
27
      Builder.createRetVoid();
2054
31
    } else {
2055
31
      Builder.createRet(FPtrRet);
2056
31
    }
2057
58
  }
2058
2059
58
  Builder.positionAtEnd(IsNullBB);
2060
2061
58
  {
2062
58
    LLVM::Value Args = getTmpValues(ArgSize + RetSize);
2063
58
    LLVM::Value Rets = Builder.createConstInBoundsGEP1_64(
2064
58
        Context.Int8Ty, Args, ArgSize * LLVM::kValSize);
2065
58
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 2, ArgSize),
2066
58
                                Args, Context.Int8Ty, LLVM::kValSize);
2067
2068
58
    Builder.createCall(
2069
58
        Context.getIntrinsic(
2070
58
            Builder, Executable::Intrinsics::kCallRef,
2071
58
            LLVM::Type::getFunctionType(Context.VoidTy,
2072
58
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
2073
58
                                         Context.Int8PtrTy, Context.Int8PtrTy},
2074
58
                                        false)),
2075
58
        {Context.getModuleInst(Builder, ModCtx), Ref, Args, Rets});
2076
2077
58
    if (RetSize == 0) {
2078
27
      endTmpValues();
2079
27
      Builder.createRetVoid();
2080
31
    } else if (RetSize == 1) {
2081
29
      auto Ret = Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty);
2082
29
      endTmpValues();
2083
29
      Builder.createRet(Ret);
2084
29
    } else {
2085
2
      auto Ret = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
2086
2
                                            LLVM::kValSize);
2087
2
      endTmpValues();
2088
2
      Builder.createAggregateRet(Ret);
2089
2
    }
2090
58
  }
2091
58
}
2092
2093
void FunctionCompiler::enterBlock(
2094
    LLVM::BasicBlock JumpBlock, LLVM::BasicBlock NextBlock,
2095
    LLVM::BasicBlock ElseBlock, std::vector<LLVM::Value> Args,
2096
    std::pair<std::vector<ValType>, std::vector<ValType>> Type,
2097
    std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
2098
22.7k
        ReturnPHI) noexcept {
2099
22.7k
  assuming(Type.first.size() == Args.size());
2100
22.7k
  for (auto &Value : Args) {
2101
4.73k
    stackPush(Value);
2102
4.73k
  }
2103
22.7k
  const auto Unreachable = isUnreachable();
2104
22.7k
  ControlStack.emplace_back(Stack.size() - Args.size(), Unreachable, JumpBlock,
2105
22.7k
                            NextBlock, ElseBlock, std::move(Args),
2106
22.7k
                            std::move(Type), std::move(ReturnPHI));
2107
22.7k
}
2108
2109
22.7k
FunctionCompiler::Control FunctionCompiler::leaveBlock() noexcept {
2110
22.7k
  Control Entry = std::move(ControlStack.back());
2111
22.7k
  ControlStack.pop_back();
2112
2113
22.7k
  auto NextBlock = Entry.NextBlock ? Entry.NextBlock : Entry.JumpBlock;
2114
22.7k
  if (!Entry.Unreachable) {
2115
13.0k
    const auto &ReturnType = Entry.Type.second;
2116
13.0k
    if (!ReturnType.empty()) {
2117
9.56k
      std::vector<LLVM::Value> Rets(ReturnType.size());
2118
19.5k
      for (size_t I = 0; I < Rets.size(); ++I) {
2119
10.0k
        const size_t J = Rets.size() - 1 - I;
2120
10.0k
        Rets[J] = stackPop();
2121
10.0k
      }
2122
9.56k
      Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
2123
9.56k
    }
2124
13.0k
    Builder.createBr(NextBlock);
2125
13.0k
  } else {
2126
9.69k
    Builder.createUnreachable();
2127
9.69k
  }
2128
22.7k
  Builder.positionAtEnd(NextBlock);
2129
22.7k
  Stack.erase(Stack.begin() + static_cast<int64_t>(Entry.StackSize),
2130
22.7k
              Stack.end());
2131
22.7k
  return Entry;
2132
22.7k
}
2133
2134
6.05k
void FunctionCompiler::checkStop() noexcept {
2135
6.05k
  if (!Interruptible) {
2136
6.05k
    return;
2137
6.05k
  }
2138
0
  auto NotStopBB = LLVM::BasicBlock::create(LLContext, F.Fn, "NotStop");
2139
0
  auto StopToken = Builder.createAtomicRMW(
2140
0
      LLVMAtomicRMWBinOpXchg, Context.getStopToken(Builder, ExecCtx),
2141
0
      LLContext.getInt32(0), LLVMAtomicOrderingMonotonic);
2142
0
#if LLVM_VERSION_MAJOR < 13
2143
#else
2144
  StopToken.setAlignment(32);
2145
#endif
2146
0
  auto NotStop = Builder.createLikely(
2147
0
      Builder.createICmpEQ(StopToken, LLContext.getInt32(0)));
2148
0
  Builder.createCondBr(NotStop, NotStopBB,
2149
0
                       getTrapBB(ErrCode::Value::Interrupted));
2150
2151
0
  Builder.positionAtEnd(NotStopBB);
2152
0
}
2153
2154
4.31k
void FunctionCompiler::checkPendingException() noexcept {
2155
4.31k
  auto PendingTagInst = Builder.createLoad(
2156
4.31k
      Context.Int8PtrTy, Context.getPendingExnTagAddr(Builder, ExecCtx));
2157
4.31k
  auto NotPendingBB =
2158
4.31k
      LLVM::BasicBlock::create(LLContext, F.Fn, "no_pending_exn");
2159
4.31k
  auto NotPending = Builder.createLikely(Builder.createIsNull(PendingTagInst));
2160
4.31k
  Builder.createCondBr(NotPending, NotPendingBB, getEHDispatchTarget());
2161
4.31k
  Builder.positionAtEnd(NotPendingBB);
2162
4.31k
}
2163
2164
6.44k
void FunctionCompiler::setUnreachable() noexcept {
2165
6.44k
  if (ControlStack.empty()) {
2166
0
    IsUnreachable = true;
2167
6.44k
  } else {
2168
6.44k
    ControlStack.back().Unreachable = true;
2169
6.44k
  }
2170
6.44k
}
2171
2172
1.51M
bool FunctionCompiler::isUnreachable() const noexcept {
2173
1.51M
  if (ControlStack.empty()) {
2174
10.6k
    return IsUnreachable;
2175
1.50M
  } else {
2176
1.50M
    return ControlStack.back().Unreachable;
2177
1.50M
  }
2178
1.51M
}
2179
2180
void FunctionCompiler::buildPHI(
2181
    Span<const ValType> RetType,
2182
    Span<const std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
2183
19.7k
        Incomings) noexcept {
2184
19.7k
  if (LLVM::isVoidReturn(RetType)) {
2185
6.86k
    return;
2186
6.86k
  }
2187
12.8k
  std::vector<LLVM::Value> Nodes;
2188
12.8k
  if (Incomings.size() == 0) {
2189
3.19k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
2190
3.19k
    Nodes.reserve(Types.size());
2191
3.81k
    for (LLVM::Type Type : Types) {
2192
3.81k
      Nodes.push_back(LLVM::Value::getUndef(Type));
2193
3.81k
    }
2194
9.63k
  } else if (Incomings.size() == 1) {
2195
8.52k
    Nodes = std::move(std::get<0>(Incomings.front()));
2196
8.52k
  } else {
2197
1.10k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
2198
1.10k
    Nodes.reserve(Types.size());
2199
2.30k
    for (size_t I = 0; I < Types.size(); ++I) {
2200
1.20k
      auto PHIRet = Builder.createPHI(Types[I]);
2201
2.93k
      for (auto &[Value, BB] : Incomings) {
2202
2.93k
        assuming(Value.size() == Types.size());
2203
2.93k
        PHIRet.addIncoming(Value[I], BB);
2204
2.93k
      }
2205
1.20k
      Nodes.push_back(PHIRet);
2206
1.20k
    }
2207
1.10k
  }
2208
13.9k
  for (auto &Val : Nodes) {
2209
13.9k
    stackPush(Val);
2210
13.9k
  }
2211
12.8k
}
2212
2213
37.6k
void FunctionCompiler::setLableJumpPHI(unsigned int Index) noexcept {
2214
37.6k
  assuming(Index < ControlStack.size());
2215
37.6k
  auto &Entry = *(ControlStack.rbegin() + Index);
2216
37.6k
  if (Entry.NextBlock) { // is loop
2217
2.37k
    std::vector<LLVM::Value> Args(Entry.Type.first.size());
2218
5.37k
    for (size_t I = 0; I < Args.size(); ++I) {
2219
2.99k
      const size_t J = Args.size() - 1 - I;
2220
2.99k
      Args[J] = stackPop();
2221
2.99k
    }
2222
5.37k
    for (size_t I = 0; I < Args.size(); ++I) {
2223
2.99k
      Entry.Args[I].addIncoming(Args[I], Builder.getInsertBlock());
2224
2.99k
      stackPush(Args[I]);
2225
2.99k
    }
2226
35.2k
  } else if (!Entry.Type.second.empty()) { // has return value
2227
1.70k
    std::vector<LLVM::Value> Rets(Entry.Type.second.size());
2228
3.54k
    for (size_t I = 0; I < Rets.size(); ++I) {
2229
1.83k
      const size_t J = Rets.size() - 1 - I;
2230
1.83k
      Rets[J] = stackPop();
2231
1.83k
    }
2232
3.54k
    for (size_t I = 0; I < Rets.size(); ++I) {
2233
1.83k
      stackPush(Rets[I]);
2234
1.83k
    }
2235
1.70k
    Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
2236
1.70k
  }
2237
37.6k
}
2238
2239
37.6k
LLVM::BasicBlock FunctionCompiler::getLabel(unsigned int Index) const noexcept {
2240
37.6k
  return (ControlStack.rbegin() + Index)->JumpBlock;
2241
37.6k
}
2242
2243
4.31k
LLVM::BasicBlock FunctionCompiler::getEHDispatchTarget() noexcept {
2244
10.8k
  for (auto It = ControlStack.rbegin(); It != ControlStack.rend(); ++It) {
2245
6.52k
    if (It->TryDispatchBB) {
2246
1
      return It->TryDispatchBB;
2247
1
    }
2248
6.52k
  }
2249
4.31k
  if (!UnwindBB) {
2250
1.98k
    UnwindBB = LLVM::BasicBlock::create(LLContext, F.Fn, "exn.unwind");
2251
1.98k
  }
2252
4.31k
  return UnwindBB;
2253
4.31k
}
2254
2255
329k
LLVM::Value FunctionCompiler::stackPop() noexcept {
2256
329k
  assuming(!ControlStack.empty() || !Stack.empty());
2257
329k
  assuming(ControlStack.empty() ||
2258
329k
           Stack.size() > ControlStack.back().StackSize);
2259
329k
  auto Value = Stack.back();
2260
329k
  Stack.pop_back();
2261
329k
  return Value;
2262
329k
}
2263
2264
19.3k
LLVM::Value FunctionCompiler::switchEndian(LLVM::Value Value) {
2265
  if constexpr (Endian::native == Endian::big) {
2266
    auto Type = Value.getType();
2267
    if ((Type.isIntegerTy() && Type.getIntegerBitWidth() > 8) ||
2268
        (Type.isVectorTy() && Type.getVectorSize() == 1)) {
2269
      return Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2270
    }
2271
    if (Type.isVectorTy()) {
2272
      // Bswap operates on the total vector width, not the lane width.
2273
      Value = Builder.createBitCast(
2274
          Value, LLContext.getIntNTy(Type.getPrimitiveSizeInBits()));
2275
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2276
      return Builder.createBitCast(Value, Type);
2277
    }
2278
    if (Type.isFloatTy() || Type.isDoubleTy()) {
2279
      LLVM::Type IntType = Type.isFloatTy() ? Context.Int32Ty : Context.Int64Ty;
2280
      Value = Builder.createBitCast(Value, IntType);
2281
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2282
      return Builder.createBitCast(Value, Type);
2283
    }
2284
  }
2285
19.3k
  return Value;
2286
19.3k
}
2287
2288
} // namespace WasmEdge