Coverage Report

Created: 2026-08-08 06:32

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) noexcept
21
10.3k
    : Context(Context), LLContext(Context.LLContext),
22
10.3k
      Interruptible(Interruptible), IsLazyJIT(IsLazyJIT), F(F),
23
10.3k
      Builder(LLContext) {
24
10.3k
  if (F.Fn) {
25
10.3k
    Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "entry"));
26
10.3k
    ExecCtx = Builder.createLoad(Context.ExecCtxTy, F.Fn.getFirstParam());
27
28
10.3k
    if (InstructionCounting) {
29
0
      LocalInstrCount = Builder.createAlloca(Context.Int64Ty);
30
0
      Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
31
0
    }
32
33
10.3k
    if (GasMeasuring) {
34
0
      LocalGas = Builder.createAlloca(Context.Int64Ty);
35
0
      Builder.createStore(LLContext.getInt64(0), LocalGas);
36
0
    }
37
38
19.7k
    for (LLVM::Value Arg = F.Fn.getFirstParam().getNextParam(); Arg;
39
10.3k
         Arg = Arg.getNextParam()) {
40
9.36k
      LLVM::Type Ty = Arg.getType();
41
9.36k
      LLVM::Value ArgPtr = Builder.createAlloca(Ty);
42
9.36k
      Builder.createStore(Arg, ArgPtr);
43
9.36k
      Local.emplace_back(Ty, ArgPtr);
44
9.36k
    }
45
46
469k
    for (const auto &Type : Locals) {
47
469k
      LLVM::Type Ty = toLLVMType(LLContext, Type);
48
469k
      LLVM::Value ArgPtr = Builder.createAlloca(Ty);
49
469k
      Builder.createStore(
50
469k
          toLLVMConstantZero(LLContext, Type, Context.CompositeTypes), ArgPtr);
51
469k
      Local.emplace_back(Ty, ArgPtr);
52
469k
    }
53
10.3k
  }
54
10.3k
}
55
56
34.3k
LLVM::BasicBlock FunctionCompiler::getTrapBB(ErrCode::Value Error) noexcept {
57
34.3k
  if (auto Iter = TrapBB.find(Error); Iter != TrapBB.end()) {
58
31.1k
    return Iter->second;
59
31.1k
  }
60
3.29k
  auto BB = LLVM::BasicBlock::create(LLContext, F.Fn, "trap");
61
3.29k
  TrapBB.emplace(Error, BB);
62
3.29k
  return BB;
63
34.3k
}
64
65
Expect<void> FunctionCompiler::compile(
66
    const AST::CodeSegment &Code,
67
10.3k
    std::pair<std::vector<ValType>, std::vector<ValType>> Type) noexcept {
68
10.3k
  auto RetBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ret");
69
10.3k
  Type.first.clear();
70
10.3k
  enterBlock(RetBB, {}, {}, {}, std::move(Type));
71
10.3k
  EXPECTED_TRY(compile(Code.getExpr().getInstrs()));
72
10.3k
  assuming(ControlStack.empty());
73
10.3k
  compileReturn();
74
75
10.3k
  for (auto &[Error, BB] : TrapBB) {
76
3.29k
    Builder.positionAtEnd(BB);
77
3.29k
    updateInstrCount();
78
3.29k
    updateGasAtTrap();
79
3.29k
    auto CallTrap = Builder.createCall(
80
3.29k
        Context.Trap, {LLContext.getInt32(static_cast<uint32_t>(Error))});
81
3.29k
    CallTrap.addCallSiteAttribute(Context.NoReturn);
82
3.29k
    Builder.createUnreachable();
83
3.29k
  }
84
85
10.3k
  if (UnwindBB) {
86
    // Escape path for uncaught exceptions: return with the pending state
87
    // set; the caller never reads the results.
88
1.78k
    Builder.positionAtEnd(UnwindBB);
89
1.78k
    updateInstrCount();
90
1.78k
    updateGasAtTrap();
91
1.78k
    auto Ty = F.Ty.getReturnType();
92
1.78k
    if (Ty.isVoidTy()) {
93
438
      Builder.createRetVoid();
94
1.34k
    } else {
95
1.34k
      Builder.createRet(LLVM::Value::getUndef(Ty));
96
1.34k
    }
97
1.78k
  }
98
10.3k
  return {};
99
10.3k
}
100
101
10.3k
Expect<void> FunctionCompiler::compile(AST::InstrView Instrs) noexcept {
102
1.56M
  auto Dispatch = [this](const AST::Instruction &Instr) -> Expect<void> {
103
1.56M
    switch (Instr.getOpCode()) {
104
    // Control instructions (for blocks)
105
3.35k
    case OpCode::Block: {
106
3.35k
      auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "block");
107
3.35k
      auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "block.end");
108
3.35k
      Builder.createBr(Block);
109
110
3.35k
      Builder.positionAtEnd(Block);
111
3.35k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
112
3.35k
      const auto Arity = Type.first.size();
113
3.35k
      std::vector<LLVM::Value> Args(Arity);
114
3.35k
      if (isUnreachable()) {
115
1.03k
        for (size_t I = 0; I < Arity; ++I) {
116
272
          auto Ty = toLLVMType(LLContext, Type.first[I]);
117
272
          Args[I] = LLVM::Value::getUndef(Ty);
118
272
        }
119
2.59k
      } else {
120
2.96k
        for (size_t I = 0; I < Arity; ++I) {
121
371
          const size_t J = Arity - 1 - I;
122
371
          Args[J] = stackPop();
123
371
        }
124
2.59k
      }
125
3.35k
      enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
126
3.35k
      checkStop();
127
3.35k
      updateGas();
128
3.35k
      return {};
129
0
    }
130
1.98k
    case OpCode::Loop: {
131
1.98k
      auto Curr = Builder.getInsertBlock();
132
1.98k
      auto Loop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop");
133
1.98k
      auto EndLoop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop.end");
134
1.98k
      Builder.createBr(Loop);
135
136
1.98k
      Builder.positionAtEnd(Loop);
137
1.98k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
138
1.98k
      const auto Arity = Type.first.size();
139
1.98k
      std::vector<LLVM::Value> Args(Arity);
140
1.98k
      if (isUnreachable()) {
141
1.02k
        for (size_t I = 0; I < Arity; ++I) {
142
399
          auto Ty = toLLVMType(LLContext, Type.first[I]);
143
399
          auto Value = LLVM::Value::getUndef(Ty);
144
399
          auto PHINode = Builder.createPHI(Ty);
145
399
          PHINode.addIncoming(Value, Curr);
146
399
          Args[I] = PHINode;
147
399
        }
148
1.35k
      } else {
149
2.05k
        for (size_t I = 0; I < Arity; ++I) {
150
705
          const size_t J = Arity - 1 - I;
151
705
          auto Value = stackPop();
152
705
          auto PHINode = Builder.createPHI(Value.getType());
153
705
          PHINode.addIncoming(Value, Curr);
154
705
          Args[J] = PHINode;
155
705
        }
156
1.35k
      }
157
1.98k
      enterBlock(Loop, EndLoop, {}, std::move(Args), std::move(Type));
158
1.98k
      checkStop();
159
1.98k
      updateGas();
160
1.98k
      return {};
161
0
    }
162
2.88k
    case OpCode::If: {
163
2.88k
      auto Then = LLVM::BasicBlock::create(LLContext, F.Fn, "then");
164
2.88k
      auto Else = LLVM::BasicBlock::create(LLContext, F.Fn, "else");
165
2.88k
      auto EndIf = LLVM::BasicBlock::create(LLContext, F.Fn, "if.end");
166
2.88k
      LLVM::Value Cond;
167
2.88k
      if (isUnreachable()) {
168
702
        Cond = LLVM::Value::getUndef(LLContext.getInt1Ty());
169
2.18k
      } else {
170
2.18k
        Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
171
2.18k
      }
172
2.88k
      Builder.createCondBr(Cond, Then, Else);
173
174
2.88k
      Builder.positionAtEnd(Then);
175
2.88k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
176
2.88k
      const auto Arity = Type.first.size();
177
2.88k
      std::vector<LLVM::Value> Args(Arity);
178
2.88k
      if (isUnreachable()) {
179
1.19k
        for (size_t I = 0; I < Arity; ++I) {
180
488
          auto Ty = toLLVMType(LLContext, Type.first[I]);
181
488
          Args[I] = LLVM::Value::getUndef(Ty);
182
488
        }
183
2.18k
      } else {
184
3.03k
        for (size_t I = 0; I < Arity; ++I) {
185
855
          const size_t J = Arity - 1 - I;
186
855
          Args[J] = stackPop();
187
855
        }
188
2.18k
      }
189
2.88k
      enterBlock(EndIf, {}, Else, std::move(Args), std::move(Type));
190
2.88k
      return {};
191
0
    }
192
166
    case OpCode::Try_table:
193
166
      compileTryTableOp(Instr);
194
166
      return {};
195
18.7k
    case OpCode::End: {
196
18.7k
      auto Entry = leaveBlock();
197
18.7k
      if (Entry.ElseBlock) {
198
1.33k
        auto Block = Builder.getInsertBlock();
199
1.33k
        Builder.positionAtEnd(Entry.ElseBlock);
200
1.33k
        enterBlock(Block, {}, {}, std::move(Entry.Args), std::move(Entry.Type),
201
1.33k
                   std::move(Entry.ReturnPHI));
202
1.33k
        Entry = leaveBlock();
203
1.33k
      }
204
18.7k
      buildPHI(Entry.Type.second, Entry.ReturnPHI);
205
18.7k
      return {};
206
0
    }
207
1.55k
    case OpCode::Else: {
208
1.55k
      auto Entry = leaveBlock();
209
1.55k
      Builder.positionAtEnd(Entry.ElseBlock);
210
1.55k
      enterBlock(Entry.JumpBlock, {}, {}, std::move(Entry.Args),
211
1.55k
                 std::move(Entry.Type), std::move(Entry.ReturnPHI));
212
1.55k
      return {};
213
0
    }
214
1.53M
    default:
215
1.53M
      break;
216
1.56M
    }
217
218
1.53M
    if (isUnreachable()) {
219
510k
      return {};
220
510k
    }
221
222
1.02M
    switch (Instr.getOpCode()) {
223
    // Control instructions
224
3.50k
    case OpCode::Unreachable:
225
3.50k
      Builder.createBr(getTrapBB(ErrCode::Value::Unreachable));
226
3.50k
      setUnreachable();
227
3.50k
      Builder.positionAtEnd(
228
3.50k
          LLVM::BasicBlock::create(LLContext, F.Fn, "unreachable.end"));
229
3.50k
      break;
230
45.1k
    case OpCode::Nop:
231
45.1k
      break;
232
2
    case OpCode::Throw:
233
2
      updateInstrCount();
234
2
      updateGas();
235
2
      compileThrowOp(Instr.getTargetIndex());
236
2
      break;
237
3
    case OpCode::Throw_ref:
238
3
      updateInstrCount();
239
3
      updateGas();
240
3
      compileThrowRefOp();
241
3
      break;
242
689
    case OpCode::Br: {
243
689
      const auto Label = Instr.getJump().TargetIndex;
244
689
      setLableJumpPHI(Label);
245
689
      Builder.createBr(getLabel(Label));
246
689
      setUnreachable();
247
689
      Builder.positionAtEnd(
248
689
          LLVM::BasicBlock::create(LLContext, F.Fn, "br.end"));
249
689
      break;
250
0
    }
251
346
    case OpCode::Br_if: {
252
346
      const auto Label = Instr.getJump().TargetIndex;
253
346
      auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
254
346
      setLableJumpPHI(Label);
255
346
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_if.end");
256
346
      Builder.createCondBr(Cond, getLabel(Label), Next);
257
346
      Builder.positionAtEnd(Next);
258
346
      break;
259
0
    }
260
934
    case OpCode::Br_table: {
261
934
      auto LabelTable = Instr.getLabelList();
262
934
      assuming(LabelTable.size() <= std::numeric_limits<uint32_t>::max());
263
934
      const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
264
934
      auto Value = stackPop();
265
934
      setLableJumpPHI(LabelTable[LabelTableSize].TargetIndex);
266
934
      auto Switch = Builder.createSwitch(
267
934
          Value, getLabel(LabelTable[LabelTableSize].TargetIndex),
268
934
          LabelTableSize);
269
20.2k
      for (uint32_t I = 0; I < LabelTableSize; ++I) {
270
19.3k
        setLableJumpPHI(LabelTable[I].TargetIndex);
271
19.3k
        Switch.addCase(LLContext.getInt32(I),
272
19.3k
                       getLabel(LabelTable[I].TargetIndex));
273
19.3k
      }
274
934
      setUnreachable();
275
934
      Builder.positionAtEnd(
276
934
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_table.end"));
277
934
      break;
278
934
    }
279
28
    case OpCode::Br_on_null: {
280
28
      const auto Label = Instr.getJump().TargetIndex;
281
28
      auto Value = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
282
28
      auto Cond = Builder.createICmpEQ(
283
28
          Builder.createExtractElement(Value, LLContext.getInt64(1)),
284
28
          LLContext.getInt64(0));
285
28
      setLableJumpPHI(Label);
286
28
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_null.end");
287
28
      Builder.createCondBr(Cond, getLabel(Label), Next);
288
28
      Builder.positionAtEnd(Next);
289
28
      stackPush(Value);
290
28
      break;
291
934
    }
292
10
    case OpCode::Br_on_non_null: {
293
10
      const auto Label = Instr.getJump().TargetIndex;
294
10
      auto Cond = Builder.createICmpNE(
295
10
          Builder.createExtractElement(
296
10
              Builder.createBitCast(Stack.back(), Context.Int64x2Ty),
297
10
              LLContext.getInt64(1)),
298
10
          LLContext.getInt64(0));
299
10
      setLableJumpPHI(Label);
300
10
      auto Next =
301
10
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_non_null.end");
302
10
      Builder.createCondBr(Cond, getLabel(Label), Next);
303
10
      Builder.positionAtEnd(Next);
304
10
      stackPop();
305
10
      break;
306
934
    }
307
0
    case OpCode::Br_on_cast:
308
0
    case OpCode::Br_on_cast_fail: {
309
0
      auto Ref = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
310
0
      const auto Label = Instr.getBrCast().Jump.TargetIndex;
311
0
      std::array<uint8_t, 16> Buf = {0};
312
0
      std::copy_n(Instr.getBrCast().RType2.getRawData().cbegin(), 8,
313
0
                  Buf.begin());
314
0
      auto VType = Builder.createExtractElement(
315
0
          Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
316
0
                                Context.Int64x2Ty),
317
0
          LLContext.getInt64(0));
318
0
      auto IsRefTest = Builder.createCall(
319
0
          Context.getIntrinsic(
320
0
              Builder, Executable::Intrinsics::kRefTest,
321
0
              LLVM::Type::getFunctionType(Context.Int32Ty,
322
0
                                          {Context.Int64x2Ty, Context.Int64Ty},
323
0
                                          false)),
324
0
          {Ref, VType});
325
0
      auto Cond = (Instr.getOpCode() == OpCode::Br_on_cast)
326
0
                      ? Builder.createICmpNE(IsRefTest, LLContext.getInt32(0))
327
0
                      : Builder.createICmpEQ(IsRefTest, LLContext.getInt32(0));
328
0
      setLableJumpPHI(Label);
329
0
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_cast.end");
330
0
      Builder.createCondBr(Cond, getLabel(Label), Next);
331
0
      Builder.positionAtEnd(Next);
332
0
      break;
333
0
    }
334
686
    case OpCode::Return:
335
686
      compileReturn();
336
686
      setUnreachable();
337
686
      Builder.positionAtEnd(
338
686
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret.end"));
339
686
      break;
340
3.02k
    case OpCode::Call:
341
3.02k
      updateInstrCount();
342
3.02k
      updateGas();
343
3.02k
      compileCallOp(Instr.getTargetIndex());
344
3.02k
      break;
345
858
    case OpCode::Call_indirect:
346
858
      updateInstrCount();
347
858
      updateGas();
348
858
      compileIndirectCallOp(Instr.getSourceIndex(), Instr.getTargetIndex());
349
858
      break;
350
65
    case OpCode::Return_call:
351
65
      updateInstrCount();
352
65
      updateGas();
353
65
      compileReturnCallOp(Instr.getTargetIndex());
354
65
      setUnreachable();
355
65
      Builder.positionAtEnd(
356
65
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call.end"));
357
65
      break;
358
120
    case OpCode::Return_call_indirect:
359
120
      updateInstrCount();
360
120
      updateGas();
361
120
      compileReturnIndirectCallOp(Instr.getSourceIndex(),
362
120
                                  Instr.getTargetIndex());
363
120
      setUnreachable();
364
120
      Builder.positionAtEnd(
365
120
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_indir.end"));
366
120
      break;
367
275
    case OpCode::Call_ref:
368
275
      updateInstrCount();
369
275
      updateGas();
370
275
      compileCallRefOp(Instr.getTargetIndex());
371
275
      break;
372
58
    case OpCode::Return_call_ref:
373
58
      updateInstrCount();
374
58
      updateGas();
375
58
      compileReturnCallRefOp(Instr.getTargetIndex());
376
58
      setUnreachable();
377
58
      Builder.positionAtEnd(
378
58
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_ref.end"));
379
58
      break;
380
381
    // Reference Instructions
382
7.49k
    case OpCode::Ref__null:
383
10.7k
    case OpCode::Ref__is_null:
384
10.7k
    case OpCode::Ref__func:
385
10.7k
    case OpCode::Ref__eq:
386
11.1k
    case OpCode::Ref__as_non_null:
387
11.2k
    case OpCode::Struct__new:
388
11.2k
    case OpCode::Struct__new_default:
389
11.2k
    case OpCode::Struct__get:
390
11.2k
    case OpCode::Struct__get_u:
391
11.2k
    case OpCode::Struct__get_s:
392
11.2k
    case OpCode::Struct__set:
393
11.4k
    case OpCode::Array__new:
394
11.4k
    case OpCode::Array__new_default:
395
11.5k
    case OpCode::Array__new_fixed:
396
11.5k
    case OpCode::Array__new_data:
397
11.5k
    case OpCode::Array__new_elem:
398
11.6k
    case OpCode::Array__get:
399
11.6k
    case OpCode::Array__get_u:
400
11.7k
    case OpCode::Array__get_s:
401
11.7k
    case OpCode::Array__set:
402
11.8k
    case OpCode::Array__len:
403
11.8k
    case OpCode::Array__fill:
404
11.8k
    case OpCode::Array__copy:
405
11.8k
    case OpCode::Array__init_data:
406
11.8k
    case OpCode::Array__init_elem:
407
11.8k
    case OpCode::Ref__test:
408
11.9k
    case OpCode::Ref__test_null:
409
11.9k
    case OpCode::Ref__cast:
410
11.9k
    case OpCode::Ref__cast_null:
411
12.0k
    case OpCode::Any__convert_extern:
412
12.0k
    case OpCode::Extern__convert_any:
413
12.1k
    case OpCode::Ref__i31:
414
12.2k
    case OpCode::I31__get_s:
415
12.2k
    case OpCode::I31__get_u:
416
15.7k
    case OpCode::Drop:
417
16.4k
    case OpCode::Select:
418
16.8k
    case OpCode::Select_t:
419
16.8k
      return compileRefOp(Instr);
420
11.1k
    case OpCode::Local__get: {
421
11.1k
      const auto &L = Local[Instr.getTargetIndex()];
422
11.1k
      stackPush(Builder.createLoad(L.first, L.second));
423
11.1k
      break;
424
16.4k
    }
425
3.62k
    case OpCode::Local__set:
426
3.62k
      Builder.createStore(stackPop(), Local[Instr.getTargetIndex()].second);
427
3.62k
      break;
428
858
    case OpCode::Local__tee:
429
858
      Builder.createStore(Stack.back(), Local[Instr.getTargetIndex()].second);
430
858
      break;
431
366
    case OpCode::Global__get: {
432
366
      const auto G =
433
366
          Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex());
434
366
      stackPush(Builder.createLoad(G.first, G.second));
435
366
      break;
436
16.4k
    }
437
88
    case OpCode::Global__set:
438
88
      Builder.createStore(
439
88
          stackPop(),
440
88
          Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex()).second);
441
88
      break;
442
443
    // Table Instructions
444
41
    case OpCode::Table__get: {
445
41
      const auto TableIndex = Instr.getTargetIndex();
446
41
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
447
41
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_get.ok");
448
41
      Builder.createCondBr(
449
41
          Builder.createLikely(Builder.createICmpULT(
450
41
              Off, Context.getTableSize(Builder, ExecCtx, TableIndex))),
451
41
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
452
41
      Builder.positionAtEnd(OkBB);
453
41
      stackPush(Builder.createLoad(
454
41
          Context.Int64x2Ty,
455
41
          Builder.createInBoundsGEP1(
456
41
              Context.Int64x2Ty, Context.getTable(Builder, ExecCtx, TableIndex),
457
41
              Off)));
458
41
      break;
459
16.4k
    }
460
31
    case OpCode::Table__set: {
461
31
      const auto TableIndex = Instr.getTargetIndex();
462
31
      auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
463
31
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
464
31
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_set.ok");
465
31
      Builder.createCondBr(
466
31
          Builder.createLikely(Builder.createICmpULT(
467
31
              Off, Context.getTableSize(Builder, ExecCtx, TableIndex))),
468
31
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
469
31
      Builder.positionAtEnd(OkBB);
470
31
      Builder.createStore(
471
31
          Ref, Builder.createInBoundsGEP1(
472
31
                   Context.Int64x2Ty,
473
31
                   Context.getTable(Builder, ExecCtx, TableIndex), Off));
474
31
      break;
475
16.4k
    }
476
25
    case OpCode::Table__init: {
477
25
      auto Len = stackPop();
478
25
      auto Src = stackPop();
479
25
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
480
25
      Builder.createCall(
481
25
          Context.getIntrinsic(
482
25
              Builder, Executable::Intrinsics::kTableInit,
483
25
              LLVM::Type::getFunctionType(Context.VoidTy,
484
25
                                          {Context.Int32Ty, Context.Int32Ty,
485
25
                                           Context.Int64Ty, Context.Int32Ty,
486
25
                                           Context.Int32Ty},
487
25
                                          false)),
488
25
          {LLContext.getInt32(Instr.getTargetIndex()),
489
25
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
490
25
      break;
491
16.4k
    }
492
33
    case OpCode::Elem__drop: {
493
33
      Builder.createCall(
494
33
          Context.getIntrinsic(Builder, Executable::Intrinsics::kElemDrop,
495
33
                               LLVM::Type::getFunctionType(
496
33
                                   Context.VoidTy, {Context.Int32Ty}, false)),
497
33
          {LLContext.getInt32(Instr.getTargetIndex())});
498
33
      break;
499
16.4k
    }
500
15
    case OpCode::Table__copy: {
501
15
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
502
15
      auto Src = Builder.createZExt(stackPop(), Context.Int64Ty);
503
15
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
504
15
      Builder.createCall(
505
15
          Context.getIntrinsic(
506
15
              Builder, Executable::Intrinsics::kTableCopy,
507
15
              LLVM::Type::getFunctionType(Context.VoidTy,
508
15
                                          {Context.Int32Ty, Context.Int32Ty,
509
15
                                           Context.Int64Ty, Context.Int64Ty,
510
15
                                           Context.Int64Ty},
511
15
                                          false)),
512
15
          {LLContext.getInt32(Instr.getTargetIndex()),
513
15
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
514
15
      break;
515
16.4k
    }
516
16
    case OpCode::Table__grow: {
517
16
      auto NewSize = Builder.createZExt(stackPop(), Context.Int64Ty);
518
16
      auto Val = stackPop();
519
16
      stackPush(Builder.createTrunc(
520
16
          Builder.createCall(
521
16
              Context.getIntrinsic(
522
16
                  Builder, Executable::Intrinsics::kTableGrow,
523
16
                  LLVM::Type::getFunctionType(
524
16
                      Context.Int64Ty,
525
16
                      {Context.Int32Ty, Context.Int64x2Ty, Context.Int64Ty},
526
16
                      false)),
527
16
              {LLContext.getInt32(Instr.getTargetIndex()), Val, NewSize}),
528
16
          Context.TableAddrTypes[Instr.getTargetIndex()]));
529
16
      break;
530
16.4k
    }
531
16
    case OpCode::Table__size: {
532
16
      stackPush(Builder.createTrunc(
533
16
          Context.getTableSize(Builder, ExecCtx, Instr.getTargetIndex()),
534
16
          Context.TableAddrTypes[Instr.getTargetIndex()]));
535
16
      break;
536
16.4k
    }
537
3
    case OpCode::Table__fill: {
538
3
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
539
3
      auto Val = stackPop();
540
3
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
541
3
      Builder.createCall(
542
3
          Context.getIntrinsic(
543
3
              Builder, Executable::Intrinsics::kTableFill,
544
3
              LLVM::Type::getFunctionType(Context.Int32Ty,
545
3
                                          {Context.Int32Ty, Context.Int64Ty,
546
3
                                           Context.Int64x2Ty, Context.Int64Ty},
547
3
                                          false)),
548
3
          {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
549
3
      break;
550
16.4k
    }
551
552
    // Memory Instructions
553
1.20k
    case OpCode::I32__load:
554
4.25k
    case OpCode::I64__load:
555
4.35k
    case OpCode::F32__load:
556
4.58k
    case OpCode::F64__load:
557
5.27k
    case OpCode::I32__load8_s:
558
5.80k
    case OpCode::I32__load8_u:
559
6.09k
    case OpCode::I32__load16_s:
560
7.67k
    case OpCode::I32__load16_u:
561
8.43k
    case OpCode::I64__load8_s:
562
8.90k
    case OpCode::I64__load8_u:
563
9.28k
    case OpCode::I64__load16_s:
564
9.89k
    case OpCode::I64__load16_u:
565
10.3k
    case OpCode::I64__load32_s:
566
10.8k
    case OpCode::I64__load32_u:
567
11.2k
    case OpCode::I32__store:
568
12.8k
    case OpCode::I64__store:
569
12.8k
    case OpCode::F32__store:
570
12.9k
    case OpCode::F64__store:
571
13.2k
    case OpCode::I32__store8:
572
13.2k
    case OpCode::I64__store8:
573
13.4k
    case OpCode::I32__store16:
574
13.5k
    case OpCode::I64__store16:
575
13.5k
    case OpCode::I64__store32:
576
14.2k
    case OpCode::Memory__size:
577
15.2k
    case OpCode::Memory__grow:
578
15.2k
    case OpCode::Memory__init:
579
15.3k
    case OpCode::Data__drop:
580
15.5k
    case OpCode::Memory__copy:
581
16.1k
    case OpCode::Memory__fill:
582
576k
    case OpCode::I32__const:
583
649k
    case OpCode::I64__const:
584
663k
    case OpCode::F32__const:
585
669k
    case OpCode::F64__const:
586
669k
      return compileMemoryOp(Instr);
587
    // Unary Numeric Instructions
588
7.81k
    case OpCode::I32__eqz:
589
9.09k
    case OpCode::I64__eqz:
590
11.2k
    case OpCode::I32__clz:
591
11.5k
    case OpCode::I64__clz:
592
13.2k
    case OpCode::I32__ctz:
593
13.8k
    case OpCode::I64__ctz:
594
31.1k
    case OpCode::I32__popcnt:
595
33.0k
    case OpCode::I64__popcnt:
596
33.8k
    case OpCode::F32__abs:
597
34.4k
    case OpCode::F64__abs:
598
35.3k
    case OpCode::F32__neg:
599
35.9k
    case OpCode::F64__neg:
600
37.3k
    case OpCode::F32__ceil:
601
39.6k
    case OpCode::F64__ceil:
602
40.3k
    case OpCode::F32__floor:
603
40.7k
    case OpCode::F64__floor:
604
41.2k
    case OpCode::F32__trunc:
605
41.5k
    case OpCode::F64__trunc:
606
42.2k
    case OpCode::F32__nearest:
607
42.6k
    case OpCode::F64__nearest:
608
43.0k
    case OpCode::F32__sqrt:
609
44.1k
    case OpCode::F64__sqrt:
610
44.5k
    case OpCode::I32__wrap_i64:
611
46.0k
    case OpCode::I32__trunc_f32_s:
612
46.2k
    case OpCode::I32__trunc_f64_s:
613
46.5k
    case OpCode::I32__trunc_f32_u:
614
47.8k
    case OpCode::I32__trunc_f64_u:
615
50.0k
    case OpCode::I64__extend_i32_s:
616
50.4k
    case OpCode::I64__extend_i32_u:
617
50.5k
    case OpCode::I64__trunc_f32_s:
618
50.8k
    case OpCode::I64__trunc_f64_s:
619
51.9k
    case OpCode::I64__trunc_f32_u:
620
53.5k
    case OpCode::I64__trunc_f64_u:
621
55.3k
    case OpCode::F32__convert_i32_s:
622
55.7k
    case OpCode::F32__convert_i64_s:
623
56.4k
    case OpCode::F32__convert_i32_u:
624
57.7k
    case OpCode::F32__convert_i64_u:
625
59.1k
    case OpCode::F64__convert_i32_s:
626
63.3k
    case OpCode::F64__convert_i64_s:
627
65.3k
    case OpCode::F64__convert_i32_u:
628
65.5k
    case OpCode::F64__convert_i64_u:
629
65.7k
    case OpCode::F32__demote_f64:
630
65.8k
    case OpCode::F64__promote_f32:
631
66.3k
    case OpCode::I32__reinterpret_f32:
632
66.9k
    case OpCode::I64__reinterpret_f64:
633
71.0k
    case OpCode::F32__reinterpret_i32:
634
72.2k
    case OpCode::F64__reinterpret_i64:
635
76.3k
    case OpCode::I32__extend8_s:
636
79.1k
    case OpCode::I32__extend16_s:
637
79.5k
    case OpCode::I64__extend8_s:
638
80.1k
    case OpCode::I64__extend16_s:
639
80.7k
    case OpCode::I64__extend32_s:
640
81.8k
    case OpCode::I32__eq:
641
82.1k
    case OpCode::I64__eq:
642
82.8k
    case OpCode::I32__ne:
643
82.8k
    case OpCode::I64__ne:
644
85.7k
    case OpCode::I32__lt_s:
645
86.3k
    case OpCode::I64__lt_s:
646
92.4k
    case OpCode::I32__lt_u:
647
92.7k
    case OpCode::I64__lt_u:
648
93.9k
    case OpCode::I32__gt_s:
649
94.4k
    case OpCode::I64__gt_s:
650
100k
    case OpCode::I32__gt_u:
651
100k
    case OpCode::I64__gt_u:
652
102k
    case OpCode::I32__le_s:
653
103k
    case OpCode::I64__le_s:
654
103k
    case OpCode::I32__le_u:
655
105k
    case OpCode::I64__le_u:
656
106k
    case OpCode::I32__ge_s:
657
106k
    case OpCode::I64__ge_s:
658
107k
    case OpCode::I32__ge_u:
659
108k
    case OpCode::I64__ge_u:
660
108k
    case OpCode::F32__eq:
661
108k
    case OpCode::F64__eq:
662
108k
    case OpCode::F32__ne:
663
108k
    case OpCode::F64__ne:
664
108k
    case OpCode::F32__lt:
665
108k
    case OpCode::F64__lt:
666
108k
    case OpCode::F32__gt:
667
108k
    case OpCode::F64__gt:
668
108k
    case OpCode::F32__le:
669
108k
    case OpCode::F64__le:
670
109k
    case OpCode::F32__ge:
671
109k
    case OpCode::F64__ge:
672
109k
    case OpCode::I32__add:
673
110k
    case OpCode::I64__add:
674
112k
    case OpCode::I32__sub:
675
112k
    case OpCode::I64__sub:
676
113k
    case OpCode::I32__mul:
677
113k
    case OpCode::I64__mul:
678
115k
    case OpCode::I32__div_s:
679
115k
    case OpCode::I64__div_s:
680
118k
    case OpCode::I32__div_u:
681
118k
    case OpCode::I64__div_u:
682
120k
    case OpCode::I32__rem_s:
683
120k
    case OpCode::I64__rem_s:
684
122k
    case OpCode::I32__rem_u:
685
123k
    case OpCode::I64__rem_u:
686
123k
    case OpCode::I32__and:
687
125k
    case OpCode::I64__and:
688
126k
    case OpCode::I32__or:
689
126k
    case OpCode::I64__or:
690
128k
    case OpCode::I32__xor:
691
128k
    case OpCode::I64__xor:
692
130k
    case OpCode::I32__shl:
693
131k
    case OpCode::I64__shl:
694
133k
    case OpCode::I32__shr_s:
695
134k
    case OpCode::I64__shr_s:
696
137k
    case OpCode::I32__shr_u:
697
138k
    case OpCode::I64__shr_u:
698
140k
    case OpCode::I32__rotl:
699
141k
    case OpCode::I32__rotr:
700
142k
    case OpCode::I64__rotl:
701
143k
    case OpCode::I64__rotr:
702
144k
    case OpCode::F32__add:
703
144k
    case OpCode::F64__add:
704
144k
    case OpCode::F32__sub:
705
144k
    case OpCode::F64__sub:
706
145k
    case OpCode::F32__mul:
707
145k
    case OpCode::F64__mul:
708
145k
    case OpCode::F32__div:
709
145k
    case OpCode::F64__div:
710
146k
    case OpCode::F32__min:
711
146k
    case OpCode::F64__min:
712
146k
    case OpCode::F32__max:
713
147k
    case OpCode::F64__max:
714
147k
    case OpCode::F32__copysign:
715
148k
    case OpCode::F64__copysign:
716
148k
    case OpCode::I32__trunc_sat_f32_s:
717
148k
    case OpCode::I32__trunc_sat_f32_u:
718
149k
    case OpCode::I32__trunc_sat_f64_s:
719
149k
    case OpCode::I32__trunc_sat_f64_u:
720
150k
    case OpCode::I64__trunc_sat_f32_s:
721
150k
    case OpCode::I64__trunc_sat_f32_u:
722
150k
    case OpCode::I64__trunc_sat_f64_s:
723
151k
    case OpCode::I64__trunc_sat_f64_u:
724
151k
      return compileNumericOp(Instr);
725
4.85k
    case OpCode::V128__load:
726
5.07k
    case OpCode::V128__load8x8_s:
727
5.12k
    case OpCode::V128__load8x8_u:
728
5.44k
    case OpCode::V128__load16x4_s:
729
5.95k
    case OpCode::V128__load16x4_u:
730
6.09k
    case OpCode::V128__load32x2_s:
731
6.28k
    case OpCode::V128__load32x2_u:
732
6.36k
    case OpCode::V128__load8_splat:
733
6.51k
    case OpCode::V128__load16_splat:
734
6.70k
    case OpCode::V128__load32_splat:
735
6.86k
    case OpCode::V128__load64_splat:
736
6.94k
    case OpCode::V128__load32_zero:
737
7.08k
    case OpCode::V128__load64_zero:
738
7.31k
    case OpCode::V128__store:
739
7.49k
    case OpCode::V128__load8_lane:
740
7.64k
    case OpCode::V128__load16_lane:
741
7.75k
    case OpCode::V128__load32_lane:
742
7.77k
    case OpCode::V128__load64_lane:
743
7.93k
    case OpCode::V128__store8_lane:
744
8.01k
    case OpCode::V128__store16_lane:
745
8.10k
    case OpCode::V128__store32_lane:
746
8.13k
    case OpCode::V128__store64_lane:
747
8.48k
    case OpCode::V128__const:
748
8.50k
    case OpCode::I8x16__shuffle:
749
8.58k
    case OpCode::I8x16__extract_lane_s:
750
8.60k
    case OpCode::I8x16__extract_lane_u:
751
8.83k
    case OpCode::I8x16__replace_lane:
752
9.28k
    case OpCode::I16x8__extract_lane_s:
753
9.68k
    case OpCode::I16x8__extract_lane_u:
754
9.94k
    case OpCode::I16x8__replace_lane:
755
10.0k
    case OpCode::I32x4__extract_lane:
756
10.2k
    case OpCode::I32x4__replace_lane:
757
10.3k
    case OpCode::I64x2__extract_lane:
758
10.3k
    case OpCode::I64x2__replace_lane:
759
10.4k
    case OpCode::F32x4__extract_lane:
760
10.4k
    case OpCode::F32x4__replace_lane:
761
10.5k
    case OpCode::F64x2__extract_lane:
762
10.5k
    case OpCode::F64x2__replace_lane:
763
10.6k
    case OpCode::I8x16__swizzle:
764
47.4k
    case OpCode::I8x16__splat:
765
56.0k
    case OpCode::I16x8__splat:
766
57.2k
    case OpCode::I32x4__splat:
767
57.8k
    case OpCode::I64x2__splat:
768
58.1k
    case OpCode::F32x4__splat:
769
58.2k
    case OpCode::F64x2__splat:
770
58.3k
    case OpCode::I8x16__eq:
771
58.8k
    case OpCode::I8x16__ne:
772
58.8k
    case OpCode::I8x16__lt_s:
773
58.9k
    case OpCode::I8x16__lt_u:
774
59.2k
    case OpCode::I8x16__gt_s:
775
59.4k
    case OpCode::I8x16__gt_u:
776
59.5k
    case OpCode::I8x16__le_s:
777
59.7k
    case OpCode::I8x16__le_u:
778
60.2k
    case OpCode::I8x16__ge_s:
779
60.3k
    case OpCode::I8x16__ge_u:
780
60.5k
    case OpCode::I16x8__eq:
781
60.7k
    case OpCode::I16x8__ne:
782
60.7k
    case OpCode::I16x8__lt_s:
783
61.0k
    case OpCode::I16x8__lt_u:
784
61.2k
    case OpCode::I16x8__gt_s:
785
61.3k
    case OpCode::I16x8__gt_u:
786
61.4k
    case OpCode::I16x8__le_s:
787
61.5k
    case OpCode::I16x8__le_u:
788
61.6k
    case OpCode::I16x8__ge_s:
789
61.7k
    case OpCode::I16x8__ge_u:
790
61.8k
    case OpCode::I32x4__eq:
791
61.9k
    case OpCode::I32x4__ne:
792
61.9k
    case OpCode::I32x4__lt_s:
793
62.0k
    case OpCode::I32x4__lt_u:
794
62.2k
    case OpCode::I32x4__gt_s:
795
62.5k
    case OpCode::I32x4__gt_u:
796
62.7k
    case OpCode::I32x4__le_s:
797
63.0k
    case OpCode::I32x4__le_u:
798
63.0k
    case OpCode::I32x4__ge_s:
799
63.2k
    case OpCode::I32x4__ge_u:
800
63.3k
    case OpCode::I64x2__eq:
801
63.4k
    case OpCode::I64x2__ne:
802
63.4k
    case OpCode::I64x2__lt_s:
803
63.6k
    case OpCode::I64x2__gt_s:
804
63.6k
    case OpCode::I64x2__le_s:
805
63.7k
    case OpCode::I64x2__ge_s:
806
65.0k
    case OpCode::F32x4__eq:
807
65.1k
    case OpCode::F32x4__ne:
808
65.8k
    case OpCode::F32x4__lt:
809
65.9k
    case OpCode::F32x4__gt:
810
66.2k
    case OpCode::F32x4__le:
811
66.3k
    case OpCode::F32x4__ge:
812
66.4k
    case OpCode::F64x2__eq:
813
66.5k
    case OpCode::F64x2__ne:
814
66.6k
    case OpCode::F64x2__lt:
815
66.6k
    case OpCode::F64x2__gt:
816
66.8k
    case OpCode::F64x2__le:
817
66.9k
    case OpCode::F64x2__ge:
818
67.4k
    case OpCode::V128__not:
819
67.5k
    case OpCode::V128__and:
820
67.6k
    case OpCode::V128__andnot:
821
67.7k
    case OpCode::V128__or:
822
67.8k
    case OpCode::V128__xor:
823
67.9k
    case OpCode::V128__bitselect:
824
68.1k
    case OpCode::V128__any_true:
825
69.5k
    case OpCode::I8x16__abs:
826
72.0k
    case OpCode::I8x16__neg:
827
72.2k
    case OpCode::I8x16__popcnt:
828
72.5k
    case OpCode::I8x16__all_true:
829
73.1k
    case OpCode::I8x16__bitmask:
830
73.2k
    case OpCode::I8x16__narrow_i16x8_s:
831
73.4k
    case OpCode::I8x16__narrow_i16x8_u:
832
73.5k
    case OpCode::I8x16__shl:
833
74.6k
    case OpCode::I8x16__shr_s:
834
74.7k
    case OpCode::I8x16__shr_u:
835
74.8k
    case OpCode::I8x16__add:
836
75.2k
    case OpCode::I8x16__add_sat_s:
837
75.2k
    case OpCode::I8x16__add_sat_u:
838
75.3k
    case OpCode::I8x16__sub:
839
75.5k
    case OpCode::I8x16__sub_sat_s:
840
75.6k
    case OpCode::I8x16__sub_sat_u:
841
75.6k
    case OpCode::I8x16__min_s:
842
75.7k
    case OpCode::I8x16__min_u:
843
76.1k
    case OpCode::I8x16__max_s:
844
76.2k
    case OpCode::I8x16__max_u:
845
76.3k
    case OpCode::I8x16__avgr_u:
846
76.5k
    case OpCode::I16x8__abs:
847
76.7k
    case OpCode::I16x8__neg:
848
76.9k
    case OpCode::I16x8__all_true:
849
77.0k
    case OpCode::I16x8__bitmask:
850
77.0k
    case OpCode::I16x8__narrow_i32x4_s:
851
77.4k
    case OpCode::I16x8__narrow_i32x4_u:
852
78.4k
    case OpCode::I16x8__extend_low_i8x16_s:
853
78.5k
    case OpCode::I16x8__extend_high_i8x16_s:
854
78.8k
    case OpCode::I16x8__extend_low_i8x16_u:
855
78.8k
    case OpCode::I16x8__extend_high_i8x16_u:
856
79.0k
    case OpCode::I16x8__shl:
857
79.2k
    case OpCode::I16x8__shr_s:
858
79.4k
    case OpCode::I16x8__shr_u:
859
79.5k
    case OpCode::I16x8__add:
860
79.5k
    case OpCode::I16x8__add_sat_s:
861
79.9k
    case OpCode::I16x8__add_sat_u:
862
80.2k
    case OpCode::I16x8__sub:
863
80.2k
    case OpCode::I16x8__sub_sat_s:
864
80.3k
    case OpCode::I16x8__sub_sat_u:
865
80.5k
    case OpCode::I16x8__mul:
866
80.6k
    case OpCode::I16x8__min_s:
867
80.8k
    case OpCode::I16x8__min_u:
868
80.8k
    case OpCode::I16x8__max_s:
869
81.4k
    case OpCode::I16x8__max_u:
870
81.5k
    case OpCode::I16x8__avgr_u:
871
81.6k
    case OpCode::I16x8__extmul_low_i8x16_s:
872
81.8k
    case OpCode::I16x8__extmul_high_i8x16_s:
873
81.9k
    case OpCode::I16x8__extmul_low_i8x16_u:
874
82.3k
    case OpCode::I16x8__extmul_high_i8x16_u:
875
82.4k
    case OpCode::I16x8__q15mulr_sat_s:
876
82.8k
    case OpCode::I16x8__extadd_pairwise_i8x16_s:
877
83.2k
    case OpCode::I16x8__extadd_pairwise_i8x16_u:
878
83.2k
    case OpCode::I32x4__abs:
879
83.4k
    case OpCode::I32x4__neg:
880
83.6k
    case OpCode::I32x4__all_true:
881
83.7k
    case OpCode::I32x4__bitmask:
882
83.8k
    case OpCode::I32x4__extend_low_i16x8_s:
883
84.3k
    case OpCode::I32x4__extend_high_i16x8_s:
884
86.2k
    case OpCode::I32x4__extend_low_i16x8_u:
885
86.4k
    case OpCode::I32x4__extend_high_i16x8_u:
886
87.4k
    case OpCode::I32x4__shl:
887
87.6k
    case OpCode::I32x4__shr_s:
888
88.0k
    case OpCode::I32x4__shr_u:
889
88.2k
    case OpCode::I32x4__add:
890
88.3k
    case OpCode::I32x4__sub:
891
88.5k
    case OpCode::I32x4__mul:
892
88.6k
    case OpCode::I32x4__min_s:
893
88.6k
    case OpCode::I32x4__min_u:
894
88.8k
    case OpCode::I32x4__max_s:
895
88.8k
    case OpCode::I32x4__max_u:
896
88.9k
    case OpCode::I32x4__extmul_low_i16x8_s:
897
89.0k
    case OpCode::I32x4__extmul_high_i16x8_s:
898
89.2k
    case OpCode::I32x4__extmul_low_i16x8_u:
899
89.4k
    case OpCode::I32x4__extmul_high_i16x8_u:
900
90.5k
    case OpCode::I32x4__extadd_pairwise_i16x8_s:
901
91.6k
    case OpCode::I32x4__extadd_pairwise_i16x8_u:
902
91.8k
    case OpCode::I32x4__dot_i16x8_s:
903
92.7k
    case OpCode::I64x2__abs:
904
93.2k
    case OpCode::I64x2__neg:
905
93.5k
    case OpCode::I64x2__all_true:
906
93.8k
    case OpCode::I64x2__bitmask:
907
94.2k
    case OpCode::I64x2__extend_low_i32x4_s:
908
94.9k
    case OpCode::I64x2__extend_high_i32x4_s:
909
95.1k
    case OpCode::I64x2__extend_low_i32x4_u:
910
95.7k
    case OpCode::I64x2__extend_high_i32x4_u:
911
95.8k
    case OpCode::I64x2__shl:
912
96.2k
    case OpCode::I64x2__shr_s:
913
96.3k
    case OpCode::I64x2__shr_u:
914
96.3k
    case OpCode::I64x2__add:
915
96.6k
    case OpCode::I64x2__sub:
916
96.7k
    case OpCode::I64x2__mul:
917
96.7k
    case OpCode::I64x2__extmul_low_i32x4_s:
918
97.1k
    case OpCode::I64x2__extmul_high_i32x4_s:
919
97.1k
    case OpCode::I64x2__extmul_low_i32x4_u:
920
97.3k
    case OpCode::I64x2__extmul_high_i32x4_u:
921
97.4k
    case OpCode::F32x4__abs:
922
97.6k
    case OpCode::F32x4__neg:
923
97.8k
    case OpCode::F32x4__sqrt:
924
97.9k
    case OpCode::F32x4__add:
925
98.2k
    case OpCode::F32x4__sub:
926
98.2k
    case OpCode::F32x4__mul:
927
98.4k
    case OpCode::F32x4__div:
928
98.5k
    case OpCode::F32x4__min:
929
98.5k
    case OpCode::F32x4__max:
930
98.6k
    case OpCode::F32x4__pmin:
931
98.8k
    case OpCode::F32x4__pmax:
932
99.9k
    case OpCode::F32x4__ceil:
933
101k
    case OpCode::F32x4__floor:
934
103k
    case OpCode::F32x4__trunc:
935
104k
    case OpCode::F32x4__nearest:
936
104k
    case OpCode::F64x2__abs:
937
105k
    case OpCode::F64x2__neg:
938
105k
    case OpCode::F64x2__sqrt:
939
105k
    case OpCode::F64x2__add:
940
105k
    case OpCode::F64x2__sub:
941
105k
    case OpCode::F64x2__mul:
942
105k
    case OpCode::F64x2__div:
943
106k
    case OpCode::F64x2__min:
944
106k
    case OpCode::F64x2__max:
945
106k
    case OpCode::F64x2__pmin:
946
106k
    case OpCode::F64x2__pmax:
947
107k
    case OpCode::F64x2__ceil:
948
108k
    case OpCode::F64x2__floor:
949
108k
    case OpCode::F64x2__trunc:
950
108k
    case OpCode::F64x2__nearest:
951
108k
    case OpCode::I32x4__trunc_sat_f32x4_s:
952
112k
    case OpCode::I32x4__trunc_sat_f32x4_u:
953
112k
    case OpCode::F32x4__convert_i32x4_s:
954
113k
    case OpCode::F32x4__convert_i32x4_u:
955
114k
    case OpCode::I32x4__trunc_sat_f64x2_s_zero:
956
116k
    case OpCode::I32x4__trunc_sat_f64x2_u_zero:
957
116k
    case OpCode::F64x2__convert_low_i32x4_s:
958
117k
    case OpCode::F64x2__convert_low_i32x4_u:
959
118k
    case OpCode::F32x4__demote_f64x2_zero:
960
119k
    case OpCode::F64x2__promote_low_f32x4:
961
119k
    case OpCode::I8x16__relaxed_swizzle:
962
119k
    case OpCode::I32x4__relaxed_trunc_f32x4_s:
963
119k
    case OpCode::I32x4__relaxed_trunc_f32x4_u:
964
119k
    case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
965
119k
    case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
966
119k
    case OpCode::F32x4__relaxed_madd:
967
119k
    case OpCode::F32x4__relaxed_nmadd:
968
119k
    case OpCode::F64x2__relaxed_madd:
969
119k
    case OpCode::F64x2__relaxed_nmadd:
970
119k
    case OpCode::I8x16__relaxed_laneselect:
971
119k
    case OpCode::I16x8__relaxed_laneselect:
972
119k
    case OpCode::I32x4__relaxed_laneselect:
973
119k
    case OpCode::I64x2__relaxed_laneselect:
974
119k
    case OpCode::F32x4__relaxed_min:
975
119k
    case OpCode::F32x4__relaxed_max:
976
119k
    case OpCode::F64x2__relaxed_min:
977
119k
    case OpCode::F64x2__relaxed_max:
978
119k
    case OpCode::I16x8__relaxed_q15mulr_s:
979
119k
    case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
980
119k
    case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
981
119k
      return compileVectorOp(Instr);
982
192
    case OpCode::Atomic__fence:
983
272
    case OpCode::Memory__atomic__notify:
984
278
    case OpCode::Memory__atomic__wait32:
985
283
    case OpCode::Memory__atomic__wait64:
986
283
    case OpCode::I32__atomic__load:
987
283
    case OpCode::I64__atomic__load:
988
283
    case OpCode::I32__atomic__load8_u:
989
283
    case OpCode::I32__atomic__load16_u:
990
283
    case OpCode::I64__atomic__load8_u:
991
283
    case OpCode::I64__atomic__load16_u:
992
283
    case OpCode::I64__atomic__load32_u:
993
283
    case OpCode::I32__atomic__store:
994
283
    case OpCode::I64__atomic__store:
995
283
    case OpCode::I32__atomic__store8:
996
283
    case OpCode::I32__atomic__store16:
997
283
    case OpCode::I64__atomic__store8:
998
283
    case OpCode::I64__atomic__store16:
999
283
    case OpCode::I64__atomic__store32:
1000
283
    case OpCode::I32__atomic__rmw__add:
1001
283
    case OpCode::I64__atomic__rmw__add:
1002
283
    case OpCode::I32__atomic__rmw8__add_u:
1003
283
    case OpCode::I32__atomic__rmw16__add_u:
1004
283
    case OpCode::I64__atomic__rmw8__add_u:
1005
283
    case OpCode::I64__atomic__rmw16__add_u:
1006
283
    case OpCode::I64__atomic__rmw32__add_u:
1007
283
    case OpCode::I32__atomic__rmw__sub:
1008
283
    case OpCode::I64__atomic__rmw__sub:
1009
283
    case OpCode::I32__atomic__rmw8__sub_u:
1010
283
    case OpCode::I32__atomic__rmw16__sub_u:
1011
283
    case OpCode::I64__atomic__rmw8__sub_u:
1012
283
    case OpCode::I64__atomic__rmw16__sub_u:
1013
283
    case OpCode::I64__atomic__rmw32__sub_u:
1014
283
    case OpCode::I32__atomic__rmw__and:
1015
283
    case OpCode::I64__atomic__rmw__and:
1016
283
    case OpCode::I32__atomic__rmw8__and_u:
1017
283
    case OpCode::I32__atomic__rmw16__and_u:
1018
283
    case OpCode::I64__atomic__rmw8__and_u:
1019
283
    case OpCode::I64__atomic__rmw16__and_u:
1020
283
    case OpCode::I64__atomic__rmw32__and_u:
1021
283
    case OpCode::I32__atomic__rmw__or:
1022
283
    case OpCode::I64__atomic__rmw__or:
1023
283
    case OpCode::I32__atomic__rmw8__or_u:
1024
283
    case OpCode::I32__atomic__rmw16__or_u:
1025
283
    case OpCode::I64__atomic__rmw8__or_u:
1026
283
    case OpCode::I64__atomic__rmw16__or_u:
1027
283
    case OpCode::I64__atomic__rmw32__or_u:
1028
283
    case OpCode::I32__atomic__rmw__xor:
1029
283
    case OpCode::I64__atomic__rmw__xor:
1030
283
    case OpCode::I32__atomic__rmw8__xor_u:
1031
283
    case OpCode::I32__atomic__rmw16__xor_u:
1032
283
    case OpCode::I64__atomic__rmw8__xor_u:
1033
283
    case OpCode::I64__atomic__rmw16__xor_u:
1034
283
    case OpCode::I64__atomic__rmw32__xor_u:
1035
283
    case OpCode::I32__atomic__rmw__xchg:
1036
283
    case OpCode::I64__atomic__rmw__xchg:
1037
283
    case OpCode::I32__atomic__rmw8__xchg_u:
1038
283
    case OpCode::I32__atomic__rmw16__xchg_u:
1039
283
    case OpCode::I64__atomic__rmw8__xchg_u:
1040
283
    case OpCode::I64__atomic__rmw16__xchg_u:
1041
283
    case OpCode::I64__atomic__rmw32__xchg_u:
1042
283
    case OpCode::I32__atomic__rmw__cmpxchg:
1043
283
    case OpCode::I64__atomic__rmw__cmpxchg:
1044
283
    case OpCode::I32__atomic__rmw8__cmpxchg_u:
1045
283
    case OpCode::I32__atomic__rmw16__cmpxchg_u:
1046
283
    case OpCode::I64__atomic__rmw8__cmpxchg_u:
1047
283
    case OpCode::I64__atomic__rmw16__cmpxchg_u:
1048
283
    case OpCode::I64__atomic__rmw32__cmpxchg_u:
1049
283
      return compileAtomicOp(Instr);
1050
0
    default:
1051
0
      assumingUnreachable();
1052
1.02M
    }
1053
71.9k
    return {};
1054
1.02M
  };
1055
1056
1.56M
  for (const auto &Instr : Instrs) {
1057
    // Update instruction count
1058
1.56M
    if (LocalInstrCount) {
1059
0
      Builder.createStore(Builder.createAdd(Builder.createLoad(Context.Int64Ty,
1060
0
                                                               LocalInstrCount),
1061
0
                                            LLContext.getInt64(1)),
1062
0
                          LocalInstrCount);
1063
0
    }
1064
1.56M
    if (LocalGas) {
1065
0
      auto NewGas = Builder.createAdd(
1066
0
          Builder.createLoad(Context.Int64Ty, LocalGas),
1067
0
          Builder.createLoad(
1068
0
              Context.Int64Ty,
1069
0
              Builder.createConstInBoundsGEP2_64(
1070
0
                  LLVM::Type::getArrayType(Context.Int64Ty, UINT16_MAX + 1),
1071
0
                  Context.getCostTable(Builder, ExecCtx), 0,
1072
0
                  uint16_t(Instr.getOpCode()))));
1073
0
      Builder.createStore(NewGas, LocalGas);
1074
0
    }
1075
1076
    // Make the instruction node according to Code.
1077
1.56M
    EXPECTED_TRY(Dispatch(Instr));
1078
1.56M
  }
1079
10.3k
  return {};
1080
10.3k
}
1081
1082
11.0k
void FunctionCompiler::compileReturn() noexcept {
1083
11.0k
  updateInstrCount();
1084
11.0k
  updateGas();
1085
11.0k
  auto Ty = F.Ty.getReturnType();
1086
11.0k
  if (Ty.isVoidTy()) {
1087
2.10k
    Builder.createRetVoid();
1088
8.96k
  } else if (Ty.isStructTy()) {
1089
317
    const auto Count = Ty.getStructNumElements();
1090
317
    std::vector<LLVM::Value> Ret(Count);
1091
1.18k
    for (unsigned I = 0; I < Count; ++I) {
1092
865
      const unsigned J = Count - 1 - I;
1093
865
      Ret[J] = stackPop();
1094
865
    }
1095
317
    Builder.createAggregateRet(Ret);
1096
8.65k
  } else {
1097
8.65k
    Builder.createRet(stackPop());
1098
8.65k
  }
1099
11.0k
}
1100
1101
20.5k
void FunctionCompiler::updateInstrCount() noexcept {
1102
20.5k
  if (LocalInstrCount) {
1103
0
    auto Store [[maybe_unused]] = Builder.createAtomicRMW(
1104
0
        LLVMAtomicRMWBinOpAdd, Context.getInstrCount(Builder, ExecCtx),
1105
0
        Builder.createLoad(Context.Int64Ty, LocalInstrCount),
1106
0
        LLVMAtomicOrderingMonotonic);
1107
#if LLVM_VERSION_MAJOR >= 13
1108
    Store.setAlignment(8);
1109
#endif
1110
0
    Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
1111
0
  }
1112
20.5k
}
1113
1114
20.9k
void FunctionCompiler::updateGas() noexcept {
1115
20.9k
  if (LocalGas) {
1116
0
    auto CurrBB = Builder.getInsertBlock();
1117
0
    auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_check");
1118
0
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_ok");
1119
0
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_end");
1120
1121
0
    auto Cost = Builder.createLoad(Context.Int64Ty, LocalGas);
1122
0
    Cost.setAlignment(64);
1123
0
    auto GasPtr = Context.getGas(Builder, ExecCtx);
1124
0
    auto GasLimit = Context.getGasLimit(Builder, ExecCtx);
1125
0
    auto Gas = Builder.createLoad(Context.Int64Ty, GasPtr);
1126
0
    Gas.setAlignment(64);
1127
0
    Gas.setOrdering(LLVMAtomicOrderingMonotonic);
1128
0
    Builder.createBr(CheckBB);
1129
0
    Builder.positionAtEnd(CheckBB);
1130
1131
0
    auto PHIOldGas = Builder.createPHI(Context.Int64Ty);
1132
0
    auto NewGas = Builder.createAdd(PHIOldGas, Cost);
1133
0
    auto IsGasRemain =
1134
0
        Builder.createLikely(Builder.createICmpULE(NewGas, GasLimit));
1135
0
    Builder.createCondBr(IsGasRemain, OkBB,
1136
0
                         getTrapBB(ErrCode::Value::CostLimitExceeded));
1137
0
    Builder.positionAtEnd(OkBB);
1138
1139
0
    auto RGasAndSucceed = Builder.createAtomicCmpXchg(
1140
0
        GasPtr, PHIOldGas, NewGas, LLVMAtomicOrderingMonotonic,
1141
0
        LLVMAtomicOrderingMonotonic);
1142
#if LLVM_VERSION_MAJOR >= 13
1143
    RGasAndSucceed.setAlignment(8);
1144
#endif
1145
0
    RGasAndSucceed.setWeak(true);
1146
0
    auto RGas = Builder.createExtractValue(RGasAndSucceed, 0);
1147
0
    auto Succeed = Builder.createExtractValue(RGasAndSucceed, 1);
1148
0
    Builder.createCondBr(Builder.createLikely(Succeed), EndBB, CheckBB);
1149
0
    Builder.positionAtEnd(EndBB);
1150
1151
0
    Builder.createStore(LLContext.getInt64(0), LocalGas);
1152
1153
0
    PHIOldGas.addIncoming(Gas, CurrBB);
1154
0
    PHIOldGas.addIncoming(RGas, OkBB);
1155
0
  }
1156
20.9k
}
1157
1158
5.07k
void FunctionCompiler::updateGasAtTrap() noexcept {
1159
5.07k
  if (LocalGas) {
1160
0
    auto Update [[maybe_unused]] = Builder.createAtomicRMW(
1161
0
        LLVMAtomicRMWBinOpAdd, Context.getGas(Builder, ExecCtx),
1162
0
        Builder.createLoad(Context.Int64Ty, LocalGas),
1163
0
        LLVMAtomicOrderingMonotonic);
1164
#if LLVM_VERSION_MAJOR >= 13
1165
    Update.setAlignment(8);
1166
#endif
1167
0
  }
1168
5.07k
}
1169
1170
void FunctionCompiler::compileTryTableOp(
1171
166
    const AST::Instruction &Instr) noexcept {
1172
166
  const auto &TryDesc = Instr.getTryCatch();
1173
166
  auto Type = Context.resolveBlockType(TryDesc.ResType);
1174
166
  const auto Arity = Type.first.size();
1175
166
  std::vector<LLVM::Value> Args(Arity);
1176
1177
166
  auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "try_table");
1178
166
  auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "try_table.end");
1179
1180
166
  if (isUnreachable()) {
1181
    // The body is dead code, therefore no dispatch block is emitted and no
1182
    // pending checks inside will target it.
1183
184
    for (size_t I = 0; I < Arity; ++I) {
1184
92
      auto Ty = toLLVMType(LLContext, Type.first[I]);
1185
92
      Args[I] = LLVM::Value::getUndef(Ty);
1186
92
    }
1187
92
    Builder.createBr(Block);
1188
92
    Builder.positionAtEnd(Block);
1189
92
    enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
1190
92
    checkStop();
1191
92
    updateGas();
1192
92
    return;
1193
92
  }
1194
1195
156
  for (size_t I = 0; I < Arity; ++I) {
1196
82
    const size_t J = Arity - 1 - I;
1197
82
    Args[J] = stackPop();
1198
82
  }
1199
74
  Builder.createBr(Block);
1200
1201
74
  LLVM::BasicBlock DispatchBB = {};
1202
74
  const auto &Catch = TryDesc.Catch;
1203
74
  if (!Catch.empty()) {
1204
    // Emit the dispatch in the outer label context: the catch clause label
1205
    // indices are relative to the block enclosing this try_table.
1206
0
    DispatchBB = LLVM::BasicBlock::create(LLContext, F.Fn, "try.dispatch");
1207
0
    Builder.positionAtEnd(DispatchBB);
1208
1209
    // Clauses after a catch_all can never match, so no check is emitted for
1210
    // them.
1211
0
    auto PendingTagInst = Builder.createLoad(
1212
0
        Context.Int8PtrTy, Context.getPendingExnTagAddr(Builder, ExecCtx));
1213
0
    std::vector<
1214
0
        std::pair<const AST::Instruction::CatchDescriptor *, LLVM::BasicBlock>>
1215
0
        Cases;
1216
0
    bool HasCatchAll = false;
1217
0
    for (const auto &C : Catch) {
1218
0
      auto CaseBB = LLVM::BasicBlock::create(LLContext, F.Fn, "catch");
1219
0
      Cases.emplace_back(&C, CaseBB);
1220
0
      if (C.IsAll) {
1221
0
        Builder.createBr(CaseBB);
1222
0
        HasCatchAll = true;
1223
0
        break;
1224
0
      }
1225
0
      assuming(C.TagIndex < Context.Tags.size());
1226
0
      auto NextBB =
1227
0
          LLVM::BasicBlock::create(LLContext, F.Fn, "try.dispatch.next");
1228
0
      auto IsMatch = Builder.createICmpEQ(
1229
0
          PendingTagInst, Context.getTag(Builder, ExecCtx, C.TagIndex));
1230
0
      Builder.createCondBr(IsMatch, CaseBB, NextBB);
1231
0
      Builder.positionAtEnd(NextBB);
1232
0
    }
1233
0
    if (!HasCatchAll) {
1234
0
      Builder.createBr(getEHDispatchTarget());
1235
0
    }
1236
1237
0
    for (const auto &[C, CaseBB] : Cases) {
1238
0
      Builder.positionAtEnd(CaseBB);
1239
1240
0
      const size_t StackSizeBefore = Stack.size();
1241
0
      uint32_t PayloadNum = 0;
1242
0
      if (!C->IsAll) {
1243
0
        const auto &TagFuncType =
1244
0
            Context.CompositeTypes[Context.Tags[C->TagIndex]]->getFuncType();
1245
0
        PayloadNum = static_cast<uint32_t>(TagFuncType.getParamTypes().size());
1246
0
      }
1247
0
      const uint32_t OutNum = PayloadNum + (C->IsRef ? 1U : 0U);
1248
0
      LLVM::Value Out = Builder.createArray(OutNum, LLVM::kValSize);
1249
0
      Builder.createCall(
1250
0
          Context.getIntrinsic(
1251
0
              Builder, Executable::Intrinsics::kCatchPop,
1252
0
              LLVM::Type::getFunctionType(
1253
0
                  Context.VoidTy,
1254
0
                  {Context.Int8PtrTy, Context.Int32Ty, Context.Int32Ty},
1255
0
                  false)),
1256
0
          {Out, LLContext.getInt32(C->IsAll ? 0 : 1),
1257
0
           LLContext.getInt32(C->IsRef ? 1 : 0)});
1258
1259
0
      uint32_t OutIdx = 0;
1260
0
      if (!C->IsAll) {
1261
0
        const auto &TagFuncType =
1262
0
            Context.CompositeTypes[Context.Tags[C->TagIndex]]->getFuncType();
1263
0
        for (const auto &PType : TagFuncType.getParamTypes()) {
1264
0
          stackPush(Builder.createValuePtrLoad(
1265
0
              toLLVMType(LLContext, PType), Out, Context.Int8Ty,
1266
0
              static_cast<uint64_t>(OutIdx) * LLVM::kValSize));
1267
0
          ++OutIdx;
1268
0
        }
1269
0
      }
1270
0
      if (C->IsRef) {
1271
0
        stackPush(Builder.createValuePtrLoad(
1272
0
            Context.Int64x2Ty, Out, Context.Int8Ty,
1273
0
            static_cast<uint64_t>(OutIdx) * LLVM::kValSize));
1274
0
      }
1275
0
      setLableJumpPHI(C->LabelIndex);
1276
0
      Builder.createBr(getLabel(C->LabelIndex));
1277
0
      Stack.erase(Stack.begin() + static_cast<int64_t>(StackSizeBefore),
1278
0
                  Stack.end());
1279
0
    }
1280
0
  }
1281
1282
74
  Builder.positionAtEnd(Block);
1283
74
  enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
1284
74
  ControlStack.back().TryDispatchBB = DispatchBB;
1285
74
  checkStop();
1286
74
  updateGas();
1287
74
}
1288
1289
2
void FunctionCompiler::compileThrowOp(const uint32_t TagIndex) noexcept {
1290
2
  assuming(TagIndex < Context.Tags.size());
1291
2
  const auto &TagFuncType =
1292
2
      Context.CompositeTypes[Context.Tags[TagIndex]]->getFuncType();
1293
2
  const auto Arity = static_cast<uint32_t>(TagFuncType.getParamTypes().size());
1294
1295
2
  std::vector<LLVM::Value> Payload(Arity);
1296
2
  for (uint32_t I = 0; I < Arity; ++I) {
1297
0
    Payload[Arity - 1 - I] = stackPop();
1298
0
  }
1299
2
  LLVM::Value Vals = Builder.createArray(Arity, LLVM::kValSize);
1300
2
  Builder.createArrayPtrStore(Payload, Vals, Context.Int8Ty, LLVM::kValSize);
1301
1302
2
  Builder.createCall(
1303
2
      Context.getIntrinsic(
1304
2
          Builder, Executable::Intrinsics::kThrow,
1305
2
          LLVM::Type::getFunctionType(
1306
2
              Context.VoidTy,
1307
2
              {Context.Int32Ty, Context.Int8PtrTy, Context.Int32Ty}, false)),
1308
2
      {LLContext.getInt32(TagIndex), Vals, LLContext.getInt32(Arity)});
1309
1310
2
  Builder.createBr(getEHDispatchTarget());
1311
2
  setUnreachable();
1312
2
  Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "throw.end"));
1313
2
}
1314
1315
3
void FunctionCompiler::compileThrowRefOp() noexcept {
1316
3
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1317
3
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "throw_ref.ok");
1318
3
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1319
3
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1320
3
      LLContext.getInt64(0)));
1321
3
  Builder.createCondBr(IsRefNotNull, OkBB,
1322
3
                       getTrapBB(ErrCode::Value::AccessNullException));
1323
3
  Builder.positionAtEnd(OkBB);
1324
1325
3
  Builder.createCall(
1326
3
      Context.getIntrinsic(Builder, Executable::Intrinsics::kThrowRef,
1327
3
                           LLVM::Type::getFunctionType(
1328
3
                               Context.VoidTy, {Context.Int64x2Ty}, false)),
1329
3
      {Ref});
1330
1331
3
  Builder.createBr(getEHDispatchTarget());
1332
3
  setUnreachable();
1333
3
  Builder.positionAtEnd(
1334
3
      LLVM::BasicBlock::create(LLContext, F.Fn, "throw_ref.end"));
1335
3
}
1336
1337
3.02k
void FunctionCompiler::compileCallOp(const unsigned int FuncIndex) noexcept {
1338
3.02k
  const auto &FuncType =
1339
3.02k
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1340
3.02k
          ->getFuncType();
1341
3.02k
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1342
3.02k
  const auto &ParamTypes = FuncType.getParamTypes();
1343
1344
3.02k
  std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
1345
3.02k
  Args[0] = F.Fn.getFirstParam();
1346
3.88k
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1347
853
    const size_t J = ParamTypes.size() - 1 - I;
1348
853
    Args[J + 1] = stackPop();
1349
853
  }
1350
1351
3.02k
  LLVM::Value Ret;
1352
3.02k
  if (IsLazyJIT) {
1353
0
    bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1354
0
    if (IsImport) {
1355
0
      Ret = Builder.createCall(Function, Args);
1356
0
    } else {
1357
0
      auto FTy = toLLVMType(LLContext, Context.ExecCtxPtrTy, FuncType);
1358
1359
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1360
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1361
0
      }
1362
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1363
0
      if (!CacheVar) {
1364
0
        CacheVar = Context.LLModule.get().addGlobal(
1365
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1366
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1367
0
      }
1368
1369
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.check");
1370
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.resolve");
1371
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.call");
1372
1373
0
      Builder.createBr(CheckBB);
1374
0
      Builder.positionAtEnd(CheckBB);
1375
1376
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1377
0
      CachedPtr.setAlignment(8);
1378
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1379
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1380
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1381
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1382
1383
0
      Builder.positionAtEnd(ResolveBB);
1384
0
      auto FPtr = Builder.createCall(
1385
0
          Context.getIntrinsic(
1386
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1387
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int32Ty},
1388
0
                                          false)),
1389
0
          {LLContext.getInt32(FuncIndex)});
1390
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1391
0
      Store.setAlignment(8);
1392
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1393
0
      Builder.createBr(CallBB);
1394
1395
0
      Builder.positionAtEnd(CallBB);
1396
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1397
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1398
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1399
1400
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1401
0
    }
1402
3.02k
  } else {
1403
3.02k
    Ret = Builder.createCall(Function, Args);
1404
3.02k
  }
1405
1406
3.02k
  auto Ty = Ret.getType();
1407
3.02k
  if (Ty.isVoidTy()) {
1408
    // nothing to do
1409
1.63k
  } else if (Ty.isStructTy()) {
1410
171
    for (auto Val : unpackStruct(Builder, Ret)) {
1411
171
      stackPush(Val);
1412
171
    }
1413
1.31k
  } else {
1414
1.31k
    stackPush(Ret);
1415
1.31k
  }
1416
1417
3.02k
  checkPendingException();
1418
3.02k
}
1419
1420
void FunctionCompiler::compileIndirectCallOp(
1421
858
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1422
858
  auto TryFastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.tryfast");
1423
858
  auto NonNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.nonnull");
1424
858
  auto FastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.fast");
1425
858
  auto SlowBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.slow");
1426
858
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1427
858
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1428
858
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1429
1430
858
  LLVM::Value FuncIndex = stackPop();
1431
858
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1432
858
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1433
858
  auto RTy = FTy.getReturnType();
1434
858
  auto FPtrTy = FTy.getPointerTo();
1435
858
  auto TableIdx = LLContext.getInt32(TableIndex);
1436
858
  auto TypeIdx = LLContext.getInt32(FuncTypeIndex);
1437
1438
858
  const size_t ArgSize = FuncType.getParamTypes().size();
1439
858
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1440
858
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1441
858
  ArgsVec[0] = F.Fn.getFirstParam();
1442
1.54k
  for (size_t I = 0; I < ArgSize; ++I) {
1443
691
    const size_t J = ArgSize - I;
1444
691
    ArgsVec[J] = stackPop();
1445
691
  }
1446
1.71k
  auto UnpackRets = [&](LLVM::Value Ret) -> std::vector<LLVM::Value> {
1447
1.71k
    if (RetSize == 0) {
1448
440
      return {};
1449
1.27k
    } else if (RetSize == 1) {
1450
1.24k
      return {Ret};
1451
1.24k
    } else {
1452
32
      return unpackStruct(Builder, Ret);
1453
32
    }
1454
1.71k
  };
1455
1456
858
  auto Idx64 = Builder.createZExt(FuncIndex, Context.Int64Ty);
1457
1458
  // Fast path: an in-bounds funcref defined in the running module with the
1459
  // call site's type index and compiled code is called directly.
1460
858
  std::vector<LLVM::Value> FastRetsVec;
1461
858
  {
1462
858
    Builder.createCondBr(
1463
858
        Builder.createLikely(Builder.createICmpULT(
1464
858
            Idx64, Context.getTableSize(Builder, ExecCtx, TableIndex))),
1465
858
        TryFastBB, SlowBB);
1466
858
    Builder.positionAtEnd(TryFastBB);
1467
1468
858
    auto FuncRef = Builder.createLoad(
1469
858
        Context.Int64x2Ty,
1470
858
        Builder.createInBoundsGEP1(
1471
858
            Context.Int64x2Ty, Context.getTable(Builder, ExecCtx, TableIndex),
1472
858
            Idx64));
1473
858
    auto FuncInstInt =
1474
858
        Builder.createExtractElement(FuncRef, LLContext.getInt64(1));
1475
858
    Builder.createCondBr(Builder.createLikely(Builder.createICmpNE(
1476
858
                             FuncInstInt, LLContext.getInt64(0))),
1477
858
                         NonNullBB, SlowBB);
1478
858
    Builder.positionAtEnd(NonNullBB);
1479
1480
858
    auto FuncInstPtr = Builder.createIntToPtr(FuncInstInt, Context.Int8PtrTy);
1481
2.57k
    auto LoadField = [&](uint64_t Off, LLVM::Type Ty) {
1482
2.57k
      return Builder.createLoad(
1483
2.57k
          Ty, Builder.createBitCast(
1484
2.57k
                  Builder.createInBoundsGEP1(Context.Int8Ty, FuncInstPtr,
1485
2.57k
                                             LLContext.getInt64(Off)),
1486
2.57k
                  Ty.getPointerTo()));
1487
2.57k
    };
1488
858
    using Runtime::Instance::FunctionInstance;
1489
858
    auto DefModule =
1490
858
        LoadField(FunctionInstance::getModuleOffset(), Context.Int8PtrTy);
1491
858
    auto CalleeTypeIdx =
1492
858
        LoadField(FunctionInstance::getTypeIndexOffset(), Context.Int32Ty);
1493
858
    auto Code =
1494
858
        LoadField(FunctionInstance::getCompiledCodeOffset(), Context.Int8PtrTy);
1495
858
    auto Hit = Builder.createAnd(
1496
858
        Builder.createAnd(
1497
858
            Builder.createICmpEQ(DefModule,
1498
858
                                 Context.getModuleInst(Builder, ExecCtx)),
1499
858
            Builder.createICmpEQ(CalleeTypeIdx, TypeIdx)),
1500
858
        Builder.createNot(Builder.createIsNull(Code)));
1501
858
    Builder.createCondBr(Builder.createLikely(Hit), FastBB, SlowBB);
1502
1503
858
    Builder.positionAtEnd(FastBB);
1504
858
    auto FastRet = Builder.createCall(
1505
858
        LLVM::FunctionCallee{FTy, Builder.createBitCast(Code, FPtrTy)},
1506
858
        ArgsVec);
1507
858
    FastRetsVec = UnpackRets(FastRet);
1508
858
    Builder.createBr(EndBB);
1509
858
  }
1510
1511
  // Slow path: resolve through the runtime, which handles cross-module, host,
1512
  // subtype, uninitialized, and not-yet-compiled cases.
1513
858
  Builder.positionAtEnd(SlowBB);
1514
858
  std::vector<LLVM::Value> FPtrRetsVec;
1515
858
  {
1516
858
    auto FPtr = Builder.createCall(
1517
858
        Context.getIntrinsic(
1518
858
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1519
858
            LLVM::Type::getFunctionType(
1520
858
                FPtrTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty},
1521
858
                false)),
1522
858
        {TableIdx, TypeIdx, FuncIndex});
1523
858
    Builder.createCondBr(
1524
858
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1525
858
        NotNullBB, IsNullBB);
1526
858
    Builder.positionAtEnd(NotNullBB);
1527
1528
858
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
1529
858
    FPtrRetsVec = UnpackRets(FPtrRet);
1530
858
  }
1531
1532
858
  Builder.createBr(EndBB);
1533
858
  Builder.positionAtEnd(IsNullBB);
1534
1535
858
  std::vector<LLVM::Value> RetsVec;
1536
858
  {
1537
858
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1538
858
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1539
858
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1540
858
                                Args, Context.Int8Ty, LLVM::kValSize);
1541
1542
858
    Builder.createCall(
1543
858
        Context.getIntrinsic(
1544
858
            Builder, Executable::Intrinsics::kCallIndirect,
1545
858
            LLVM::Type::getFunctionType(Context.VoidTy,
1546
858
                                        {Context.Int32Ty, Context.Int32Ty,
1547
858
                                         Context.Int32Ty, Context.Int8PtrTy,
1548
858
                                         Context.Int8PtrTy},
1549
858
                                        false)),
1550
858
        {TableIdx, TypeIdx, FuncIndex, Args, Rets});
1551
1552
858
    if (RetSize == 0) {
1553
      // nothing to do
1554
638
    } else if (RetSize == 1) {
1555
622
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1556
622
    } else {
1557
16
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1558
16
                                           LLVM::kValSize);
1559
16
    }
1560
858
    Builder.createBr(EndBB);
1561
858
    Builder.positionAtEnd(EndBB);
1562
858
  }
1563
1564
1.51k
  for (unsigned I = 0; I < RetSize; ++I) {
1565
654
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1566
654
    PHIRet.addIncoming(FastRetsVec[I], FastBB);
1567
654
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1568
654
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1569
654
    stackPush(PHIRet);
1570
654
  }
1571
1572
858
  checkPendingException();
1573
858
}
1574
1575
void FunctionCompiler::compileReturnCallOp(
1576
65
    const unsigned int FuncIndex) noexcept {
1577
65
  const auto &FuncType =
1578
65
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1579
65
          ->getFuncType();
1580
65
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1581
65
  const auto &ParamTypes = FuncType.getParamTypes();
1582
1583
65
  std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
1584
65
  Args[0] = F.Fn.getFirstParam();
1585
111
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1586
46
    const size_t J = ParamTypes.size() - 1 - I;
1587
46
    Args[J + 1] = stackPop();
1588
46
  }
1589
1590
65
  LLVM::Value Ret;
1591
65
  if (IsLazyJIT) {
1592
0
    bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1593
0
    if (IsImport) {
1594
0
      Ret = Builder.createCall(Function, Args);
1595
0
    } else {
1596
0
      auto FTy = toLLVMType(LLContext, Context.ExecCtxPtrTy, FuncType);
1597
1598
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1599
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1600
0
      }
1601
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1602
0
      if (!CacheVar) {
1603
0
        CacheVar = Context.LLModule.get().addGlobal(
1604
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1605
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1606
0
      }
1607
1608
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.check");
1609
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.resolve");
1610
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.call");
1611
1612
0
      Builder.createBr(CheckBB);
1613
0
      Builder.positionAtEnd(CheckBB);
1614
1615
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1616
0
      CachedPtr.setAlignment(8);
1617
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1618
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1619
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1620
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1621
1622
0
      Builder.positionAtEnd(ResolveBB);
1623
0
      auto FPtr = Builder.createCall(
1624
0
          Context.getIntrinsic(
1625
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1626
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int32Ty},
1627
0
                                          false)),
1628
0
          {LLContext.getInt32(FuncIndex)});
1629
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1630
0
      Store.setAlignment(8);
1631
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1632
0
      Builder.createBr(CallBB);
1633
1634
0
      Builder.positionAtEnd(CallBB);
1635
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1636
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1637
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1638
1639
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1640
0
    }
1641
65
  } else {
1642
65
    Ret = Builder.createCall(Function, Args);
1643
65
  }
1644
1645
65
  Ret.setMustTailCall();
1646
65
  auto Ty = Ret.getType();
1647
65
  if (Ty.isVoidTy()) {
1648
21
    Builder.createRetVoid();
1649
44
  } else {
1650
44
    Builder.createRet(Ret);
1651
44
  }
1652
65
}
1653
1654
void FunctionCompiler::compileReturnIndirectCallOp(
1655
120
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1656
120
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1657
120
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1658
1659
120
  LLVM::Value FuncIndex = stackPop();
1660
120
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1661
120
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1662
120
  auto RTy = FTy.getReturnType();
1663
1664
120
  const size_t ArgSize = FuncType.getParamTypes().size();
1665
120
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1666
120
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1667
120
  ArgsVec[0] = F.Fn.getFirstParam();
1668
239
  for (size_t I = 0; I < ArgSize; ++I) {
1669
119
    const size_t J = ArgSize - I;
1670
119
    ArgsVec[J] = stackPop();
1671
119
  }
1672
1673
120
  {
1674
120
    auto FPtr = Builder.createCall(
1675
120
        Context.getIntrinsic(
1676
120
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1677
120
            LLVM::Type::getFunctionType(
1678
120
                FTy.getPointerTo(),
1679
120
                {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)),
1680
120
        {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
1681
120
         FuncIndex});
1682
120
    Builder.createCondBr(
1683
120
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1684
120
        NotNullBB, IsNullBB);
1685
120
    Builder.positionAtEnd(NotNullBB);
1686
1687
120
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
1688
120
    FPtrRet.setMustTailCall();
1689
120
    if (RetSize == 0) {
1690
40
      Builder.createRetVoid();
1691
80
    } else {
1692
80
      Builder.createRet(FPtrRet);
1693
80
    }
1694
120
  }
1695
1696
120
  Builder.positionAtEnd(IsNullBB);
1697
1698
120
  {
1699
120
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1700
120
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1701
120
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1702
120
                                Args, Context.Int8Ty, LLVM::kValSize);
1703
1704
120
    Builder.createCall(
1705
120
        Context.getIntrinsic(
1706
120
            Builder, Executable::Intrinsics::kCallIndirect,
1707
120
            LLVM::Type::getFunctionType(Context.VoidTy,
1708
120
                                        {Context.Int32Ty, Context.Int32Ty,
1709
120
                                         Context.Int32Ty, Context.Int8PtrTy,
1710
120
                                         Context.Int8PtrTy},
1711
120
                                        false)),
1712
120
        {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
1713
120
         FuncIndex, Args, Rets});
1714
1715
120
    if (RetSize == 0) {
1716
40
      Builder.createRetVoid();
1717
80
    } else if (RetSize == 1) {
1718
71
      Builder.createRet(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1719
71
    } else {
1720
9
      Builder.createAggregateRet(Builder.createArrayPtrLoad(
1721
9
          RetSize, RTy, Rets, Context.Int8Ty, LLVM::kValSize));
1722
9
    }
1723
120
  }
1724
120
}
1725
1726
275
void FunctionCompiler::compileCallRefOp(const unsigned int TypeIndex) noexcept {
1727
275
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1728
275
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
1729
275
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1730
1731
275
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1732
275
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
1733
275
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1734
275
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1735
275
      LLContext.getInt64(0)));
1736
275
  Builder.createCondBr(IsRefNotNull, OkBB,
1737
275
                       getTrapBB(ErrCode::Value::AccessNullFunc));
1738
275
  Builder.positionAtEnd(OkBB);
1739
1740
275
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
1741
275
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1742
275
  auto RTy = FTy.getReturnType();
1743
1744
275
  const size_t ArgSize = FuncType.getParamTypes().size();
1745
275
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1746
275
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1747
275
  ArgsVec[0] = F.Fn.getFirstParam();
1748
536
  for (size_t I = 0; I < ArgSize; ++I) {
1749
261
    const size_t J = ArgSize - I;
1750
261
    ArgsVec[J] = stackPop();
1751
261
  }
1752
1753
275
  std::vector<LLVM::Value> FPtrRetsVec;
1754
275
  FPtrRetsVec.reserve(RetSize);
1755
275
  {
1756
275
    auto FPtr = Builder.createCall(
1757
275
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1758
275
                             LLVM::Type::getFunctionType(FTy.getPointerTo(),
1759
275
                                                         {Context.Int64x2Ty},
1760
275
                                                         false)),
1761
275
        {Ref});
1762
275
    Builder.createCondBr(
1763
275
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1764
275
        NotNullBB, IsNullBB);
1765
275
    Builder.positionAtEnd(NotNullBB);
1766
1767
275
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
1768
275
    if (RetSize == 0) {
1769
      // nothing to do
1770
156
    } else if (RetSize == 1) {
1771
107
      FPtrRetsVec.push_back(FPtrRet);
1772
107
    } else {
1773
24
      for (auto Val : unpackStruct(Builder, FPtrRet)) {
1774
24
        FPtrRetsVec.push_back(Val);
1775
24
      }
1776
12
    }
1777
275
  }
1778
1779
275
  Builder.createBr(EndBB);
1780
275
  Builder.positionAtEnd(IsNullBB);
1781
1782
275
  std::vector<LLVM::Value> RetsVec;
1783
275
  {
1784
275
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1785
275
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1786
275
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1787
275
                                Args, Context.Int8Ty, LLVM::kValSize);
1788
1789
275
    Builder.createCall(
1790
275
        Context.getIntrinsic(
1791
275
            Builder, Executable::Intrinsics::kCallRef,
1792
275
            LLVM::Type::getFunctionType(
1793
275
                Context.VoidTy,
1794
275
                {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
1795
275
                false)),
1796
275
        {Ref, Args, Rets});
1797
1798
275
    if (RetSize == 0) {
1799
      // nothing to do
1800
156
    } else if (RetSize == 1) {
1801
107
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1802
107
    } else {
1803
12
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1804
12
                                           LLVM::kValSize);
1805
12
    }
1806
275
    Builder.createBr(EndBB);
1807
275
    Builder.positionAtEnd(EndBB);
1808
275
  }
1809
1810
406
  for (unsigned I = 0; I < RetSize; ++I) {
1811
131
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1812
131
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1813
131
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1814
131
    stackPush(PHIRet);
1815
131
  }
1816
1817
275
  checkPendingException();
1818
275
}
1819
1820
void FunctionCompiler::compileReturnCallRefOp(
1821
58
    const unsigned int TypeIndex) noexcept {
1822
58
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1823
58
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
1824
1825
58
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1826
58
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
1827
58
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1828
58
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1829
58
      LLContext.getInt64(0)));
1830
58
  Builder.createCondBr(IsRefNotNull, OkBB,
1831
58
                       getTrapBB(ErrCode::Value::AccessNullFunc));
1832
58
  Builder.positionAtEnd(OkBB);
1833
1834
58
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
1835
58
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1836
58
  auto RTy = FTy.getReturnType();
1837
1838
58
  const size_t ArgSize = FuncType.getParamTypes().size();
1839
58
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1840
58
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1841
58
  ArgsVec[0] = F.Fn.getFirstParam();
1842
97
  for (size_t I = 0; I < ArgSize; ++I) {
1843
39
    const size_t J = ArgSize - I;
1844
39
    ArgsVec[J] = stackPop();
1845
39
  }
1846
1847
58
  {
1848
58
    auto FPtr = Builder.createCall(
1849
58
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1850
58
                             LLVM::Type::getFunctionType(FTy.getPointerTo(),
1851
58
                                                         {Context.Int64x2Ty},
1852
58
                                                         false)),
1853
58
        {Ref});
1854
58
    Builder.createCondBr(
1855
58
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1856
58
        NotNullBB, IsNullBB);
1857
58
    Builder.positionAtEnd(NotNullBB);
1858
1859
58
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
1860
58
    FPtrRet.setMustTailCall();
1861
58
    if (RetSize == 0) {
1862
21
      Builder.createRetVoid();
1863
37
    } else {
1864
37
      Builder.createRet(FPtrRet);
1865
37
    }
1866
58
  }
1867
1868
58
  Builder.positionAtEnd(IsNullBB);
1869
1870
58
  {
1871
58
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1872
58
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1873
58
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1874
58
                                Args, Context.Int8Ty, LLVM::kValSize);
1875
1876
58
    Builder.createCall(
1877
58
        Context.getIntrinsic(
1878
58
            Builder, Executable::Intrinsics::kCallRef,
1879
58
            LLVM::Type::getFunctionType(
1880
58
                Context.VoidTy,
1881
58
                {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
1882
58
                false)),
1883
58
        {Ref, Args, Rets});
1884
1885
58
    if (RetSize == 0) {
1886
21
      Builder.createRetVoid();
1887
37
    } else if (RetSize == 1) {
1888
34
      Builder.createRet(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1889
34
    } else {
1890
3
      Builder.createAggregateRet(Builder.createArrayPtrLoad(
1891
3
          RetSize, RTy, Rets, Context.Int8Ty, LLVM::kValSize));
1892
3
    }
1893
58
  }
1894
58
}
1895
1896
void FunctionCompiler::enterBlock(
1897
    LLVM::BasicBlock JumpBlock, LLVM::BasicBlock NextBlock,
1898
    LLVM::BasicBlock ElseBlock, std::vector<LLVM::Value> Args,
1899
    std::pair<std::vector<ValType>, std::vector<ValType>> Type,
1900
    std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
1901
21.6k
        ReturnPHI) noexcept {
1902
21.6k
  assuming(Type.first.size() == Args.size());
1903
21.6k
  for (auto &Value : Args) {
1904
4.60k
    stackPush(Value);
1905
4.60k
  }
1906
21.6k
  const auto Unreachable = isUnreachable();
1907
21.6k
  ControlStack.emplace_back(Stack.size() - Args.size(), Unreachable, JumpBlock,
1908
21.6k
                            NextBlock, ElseBlock, std::move(Args),
1909
21.6k
                            std::move(Type), std::move(ReturnPHI));
1910
21.6k
}
1911
1912
21.6k
FunctionCompiler::Control FunctionCompiler::leaveBlock() noexcept {
1913
21.6k
  Control Entry = std::move(ControlStack.back());
1914
21.6k
  ControlStack.pop_back();
1915
1916
21.6k
  auto NextBlock = Entry.NextBlock ? Entry.NextBlock : Entry.JumpBlock;
1917
21.6k
  if (!Entry.Unreachable) {
1918
12.7k
    const auto &ReturnType = Entry.Type.second;
1919
12.7k
    if (!ReturnType.empty()) {
1920
9.62k
      std::vector<LLVM::Value> Rets(ReturnType.size());
1921
19.6k
      for (size_t I = 0; I < Rets.size(); ++I) {
1922
10.0k
        const size_t J = Rets.size() - 1 - I;
1923
10.0k
        Rets[J] = stackPop();
1924
10.0k
      }
1925
9.62k
      Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
1926
9.62k
    }
1927
12.7k
    Builder.createBr(NextBlock);
1928
12.7k
  } else {
1929
8.94k
    Builder.createUnreachable();
1930
8.94k
  }
1931
21.6k
  Builder.positionAtEnd(NextBlock);
1932
21.6k
  Stack.erase(Stack.begin() + static_cast<int64_t>(Entry.StackSize),
1933
21.6k
              Stack.end());
1934
21.6k
  return Entry;
1935
21.6k
}
1936
1937
5.49k
void FunctionCompiler::checkStop() noexcept {
1938
5.49k
  if (!Interruptible) {
1939
5.49k
    return;
1940
5.49k
  }
1941
0
  auto NotStopBB = LLVM::BasicBlock::create(LLContext, F.Fn, "NotStop");
1942
0
  auto StopToken = Builder.createAtomicRMW(
1943
0
      LLVMAtomicRMWBinOpXchg, Context.getStopToken(Builder, ExecCtx),
1944
0
      LLContext.getInt32(0), LLVMAtomicOrderingMonotonic);
1945
#if LLVM_VERSION_MAJOR >= 13
1946
  StopToken.setAlignment(32);
1947
#endif
1948
0
  auto NotStop = Builder.createLikely(
1949
0
      Builder.createICmpEQ(StopToken, LLContext.getInt32(0)));
1950
0
  Builder.createCondBr(NotStop, NotStopBB,
1951
0
                       getTrapBB(ErrCode::Value::Interrupted));
1952
1953
0
  Builder.positionAtEnd(NotStopBB);
1954
0
}
1955
1956
4.16k
void FunctionCompiler::checkPendingException() noexcept {
1957
4.16k
  auto PendingTagInst = Builder.createLoad(
1958
4.16k
      Context.Int8PtrTy, Context.getPendingExnTagAddr(Builder, ExecCtx));
1959
4.16k
  auto NotPendingBB =
1960
4.16k
      LLVM::BasicBlock::create(LLContext, F.Fn, "no_pending_exn");
1961
4.16k
  auto NotPending = Builder.createLikely(Builder.createIsNull(PendingTagInst));
1962
4.16k
  Builder.createCondBr(NotPending, NotPendingBB, getEHDispatchTarget());
1963
4.16k
  Builder.positionAtEnd(NotPendingBB);
1964
4.16k
}
1965
1966
6.06k
void FunctionCompiler::setUnreachable() noexcept {
1967
6.06k
  if (ControlStack.empty()) {
1968
0
    IsUnreachable = true;
1969
6.06k
  } else {
1970
6.06k
    ControlStack.back().Unreachable = true;
1971
6.06k
  }
1972
6.06k
}
1973
1974
1.57M
bool FunctionCompiler::isUnreachable() const noexcept {
1975
1.57M
  if (ControlStack.empty()) {
1976
10.3k
    return IsUnreachable;
1977
1.56M
  } else {
1978
1.56M
    return ControlStack.back().Unreachable;
1979
1.56M
  }
1980
1.57M
}
1981
1982
void FunctionCompiler::buildPHI(
1983
    Span<const ValType> RetType,
1984
    Span<const std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
1985
18.7k
        Incomings) noexcept {
1986
18.7k
  if (LLVM::isVoidReturn(RetType)) {
1987
6.08k
    return;
1988
6.08k
  }
1989
12.6k
  std::vector<LLVM::Value> Nodes;
1990
12.6k
  if (Incomings.size() == 0) {
1991
3.00k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
1992
3.00k
    Nodes.reserve(Types.size());
1993
3.45k
    for (LLVM::Type Type : Types) {
1994
3.45k
      Nodes.push_back(LLVM::Value::getUndef(Type));
1995
3.45k
    }
1996
9.68k
  } else if (Incomings.size() == 1) {
1997
8.63k
    Nodes = std::move(std::get<0>(Incomings.front()));
1998
8.63k
  } else {
1999
1.04k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
2000
1.04k
    Nodes.reserve(Types.size());
2001
2.18k
    for (size_t I = 0; I < Types.size(); ++I) {
2002
1.13k
      auto PHIRet = Builder.createPHI(Types[I]);
2003
2.96k
      for (auto &[Value, BB] : Incomings) {
2004
2.96k
        assuming(Value.size() == Types.size());
2005
2.96k
        PHIRet.addIncoming(Value[I], BB);
2006
2.96k
      }
2007
1.13k
      Nodes.push_back(PHIRet);
2008
1.13k
    }
2009
1.04k
  }
2010
13.5k
  for (auto &Val : Nodes) {
2011
13.5k
    stackPush(Val);
2012
13.5k
  }
2013
12.6k
}
2014
2015
21.3k
void FunctionCompiler::setLableJumpPHI(unsigned int Index) noexcept {
2016
21.3k
  assuming(Index < ControlStack.size());
2017
21.3k
  auto &Entry = *(ControlStack.rbegin() + Index);
2018
21.3k
  if (Entry.NextBlock) { // is loop
2019
2.24k
    std::vector<LLVM::Value> Args(Entry.Type.first.size());
2020
4.86k
    for (size_t I = 0; I < Args.size(); ++I) {
2021
2.62k
      const size_t J = Args.size() - 1 - I;
2022
2.62k
      Args[J] = stackPop();
2023
2.62k
    }
2024
4.86k
    for (size_t I = 0; I < Args.size(); ++I) {
2025
2.62k
      Entry.Args[I].addIncoming(Args[I], Builder.getInsertBlock());
2026
2.62k
      stackPush(Args[I]);
2027
2.62k
    }
2028
19.0k
  } else if (!Entry.Type.second.empty()) { // has return value
2029
1.80k
    std::vector<LLVM::Value> Rets(Entry.Type.second.size());
2030
3.71k
    for (size_t I = 0; I < Rets.size(); ++I) {
2031
1.91k
      const size_t J = Rets.size() - 1 - I;
2032
1.91k
      Rets[J] = stackPop();
2033
1.91k
    }
2034
3.71k
    for (size_t I = 0; I < Rets.size(); ++I) {
2035
1.91k
      stackPush(Rets[I]);
2036
1.91k
    }
2037
1.80k
    Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
2038
1.80k
  }
2039
21.3k
}
2040
2041
21.3k
LLVM::BasicBlock FunctionCompiler::getLabel(unsigned int Index) const noexcept {
2042
21.3k
  return (ControlStack.rbegin() + Index)->JumpBlock;
2043
21.3k
}
2044
2045
4.16k
LLVM::BasicBlock FunctionCompiler::getEHDispatchTarget() noexcept {
2046
10.4k
  for (auto It = ControlStack.rbegin(); It != ControlStack.rend(); ++It) {
2047
6.25k
    if (It->TryDispatchBB) {
2048
0
      return It->TryDispatchBB;
2049
0
    }
2050
6.25k
  }
2051
4.16k
  if (!UnwindBB) {
2052
1.78k
    UnwindBB = LLVM::BasicBlock::create(LLContext, F.Fn, "exn.unwind");
2053
1.78k
  }
2054
4.16k
  return UnwindBB;
2055
4.16k
}
2056
2057
345k
LLVM::Value FunctionCompiler::stackPop() noexcept {
2058
345k
  assuming(!ControlStack.empty() || !Stack.empty());
2059
345k
  assuming(ControlStack.empty() ||
2060
345k
           Stack.size() > ControlStack.back().StackSize);
2061
345k
  auto Value = Stack.back();
2062
345k
  Stack.pop_back();
2063
345k
  return Value;
2064
345k
}
2065
2066
21.7k
LLVM::Value FunctionCompiler::switchEndian(LLVM::Value Value) {
2067
  if constexpr (Endian::native == Endian::big) {
2068
    auto Type = Value.getType();
2069
    if ((Type.isIntegerTy() && Type.getIntegerBitWidth() > 8) ||
2070
        (Type.isVectorTy() && Type.getVectorSize() == 1)) {
2071
      return Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2072
    }
2073
    if (Type.isVectorTy()) {
2074
      LLVM::Type VecType = Type.getElementType().getIntegerBitWidth() == 128
2075
                               ? Context.Int128Ty
2076
                               : Context.Int64Ty;
2077
      Value = Builder.createBitCast(Value, VecType);
2078
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2079
      return Builder.createBitCast(Value, Type);
2080
    }
2081
    if (Type.isFloatTy() || Type.isDoubleTy()) {
2082
      LLVM::Type IntType = Type.isFloatTy() ? Context.Int32Ty : Context.Int64Ty;
2083
      Value = Builder.createBitCast(Value, IntType);
2084
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
2085
      return Builder.createBitCast(Value, Type);
2086
    }
2087
  }
2088
21.7k
  return Value;
2089
21.7k
}
2090
2091
} // namespace WasmEdge