Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler/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.5k
    : Context(Context), LLContext(Context.LLContext),
22
10.5k
      Interruptible(Interruptible), IsLazyJIT(IsLazyJIT), F(F),
23
10.5k
      Builder(LLContext) {
24
10.5k
  if (F.Fn) {
25
10.5k
    Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "entry"));
26
10.5k
    ExecCtx = Builder.createLoad(Context.ExecCtxTy, F.Fn.getFirstParam());
27
28
10.5k
    if (InstructionCounting) {
29
0
      LocalInstrCount = Builder.createAlloca(Context.Int64Ty);
30
0
      Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
31
0
    }
32
33
10.5k
    if (GasMeasuring) {
34
0
      LocalGas = Builder.createAlloca(Context.Int64Ty);
35
0
      Builder.createStore(LLContext.getInt64(0), LocalGas);
36
0
    }
37
38
19.8k
    for (LLVM::Value Arg = F.Fn.getFirstParam().getNextParam(); Arg;
39
10.5k
         Arg = Arg.getNextParam()) {
40
9.34k
      LLVM::Type Ty = Arg.getType();
41
9.34k
      LLVM::Value ArgPtr = Builder.createAlloca(Ty);
42
9.34k
      Builder.createStore(Arg, ArgPtr);
43
9.34k
      Local.emplace_back(Ty, ArgPtr);
44
9.34k
    }
45
46
665k
    for (const auto &Type : Locals) {
47
665k
      LLVM::Type Ty = toLLVMType(LLContext, Type);
48
665k
      LLVM::Value ArgPtr = Builder.createAlloca(Ty);
49
665k
      Builder.createStore(
50
665k
          toLLVMConstantZero(LLContext, Type, Context.CompositeTypes), ArgPtr);
51
665k
      Local.emplace_back(Ty, ArgPtr);
52
665k
    }
53
10.5k
  }
54
10.5k
}
55
56
29.5k
LLVM::BasicBlock FunctionCompiler::getTrapBB(ErrCode::Value Error) noexcept {
57
29.5k
  if (auto Iter = TrapBB.find(Error); Iter != TrapBB.end()) {
58
26.3k
    return Iter->second;
59
26.3k
  }
60
3.17k
  auto BB = LLVM::BasicBlock::create(LLContext, F.Fn, "trap");
61
3.17k
  TrapBB.emplace(Error, BB);
62
3.17k
  return BB;
63
29.5k
}
64
65
Expect<void> FunctionCompiler::compile(
66
    const AST::CodeSegment &Code,
67
10.5k
    std::pair<std::vector<ValType>, std::vector<ValType>> Type) noexcept {
68
10.5k
  auto RetBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ret");
69
10.5k
  Type.first.clear();
70
10.5k
  enterBlock(RetBB, {}, {}, {}, std::move(Type));
71
10.5k
  EXPECTED_TRY(compile(Code.getExpr().getInstrs()));
72
10.5k
  assuming(ControlStack.empty());
73
10.5k
  compileReturn();
74
75
10.5k
  for (auto &[Error, BB] : TrapBB) {
76
3.16k
    Builder.positionAtEnd(BB);
77
3.16k
    updateInstrCount();
78
3.16k
    updateGasAtTrap();
79
3.16k
    auto CallTrap = Builder.createCall(
80
3.16k
        Context.Trap, {LLContext.getInt32(static_cast<uint32_t>(Error))});
81
3.16k
    CallTrap.addCallSiteAttribute(Context.NoReturn);
82
3.16k
    Builder.createUnreachable();
83
3.16k
  }
84
10.5k
  return {};
85
10.5k
}
86
87
10.5k
Expect<void> FunctionCompiler::compile(AST::InstrView Instrs) noexcept {
88
1.48M
  auto Dispatch = [this](const AST::Instruction &Instr) -> Expect<void> {
89
1.48M
    switch (Instr.getOpCode()) {
90
    // Control instructions (for blocks)
91
3.34k
    case OpCode::Block: {
92
3.34k
      auto Block = LLVM::BasicBlock::create(LLContext, F.Fn, "block");
93
3.34k
      auto EndBlock = LLVM::BasicBlock::create(LLContext, F.Fn, "block.end");
94
3.34k
      Builder.createBr(Block);
95
96
3.34k
      Builder.positionAtEnd(Block);
97
3.34k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
98
3.34k
      const auto Arity = Type.first.size();
99
3.34k
      std::vector<LLVM::Value> Args(Arity);
100
3.34k
      if (isUnreachable()) {
101
1.05k
        for (size_t I = 0; I < Arity; ++I) {
102
287
          auto Ty = toLLVMType(LLContext, Type.first[I]);
103
287
          Args[I] = LLVM::Value::getUndef(Ty);
104
287
        }
105
2.57k
      } else {
106
2.95k
        for (size_t I = 0; I < Arity; ++I) {
107
374
          const size_t J = Arity - 1 - I;
108
374
          Args[J] = stackPop();
109
374
        }
110
2.57k
      }
111
3.34k
      enterBlock(EndBlock, {}, {}, std::move(Args), std::move(Type));
112
3.34k
      checkStop();
113
3.34k
      updateGas();
114
3.34k
      return {};
115
0
    }
116
1.94k
    case OpCode::Loop: {
117
1.94k
      auto Curr = Builder.getInsertBlock();
118
1.94k
      auto Loop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop");
119
1.94k
      auto EndLoop = LLVM::BasicBlock::create(LLContext, F.Fn, "loop.end");
120
1.94k
      Builder.createBr(Loop);
121
122
1.94k
      Builder.positionAtEnd(Loop);
123
1.94k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
124
1.94k
      const auto Arity = Type.first.size();
125
1.94k
      std::vector<LLVM::Value> Args(Arity);
126
1.94k
      if (isUnreachable()) {
127
1.03k
        for (size_t I = 0; I < Arity; ++I) {
128
405
          auto Ty = toLLVMType(LLContext, Type.first[I]);
129
405
          auto Value = LLVM::Value::getUndef(Ty);
130
405
          auto PHINode = Builder.createPHI(Ty);
131
405
          PHINode.addIncoming(Value, Curr);
132
405
          Args[I] = PHINode;
133
405
        }
134
1.32k
      } else {
135
1.99k
        for (size_t I = 0; I < Arity; ++I) {
136
672
          const size_t J = Arity - 1 - I;
137
672
          auto Value = stackPop();
138
672
          auto PHINode = Builder.createPHI(Value.getType());
139
672
          PHINode.addIncoming(Value, Curr);
140
672
          Args[J] = PHINode;
141
672
        }
142
1.32k
      }
143
1.94k
      enterBlock(Loop, EndLoop, {}, std::move(Args), std::move(Type));
144
1.94k
      checkStop();
145
1.94k
      updateGas();
146
1.94k
      return {};
147
0
    }
148
2.76k
    case OpCode::If: {
149
2.76k
      auto Then = LLVM::BasicBlock::create(LLContext, F.Fn, "then");
150
2.76k
      auto Else = LLVM::BasicBlock::create(LLContext, F.Fn, "else");
151
2.76k
      auto EndIf = LLVM::BasicBlock::create(LLContext, F.Fn, "if.end");
152
2.76k
      LLVM::Value Cond;
153
2.76k
      if (isUnreachable()) {
154
637
        Cond = LLVM::Value::getUndef(LLContext.getInt1Ty());
155
2.13k
      } else {
156
2.13k
        Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
157
2.13k
      }
158
2.76k
      Builder.createCondBr(Cond, Then, Else);
159
160
2.76k
      Builder.positionAtEnd(Then);
161
2.76k
      auto Type = Context.resolveBlockType(Instr.getBlockType());
162
2.76k
      const auto Arity = Type.first.size();
163
2.76k
      std::vector<LLVM::Value> Args(Arity);
164
2.76k
      if (isUnreachable()) {
165
1.09k
        for (size_t I = 0; I < Arity; ++I) {
166
457
          auto Ty = toLLVMType(LLContext, Type.first[I]);
167
457
          Args[I] = LLVM::Value::getUndef(Ty);
168
457
        }
169
2.13k
      } else {
170
2.94k
        for (size_t I = 0; I < Arity; ++I) {
171
814
          const size_t J = Arity - 1 - I;
172
814
          Args[J] = stackPop();
173
814
        }
174
2.13k
      }
175
2.76k
      enterBlock(EndIf, {}, Else, std::move(Args), std::move(Type));
176
2.76k
      return {};
177
0
    }
178
7
    case OpCode::Try_table:
179
      // TODO: EXCEPTION - implement the AOT.
180
7
      return Unexpect(ErrCode::Value::AOTNotImpl);
181
18.5k
    case OpCode::End: {
182
18.5k
      auto Entry = leaveBlock();
183
18.5k
      if (Entry.ElseBlock) {
184
1.27k
        auto Block = Builder.getInsertBlock();
185
1.27k
        Builder.positionAtEnd(Entry.ElseBlock);
186
1.27k
        enterBlock(Block, {}, {}, std::move(Entry.Args), std::move(Entry.Type),
187
1.27k
                   std::move(Entry.ReturnPHI));
188
1.27k
        Entry = leaveBlock();
189
1.27k
      }
190
18.5k
      buildPHI(Entry.Type.second, Entry.ReturnPHI);
191
18.5k
      return {};
192
0
    }
193
1.49k
    case OpCode::Else: {
194
1.49k
      auto Entry = leaveBlock();
195
1.49k
      Builder.positionAtEnd(Entry.ElseBlock);
196
1.49k
      enterBlock(Entry.JumpBlock, {}, {}, std::move(Entry.Args),
197
1.49k
                 std::move(Entry.Type), std::move(Entry.ReturnPHI));
198
1.49k
      return {};
199
0
    }
200
1.46M
    default:
201
1.46M
      break;
202
1.48M
    }
203
204
1.46M
    if (isUnreachable()) {
205
469k
      return {};
206
469k
    }
207
208
991k
    switch (Instr.getOpCode()) {
209
    // Control instructions
210
3.30k
    case OpCode::Unreachable:
211
3.30k
      Builder.createBr(getTrapBB(ErrCode::Value::Unreachable));
212
3.30k
      setUnreachable();
213
3.30k
      Builder.positionAtEnd(
214
3.30k
          LLVM::BasicBlock::create(LLContext, F.Fn, "unreachable.end"));
215
3.30k
      break;
216
42.3k
    case OpCode::Nop:
217
42.3k
      break;
218
1
    case OpCode::Throw:
219
2
    case OpCode::Throw_ref:
220
      // TODO: EXCEPTION - implement the AOT.
221
2
      return Unexpect(ErrCode::Value::AOTNotImpl);
222
701
    case OpCode::Br: {
223
701
      const auto Label = Instr.getJump().TargetIndex;
224
701
      setLableJumpPHI(Label);
225
701
      Builder.createBr(getLabel(Label));
226
701
      setUnreachable();
227
701
      Builder.positionAtEnd(
228
701
          LLVM::BasicBlock::create(LLContext, F.Fn, "br.end"));
229
701
      break;
230
1
    }
231
360
    case OpCode::Br_if: {
232
360
      const auto Label = Instr.getJump().TargetIndex;
233
360
      auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
234
360
      setLableJumpPHI(Label);
235
360
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_if.end");
236
360
      Builder.createCondBr(Cond, getLabel(Label), Next);
237
360
      Builder.positionAtEnd(Next);
238
360
      break;
239
1
    }
240
929
    case OpCode::Br_table: {
241
929
      auto LabelTable = Instr.getLabelList();
242
929
      assuming(LabelTable.size() <= std::numeric_limits<uint32_t>::max());
243
929
      const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1);
244
929
      auto Value = stackPop();
245
929
      setLableJumpPHI(LabelTable[LabelTableSize].TargetIndex);
246
929
      auto Switch = Builder.createSwitch(
247
929
          Value, getLabel(LabelTable[LabelTableSize].TargetIndex),
248
929
          LabelTableSize);
249
20.2k
      for (uint32_t I = 0; I < LabelTableSize; ++I) {
250
19.3k
        setLableJumpPHI(LabelTable[I].TargetIndex);
251
19.3k
        Switch.addCase(LLContext.getInt32(I),
252
19.3k
                       getLabel(LabelTable[I].TargetIndex));
253
19.3k
      }
254
929
      setUnreachable();
255
929
      Builder.positionAtEnd(
256
929
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_table.end"));
257
929
      break;
258
929
    }
259
20
    case OpCode::Br_on_null: {
260
20
      const auto Label = Instr.getJump().TargetIndex;
261
20
      auto Value = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
262
20
      auto Cond = Builder.createICmpEQ(
263
20
          Builder.createExtractElement(Value, LLContext.getInt64(1)),
264
20
          LLContext.getInt64(0));
265
20
      setLableJumpPHI(Label);
266
20
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_null.end");
267
20
      Builder.createCondBr(Cond, getLabel(Label), Next);
268
20
      Builder.positionAtEnd(Next);
269
20
      stackPush(Value);
270
20
      break;
271
929
    }
272
10
    case OpCode::Br_on_non_null: {
273
10
      const auto Label = Instr.getJump().TargetIndex;
274
10
      auto Cond = Builder.createICmpNE(
275
10
          Builder.createExtractElement(
276
10
              Builder.createBitCast(Stack.back(), Context.Int64x2Ty),
277
10
              LLContext.getInt64(1)),
278
10
          LLContext.getInt64(0));
279
10
      setLableJumpPHI(Label);
280
10
      auto Next =
281
10
          LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_non_null.end");
282
10
      Builder.createCondBr(Cond, getLabel(Label), Next);
283
10
      Builder.positionAtEnd(Next);
284
10
      stackPop();
285
10
      break;
286
929
    }
287
0
    case OpCode::Br_on_cast:
288
0
    case OpCode::Br_on_cast_fail: {
289
0
      auto Ref = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
290
0
      const auto Label = Instr.getBrCast().Jump.TargetIndex;
291
0
      std::array<uint8_t, 16> Buf = {0};
292
0
      std::copy_n(Instr.getBrCast().RType2.getRawData().cbegin(), 8,
293
0
                  Buf.begin());
294
0
      auto VType = Builder.createExtractElement(
295
0
          Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
296
0
                                Context.Int64x2Ty),
297
0
          LLContext.getInt64(0));
298
0
      auto IsRefTest = Builder.createCall(
299
0
          Context.getIntrinsic(
300
0
              Builder, Executable::Intrinsics::kRefTest,
301
0
              LLVM::Type::getFunctionType(Context.Int32Ty,
302
0
                                          {Context.Int64x2Ty, Context.Int64Ty},
303
0
                                          false)),
304
0
          {Ref, VType});
305
0
      auto Cond = (Instr.getOpCode() == OpCode::Br_on_cast)
306
0
                      ? Builder.createICmpNE(IsRefTest, LLContext.getInt32(0))
307
0
                      : Builder.createICmpEQ(IsRefTest, LLContext.getInt32(0));
308
0
      setLableJumpPHI(Label);
309
0
      auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "br_on_cast.end");
310
0
      Builder.createCondBr(Cond, getLabel(Label), Next);
311
0
      Builder.positionAtEnd(Next);
312
0
      break;
313
0
    }
314
675
    case OpCode::Return:
315
675
      compileReturn();
316
675
      setUnreachable();
317
675
      Builder.positionAtEnd(
318
675
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret.end"));
319
675
      break;
320
3.42k
    case OpCode::Call:
321
3.42k
      updateInstrCount();
322
3.42k
      updateGas();
323
3.42k
      compileCallOp(Instr.getTargetIndex());
324
3.42k
      break;
325
795
    case OpCode::Call_indirect:
326
795
      updateInstrCount();
327
795
      updateGas();
328
795
      compileIndirectCallOp(Instr.getSourceIndex(), Instr.getTargetIndex());
329
795
      break;
330
65
    case OpCode::Return_call:
331
65
      updateInstrCount();
332
65
      updateGas();
333
65
      compileReturnCallOp(Instr.getTargetIndex());
334
65
      setUnreachable();
335
65
      Builder.positionAtEnd(
336
65
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call.end"));
337
65
      break;
338
119
    case OpCode::Return_call_indirect:
339
119
      updateInstrCount();
340
119
      updateGas();
341
119
      compileReturnIndirectCallOp(Instr.getSourceIndex(),
342
119
                                  Instr.getTargetIndex());
343
119
      setUnreachable();
344
119
      Builder.positionAtEnd(
345
119
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_indir.end"));
346
119
      break;
347
193
    case OpCode::Call_ref:
348
193
      updateInstrCount();
349
193
      updateGas();
350
193
      compileCallRefOp(Instr.getTargetIndex());
351
193
      break;
352
49
    case OpCode::Return_call_ref:
353
49
      updateInstrCount();
354
49
      updateGas();
355
49
      compileReturnCallRefOp(Instr.getTargetIndex());
356
49
      setUnreachable();
357
49
      Builder.positionAtEnd(
358
49
          LLVM::BasicBlock::create(LLContext, F.Fn, "ret_call_ref.end"));
359
49
      break;
360
0
    case OpCode::Try_table:
361
      // TODO: EXCEPTION - implement the AOT.
362
0
      return Unexpect(ErrCode::Value::AOTNotImpl);
363
364
    // Reference Instructions
365
5.55k
    case OpCode::Ref__null:
366
7.91k
    case OpCode::Ref__is_null:
367
7.94k
    case OpCode::Ref__func:
368
7.95k
    case OpCode::Ref__eq:
369
8.32k
    case OpCode::Ref__as_non_null:
370
8.36k
    case OpCode::Struct__new:
371
8.39k
    case OpCode::Struct__new_default:
372
8.39k
    case OpCode::Struct__get:
373
8.39k
    case OpCode::Struct__get_u:
374
8.39k
    case OpCode::Struct__get_s:
375
8.39k
    case OpCode::Struct__set:
376
8.55k
    case OpCode::Array__new:
377
8.56k
    case OpCode::Array__new_default:
378
8.60k
    case OpCode::Array__new_fixed:
379
8.60k
    case OpCode::Array__new_data:
380
8.60k
    case OpCode::Array__new_elem:
381
8.72k
    case OpCode::Array__get:
382
8.75k
    case OpCode::Array__get_u:
383
8.81k
    case OpCode::Array__get_s:
384
8.85k
    case OpCode::Array__set:
385
8.91k
    case OpCode::Array__len:
386
8.92k
    case OpCode::Array__fill:
387
8.93k
    case OpCode::Array__copy:
388
8.93k
    case OpCode::Array__init_data:
389
8.93k
    case OpCode::Array__init_elem:
390
8.94k
    case OpCode::Ref__test:
391
8.97k
    case OpCode::Ref__test_null:
392
8.99k
    case OpCode::Ref__cast:
393
9.00k
    case OpCode::Ref__cast_null:
394
9.01k
    case OpCode::Any__convert_extern:
395
9.04k
    case OpCode::Extern__convert_any:
396
9.13k
    case OpCode::Ref__i31:
397
9.17k
    case OpCode::I31__get_s:
398
9.19k
    case OpCode::I31__get_u:
399
12.6k
    case OpCode::Drop:
400
13.3k
    case OpCode::Select:
401
13.7k
    case OpCode::Select_t:
402
13.7k
      return compileRefOp(Instr);
403
11.0k
    case OpCode::Local__get: {
404
11.0k
      const auto &L = Local[Instr.getTargetIndex()];
405
11.0k
      stackPush(Builder.createLoad(L.first, L.second));
406
11.0k
      break;
407
13.3k
    }
408
3.83k
    case OpCode::Local__set:
409
3.83k
      Builder.createStore(stackPop(), Local[Instr.getTargetIndex()].second);
410
3.83k
      break;
411
817
    case OpCode::Local__tee:
412
817
      Builder.createStore(Stack.back(), Local[Instr.getTargetIndex()].second);
413
817
      break;
414
365
    case OpCode::Global__get: {
415
365
      const auto G =
416
365
          Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex());
417
365
      stackPush(Builder.createLoad(G.first, G.second));
418
365
      break;
419
13.3k
    }
420
87
    case OpCode::Global__set:
421
87
      Builder.createStore(
422
87
          stackPop(),
423
87
          Context.getGlobal(Builder, ExecCtx, Instr.getTargetIndex()).second);
424
87
      break;
425
426
    // Table Instructions
427
44
    case OpCode::Table__get: {
428
44
      const auto TableIndex = Instr.getTargetIndex();
429
44
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
430
44
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_get.ok");
431
44
      Builder.createCondBr(
432
44
          Builder.createLikely(Builder.createICmpULT(
433
44
              Off, Context.getTableSize(Builder, ExecCtx, TableIndex))),
434
44
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
435
44
      Builder.positionAtEnd(OkBB);
436
44
      stackPush(Builder.createLoad(
437
44
          Context.Int64x2Ty,
438
44
          Builder.createInBoundsGEP1(
439
44
              Context.Int64x2Ty, Context.getTable(Builder, ExecCtx, TableIndex),
440
44
              Off)));
441
44
      break;
442
13.3k
    }
443
34
    case OpCode::Table__set: {
444
34
      const auto TableIndex = Instr.getTargetIndex();
445
34
      auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
446
34
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
447
34
      auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "t_set.ok");
448
34
      Builder.createCondBr(
449
34
          Builder.createLikely(Builder.createICmpULT(
450
34
              Off, Context.getTableSize(Builder, ExecCtx, TableIndex))),
451
34
          OkBB, getTrapBB(ErrCode::Value::TableOutOfBounds));
452
34
      Builder.positionAtEnd(OkBB);
453
34
      Builder.createStore(
454
34
          Ref, Builder.createInBoundsGEP1(
455
34
                   Context.Int64x2Ty,
456
34
                   Context.getTable(Builder, ExecCtx, TableIndex), Off));
457
34
      break;
458
13.3k
    }
459
27
    case OpCode::Table__init: {
460
27
      auto Len = stackPop();
461
27
      auto Src = stackPop();
462
27
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
463
27
      Builder.createCall(
464
27
          Context.getIntrinsic(
465
27
              Builder, Executable::Intrinsics::kTableInit,
466
27
              LLVM::Type::getFunctionType(Context.VoidTy,
467
27
                                          {Context.Int32Ty, Context.Int32Ty,
468
27
                                           Context.Int64Ty, Context.Int32Ty,
469
27
                                           Context.Int32Ty},
470
27
                                          false)),
471
27
          {LLContext.getInt32(Instr.getTargetIndex()),
472
27
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
473
27
      break;
474
13.3k
    }
475
33
    case OpCode::Elem__drop: {
476
33
      Builder.createCall(
477
33
          Context.getIntrinsic(Builder, Executable::Intrinsics::kElemDrop,
478
33
                               LLVM::Type::getFunctionType(
479
33
                                   Context.VoidTy, {Context.Int32Ty}, false)),
480
33
          {LLContext.getInt32(Instr.getTargetIndex())});
481
33
      break;
482
13.3k
    }
483
15
    case OpCode::Table__copy: {
484
15
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
485
15
      auto Src = Builder.createZExt(stackPop(), Context.Int64Ty);
486
15
      auto Dst = Builder.createZExt(stackPop(), Context.Int64Ty);
487
15
      Builder.createCall(
488
15
          Context.getIntrinsic(
489
15
              Builder, Executable::Intrinsics::kTableCopy,
490
15
              LLVM::Type::getFunctionType(Context.VoidTy,
491
15
                                          {Context.Int32Ty, Context.Int32Ty,
492
15
                                           Context.Int64Ty, Context.Int64Ty,
493
15
                                           Context.Int64Ty},
494
15
                                          false)),
495
15
          {LLContext.getInt32(Instr.getTargetIndex()),
496
15
           LLContext.getInt32(Instr.getSourceIndex()), Dst, Src, Len});
497
15
      break;
498
13.3k
    }
499
16
    case OpCode::Table__grow: {
500
16
      auto NewSize = Builder.createZExt(stackPop(), Context.Int64Ty);
501
16
      auto Val = stackPop();
502
16
      stackPush(Builder.createTrunc(
503
16
          Builder.createCall(
504
16
              Context.getIntrinsic(
505
16
                  Builder, Executable::Intrinsics::kTableGrow,
506
16
                  LLVM::Type::getFunctionType(
507
16
                      Context.Int64Ty,
508
16
                      {Context.Int32Ty, Context.Int64x2Ty, Context.Int64Ty},
509
16
                      false)),
510
16
              {LLContext.getInt32(Instr.getTargetIndex()), Val, NewSize}),
511
16
          Context.TableAddrTypes[Instr.getTargetIndex()]));
512
16
      break;
513
13.3k
    }
514
16
    case OpCode::Table__size: {
515
16
      stackPush(Builder.createTrunc(
516
16
          Context.getTableSize(Builder, ExecCtx, Instr.getTargetIndex()),
517
16
          Context.TableAddrTypes[Instr.getTargetIndex()]));
518
16
      break;
519
13.3k
    }
520
3
    case OpCode::Table__fill: {
521
3
      auto Len = Builder.createZExt(stackPop(), Context.Int64Ty);
522
3
      auto Val = stackPop();
523
3
      auto Off = Builder.createZExt(stackPop(), Context.Int64Ty);
524
3
      Builder.createCall(
525
3
          Context.getIntrinsic(
526
3
              Builder, Executable::Intrinsics::kTableFill,
527
3
              LLVM::Type::getFunctionType(Context.Int32Ty,
528
3
                                          {Context.Int32Ty, Context.Int64Ty,
529
3
                                           Context.Int64x2Ty, Context.Int64Ty},
530
3
                                          false)),
531
3
          {LLContext.getInt32(Instr.getTargetIndex()), Off, Val, Len});
532
3
      break;
533
13.3k
    }
534
535
    // Memory Instructions
536
1.18k
    case OpCode::I32__load:
537
4.42k
    case OpCode::I64__load:
538
4.53k
    case OpCode::F32__load:
539
4.75k
    case OpCode::F64__load:
540
5.42k
    case OpCode::I32__load8_s:
541
5.81k
    case OpCode::I32__load8_u:
542
6.11k
    case OpCode::I32__load16_s:
543
7.67k
    case OpCode::I32__load16_u:
544
8.41k
    case OpCode::I64__load8_s:
545
8.85k
    case OpCode::I64__load8_u:
546
9.25k
    case OpCode::I64__load16_s:
547
9.81k
    case OpCode::I64__load16_u:
548
10.2k
    case OpCode::I64__load32_s:
549
10.6k
    case OpCode::I64__load32_u:
550
11.0k
    case OpCode::I32__store:
551
12.6k
    case OpCode::I64__store:
552
12.6k
    case OpCode::F32__store:
553
12.7k
    case OpCode::F64__store:
554
13.0k
    case OpCode::I32__store8:
555
13.0k
    case OpCode::I64__store8:
556
13.2k
    case OpCode::I32__store16:
557
13.3k
    case OpCode::I64__store16:
558
13.3k
    case OpCode::I64__store32:
559
14.0k
    case OpCode::Memory__size:
560
14.8k
    case OpCode::Memory__grow:
561
14.8k
    case OpCode::Memory__init:
562
14.9k
    case OpCode::Data__drop:
563
15.1k
    case OpCode::Memory__copy:
564
15.7k
    case OpCode::Memory__fill:
565
558k
    case OpCode::I32__const:
566
627k
    case OpCode::I64__const:
567
641k
    case OpCode::F32__const:
568
647k
    case OpCode::F64__const:
569
647k
      return compileMemoryOp(Instr);
570
    // Unary Numeric Instructions
571
7.68k
    case OpCode::I32__eqz:
572
8.65k
    case OpCode::I64__eqz:
573
10.6k
    case OpCode::I32__clz:
574
11.0k
    case OpCode::I64__clz:
575
12.7k
    case OpCode::I32__ctz:
576
13.3k
    case OpCode::I64__ctz:
577
29.1k
    case OpCode::I32__popcnt:
578
31.0k
    case OpCode::I64__popcnt:
579
31.8k
    case OpCode::F32__abs:
580
32.4k
    case OpCode::F64__abs:
581
33.2k
    case OpCode::F32__neg:
582
33.8k
    case OpCode::F64__neg:
583
35.3k
    case OpCode::F32__ceil:
584
37.5k
    case OpCode::F64__ceil:
585
38.2k
    case OpCode::F32__floor:
586
38.6k
    case OpCode::F64__floor:
587
39.2k
    case OpCode::F32__trunc:
588
39.4k
    case OpCode::F64__trunc:
589
40.1k
    case OpCode::F32__nearest:
590
40.5k
    case OpCode::F64__nearest:
591
40.9k
    case OpCode::F32__sqrt:
592
42.1k
    case OpCode::F64__sqrt:
593
42.4k
    case OpCode::I32__wrap_i64:
594
43.7k
    case OpCode::I32__trunc_f32_s:
595
43.9k
    case OpCode::I32__trunc_f64_s:
596
44.1k
    case OpCode::I32__trunc_f32_u:
597
45.3k
    case OpCode::I32__trunc_f64_u:
598
47.4k
    case OpCode::I64__extend_i32_s:
599
47.8k
    case OpCode::I64__extend_i32_u:
600
47.9k
    case OpCode::I64__trunc_f32_s:
601
48.2k
    case OpCode::I64__trunc_f64_s:
602
49.0k
    case OpCode::I64__trunc_f32_u:
603
49.9k
    case OpCode::I64__trunc_f64_u:
604
51.5k
    case OpCode::F32__convert_i32_s:
605
51.9k
    case OpCode::F32__convert_i64_s:
606
52.5k
    case OpCode::F32__convert_i32_u:
607
53.4k
    case OpCode::F32__convert_i64_u:
608
54.7k
    case OpCode::F64__convert_i32_s:
609
58.3k
    case OpCode::F64__convert_i64_s:
610
59.9k
    case OpCode::F64__convert_i32_u:
611
60.1k
    case OpCode::F64__convert_i64_u:
612
60.3k
    case OpCode::F32__demote_f64:
613
60.4k
    case OpCode::F64__promote_f32:
614
60.9k
    case OpCode::I32__reinterpret_f32:
615
61.6k
    case OpCode::I64__reinterpret_f64:
616
65.5k
    case OpCode::F32__reinterpret_i32:
617
66.7k
    case OpCode::F64__reinterpret_i64:
618
70.6k
    case OpCode::I32__extend8_s:
619
73.3k
    case OpCode::I32__extend16_s:
620
73.7k
    case OpCode::I64__extend8_s:
621
74.3k
    case OpCode::I64__extend16_s:
622
75.0k
    case OpCode::I64__extend32_s:
623
76.0k
    case OpCode::I32__eq:
624
76.3k
    case OpCode::I64__eq:
625
77.0k
    case OpCode::I32__ne:
626
77.0k
    case OpCode::I64__ne:
627
79.7k
    case OpCode::I32__lt_s:
628
80.2k
    case OpCode::I64__lt_s:
629
86.0k
    case OpCode::I32__lt_u:
630
86.3k
    case OpCode::I64__lt_u:
631
87.4k
    case OpCode::I32__gt_s:
632
87.7k
    case OpCode::I64__gt_s:
633
93.6k
    case OpCode::I32__gt_u:
634
93.7k
    case OpCode::I64__gt_u:
635
95.7k
    case OpCode::I32__le_s:
636
96.4k
    case OpCode::I64__le_s:
637
96.8k
    case OpCode::I32__le_u:
638
98.1k
    case OpCode::I64__le_u:
639
99.2k
    case OpCode::I32__ge_s:
640
99.3k
    case OpCode::I64__ge_s:
641
100k
    case OpCode::I32__ge_u:
642
100k
    case OpCode::I64__ge_u:
643
101k
    case OpCode::F32__eq:
644
101k
    case OpCode::F64__eq:
645
101k
    case OpCode::F32__ne:
646
101k
    case OpCode::F64__ne:
647
101k
    case OpCode::F32__lt:
648
101k
    case OpCode::F64__lt:
649
101k
    case OpCode::F32__gt:
650
101k
    case OpCode::F64__gt:
651
101k
    case OpCode::F32__le:
652
101k
    case OpCode::F64__le:
653
102k
    case OpCode::F32__ge:
654
102k
    case OpCode::F64__ge:
655
102k
    case OpCode::I32__add:
656
103k
    case OpCode::I64__add:
657
105k
    case OpCode::I32__sub:
658
105k
    case OpCode::I64__sub:
659
106k
    case OpCode::I32__mul:
660
106k
    case OpCode::I64__mul:
661
107k
    case OpCode::I32__div_s:
662
108k
    case OpCode::I64__div_s:
663
111k
    case OpCode::I32__div_u:
664
111k
    case OpCode::I64__div_u:
665
112k
    case OpCode::I32__rem_s:
666
113k
    case OpCode::I64__rem_s:
667
115k
    case OpCode::I32__rem_u:
668
115k
    case OpCode::I64__rem_u:
669
116k
    case OpCode::I32__and:
670
117k
    case OpCode::I64__and:
671
118k
    case OpCode::I32__or:
672
119k
    case OpCode::I64__or:
673
120k
    case OpCode::I32__xor:
674
121k
    case OpCode::I64__xor:
675
123k
    case OpCode::I32__shl:
676
123k
    case OpCode::I64__shl:
677
125k
    case OpCode::I32__shr_s:
678
126k
    case OpCode::I64__shr_s:
679
130k
    case OpCode::I32__shr_u:
680
130k
    case OpCode::I64__shr_u:
681
132k
    case OpCode::I32__rotl:
682
133k
    case OpCode::I32__rotr:
683
134k
    case OpCode::I64__rotl:
684
135k
    case OpCode::I64__rotr:
685
136k
    case OpCode::F32__add:
686
136k
    case OpCode::F64__add:
687
136k
    case OpCode::F32__sub:
688
136k
    case OpCode::F64__sub:
689
137k
    case OpCode::F32__mul:
690
137k
    case OpCode::F64__mul:
691
137k
    case OpCode::F32__div:
692
137k
    case OpCode::F64__div:
693
138k
    case OpCode::F32__min:
694
138k
    case OpCode::F64__min:
695
138k
    case OpCode::F32__max:
696
139k
    case OpCode::F64__max:
697
139k
    case OpCode::F32__copysign:
698
140k
    case OpCode::F64__copysign:
699
140k
    case OpCode::I32__trunc_sat_f32_s:
700
140k
    case OpCode::I32__trunc_sat_f32_u:
701
140k
    case OpCode::I32__trunc_sat_f64_s:
702
141k
    case OpCode::I32__trunc_sat_f64_u:
703
141k
    case OpCode::I64__trunc_sat_f32_s:
704
141k
    case OpCode::I64__trunc_sat_f32_u:
705
142k
    case OpCode::I64__trunc_sat_f64_s:
706
142k
    case OpCode::I64__trunc_sat_f64_u:
707
142k
      return compileNumericOp(Instr);
708
4.87k
    case OpCode::V128__load:
709
5.09k
    case OpCode::V128__load8x8_s:
710
5.14k
    case OpCode::V128__load8x8_u:
711
5.45k
    case OpCode::V128__load16x4_s:
712
5.95k
    case OpCode::V128__load16x4_u:
713
6.08k
    case OpCode::V128__load32x2_s:
714
6.27k
    case OpCode::V128__load32x2_u:
715
6.34k
    case OpCode::V128__load8_splat:
716
6.48k
    case OpCode::V128__load16_splat:
717
6.66k
    case OpCode::V128__load32_splat:
718
6.82k
    case OpCode::V128__load64_splat:
719
6.90k
    case OpCode::V128__load32_zero:
720
7.04k
    case OpCode::V128__load64_zero:
721
7.27k
    case OpCode::V128__store:
722
7.49k
    case OpCode::V128__load8_lane:
723
7.63k
    case OpCode::V128__load16_lane:
724
7.75k
    case OpCode::V128__load32_lane:
725
7.77k
    case OpCode::V128__load64_lane:
726
7.94k
    case OpCode::V128__store8_lane:
727
8.02k
    case OpCode::V128__store16_lane:
728
8.12k
    case OpCode::V128__store32_lane:
729
8.16k
    case OpCode::V128__store64_lane:
730
8.51k
    case OpCode::V128__const:
731
8.52k
    case OpCode::I8x16__shuffle:
732
8.59k
    case OpCode::I8x16__extract_lane_s:
733
8.61k
    case OpCode::I8x16__extract_lane_u:
734
8.82k
    case OpCode::I8x16__replace_lane:
735
9.26k
    case OpCode::I16x8__extract_lane_s:
736
9.66k
    case OpCode::I16x8__extract_lane_u:
737
10.0k
    case OpCode::I16x8__replace_lane:
738
10.0k
    case OpCode::I32x4__extract_lane:
739
10.2k
    case OpCode::I32x4__replace_lane:
740
10.4k
    case OpCode::I64x2__extract_lane:
741
10.4k
    case OpCode::I64x2__replace_lane:
742
10.4k
    case OpCode::F32x4__extract_lane:
743
10.4k
    case OpCode::F32x4__replace_lane:
744
10.5k
    case OpCode::F64x2__extract_lane:
745
10.5k
    case OpCode::F64x2__replace_lane:
746
10.6k
    case OpCode::I8x16__swizzle:
747
46.8k
    case OpCode::I8x16__splat:
748
55.2k
    case OpCode::I16x8__splat:
749
56.5k
    case OpCode::I32x4__splat:
750
57.0k
    case OpCode::I64x2__splat:
751
57.3k
    case OpCode::F32x4__splat:
752
57.4k
    case OpCode::F64x2__splat:
753
57.5k
    case OpCode::I8x16__eq:
754
57.9k
    case OpCode::I8x16__ne:
755
58.0k
    case OpCode::I8x16__lt_s:
756
58.0k
    case OpCode::I8x16__lt_u:
757
58.3k
    case OpCode::I8x16__gt_s:
758
58.5k
    case OpCode::I8x16__gt_u:
759
58.6k
    case OpCode::I8x16__le_s:
760
58.7k
    case OpCode::I8x16__le_u:
761
59.2k
    case OpCode::I8x16__ge_s:
762
59.3k
    case OpCode::I8x16__ge_u:
763
59.5k
    case OpCode::I16x8__eq:
764
59.7k
    case OpCode::I16x8__ne:
765
59.7k
    case OpCode::I16x8__lt_s:
766
59.9k
    case OpCode::I16x8__lt_u:
767
60.2k
    case OpCode::I16x8__gt_s:
768
60.3k
    case OpCode::I16x8__gt_u:
769
60.4k
    case OpCode::I16x8__le_s:
770
60.5k
    case OpCode::I16x8__le_u:
771
60.6k
    case OpCode::I16x8__ge_s:
772
60.7k
    case OpCode::I16x8__ge_u:
773
60.7k
    case OpCode::I32x4__eq:
774
60.8k
    case OpCode::I32x4__ne:
775
60.9k
    case OpCode::I32x4__lt_s:
776
61.0k
    case OpCode::I32x4__lt_u:
777
61.2k
    case OpCode::I32x4__gt_s:
778
61.4k
    case OpCode::I32x4__gt_u:
779
61.7k
    case OpCode::I32x4__le_s:
780
61.9k
    case OpCode::I32x4__le_u:
781
62.0k
    case OpCode::I32x4__ge_s:
782
62.1k
    case OpCode::I32x4__ge_u:
783
62.3k
    case OpCode::I64x2__eq:
784
62.3k
    case OpCode::I64x2__ne:
785
62.3k
    case OpCode::I64x2__lt_s:
786
62.5k
    case OpCode::I64x2__gt_s:
787
62.6k
    case OpCode::I64x2__le_s:
788
62.6k
    case OpCode::I64x2__ge_s:
789
64.0k
    case OpCode::F32x4__eq:
790
64.0k
    case OpCode::F32x4__ne:
791
64.7k
    case OpCode::F32x4__lt:
792
64.8k
    case OpCode::F32x4__gt:
793
65.2k
    case OpCode::F32x4__le:
794
65.3k
    case OpCode::F32x4__ge:
795
65.3k
    case OpCode::F64x2__eq:
796
65.4k
    case OpCode::F64x2__ne:
797
65.6k
    case OpCode::F64x2__lt:
798
65.6k
    case OpCode::F64x2__gt:
799
65.8k
    case OpCode::F64x2__le:
800
65.8k
    case OpCode::F64x2__ge:
801
66.2k
    case OpCode::V128__not:
802
66.3k
    case OpCode::V128__and:
803
66.4k
    case OpCode::V128__andnot:
804
66.5k
    case OpCode::V128__or:
805
66.6k
    case OpCode::V128__xor:
806
66.7k
    case OpCode::V128__bitselect:
807
66.8k
    case OpCode::V128__any_true:
808
68.1k
    case OpCode::I8x16__abs:
809
70.4k
    case OpCode::I8x16__neg:
810
70.6k
    case OpCode::I8x16__popcnt:
811
70.9k
    case OpCode::I8x16__all_true:
812
71.5k
    case OpCode::I8x16__bitmask:
813
71.6k
    case OpCode::I8x16__narrow_i16x8_s:
814
71.8k
    case OpCode::I8x16__narrow_i16x8_u:
815
71.9k
    case OpCode::I8x16__shl:
816
73.0k
    case OpCode::I8x16__shr_s:
817
73.1k
    case OpCode::I8x16__shr_u:
818
73.2k
    case OpCode::I8x16__add:
819
73.7k
    case OpCode::I8x16__add_sat_s:
820
73.8k
    case OpCode::I8x16__add_sat_u:
821
73.8k
    case OpCode::I8x16__sub:
822
74.0k
    case OpCode::I8x16__sub_sat_s:
823
74.1k
    case OpCode::I8x16__sub_sat_u:
824
74.2k
    case OpCode::I8x16__min_s:
825
74.3k
    case OpCode::I8x16__min_u:
826
74.6k
    case OpCode::I8x16__max_s:
827
74.7k
    case OpCode::I8x16__max_u:
828
74.9k
    case OpCode::I8x16__avgr_u:
829
75.1k
    case OpCode::I16x8__abs:
830
75.3k
    case OpCode::I16x8__neg:
831
75.4k
    case OpCode::I16x8__all_true:
832
75.5k
    case OpCode::I16x8__bitmask:
833
75.5k
    case OpCode::I16x8__narrow_i32x4_s:
834
75.9k
    case OpCode::I16x8__narrow_i32x4_u:
835
76.9k
    case OpCode::I16x8__extend_low_i8x16_s:
836
77.0k
    case OpCode::I16x8__extend_high_i8x16_s:
837
77.3k
    case OpCode::I16x8__extend_low_i8x16_u:
838
77.4k
    case OpCode::I16x8__extend_high_i8x16_u:
839
77.5k
    case OpCode::I16x8__shl:
840
77.8k
    case OpCode::I16x8__shr_s:
841
77.9k
    case OpCode::I16x8__shr_u:
842
78.1k
    case OpCode::I16x8__add:
843
78.1k
    case OpCode::I16x8__add_sat_s:
844
78.5k
    case OpCode::I16x8__add_sat_u:
845
78.7k
    case OpCode::I16x8__sub:
846
78.8k
    case OpCode::I16x8__sub_sat_s:
847
78.9k
    case OpCode::I16x8__sub_sat_u:
848
79.0k
    case OpCode::I16x8__mul:
849
79.1k
    case OpCode::I16x8__min_s:
850
79.2k
    case OpCode::I16x8__min_u:
851
79.3k
    case OpCode::I16x8__max_s:
852
79.9k
    case OpCode::I16x8__max_u:
853
80.0k
    case OpCode::I16x8__avgr_u:
854
80.0k
    case OpCode::I16x8__extmul_low_i8x16_s:
855
80.2k
    case OpCode::I16x8__extmul_high_i8x16_s:
856
80.3k
    case OpCode::I16x8__extmul_low_i8x16_u:
857
80.7k
    case OpCode::I16x8__extmul_high_i8x16_u:
858
80.9k
    case OpCode::I16x8__q15mulr_sat_s:
859
81.2k
    case OpCode::I16x8__extadd_pairwise_i8x16_s:
860
81.6k
    case OpCode::I16x8__extadd_pairwise_i8x16_u:
861
81.6k
    case OpCode::I32x4__abs:
862
81.8k
    case OpCode::I32x4__neg:
863
82.0k
    case OpCode::I32x4__all_true:
864
82.1k
    case OpCode::I32x4__bitmask:
865
82.2k
    case OpCode::I32x4__extend_low_i16x8_s:
866
82.7k
    case OpCode::I32x4__extend_high_i16x8_s:
867
84.6k
    case OpCode::I32x4__extend_low_i16x8_u:
868
84.8k
    case OpCode::I32x4__extend_high_i16x8_u:
869
85.9k
    case OpCode::I32x4__shl:
870
86.1k
    case OpCode::I32x4__shr_s:
871
86.6k
    case OpCode::I32x4__shr_u:
872
86.7k
    case OpCode::I32x4__add:
873
86.8k
    case OpCode::I32x4__sub:
874
87.0k
    case OpCode::I32x4__mul:
875
87.1k
    case OpCode::I32x4__min_s:
876
87.2k
    case OpCode::I32x4__min_u:
877
87.3k
    case OpCode::I32x4__max_s:
878
87.3k
    case OpCode::I32x4__max_u:
879
87.4k
    case OpCode::I32x4__extmul_low_i16x8_s:
880
87.5k
    case OpCode::I32x4__extmul_high_i16x8_s:
881
87.7k
    case OpCode::I32x4__extmul_low_i16x8_u:
882
87.8k
    case OpCode::I32x4__extmul_high_i16x8_u:
883
89.0k
    case OpCode::I32x4__extadd_pairwise_i16x8_s:
884
90.0k
    case OpCode::I32x4__extadd_pairwise_i16x8_u:
885
90.1k
    case OpCode::I32x4__dot_i16x8_s:
886
91.0k
    case OpCode::I64x2__abs:
887
91.5k
    case OpCode::I64x2__neg:
888
91.8k
    case OpCode::I64x2__all_true:
889
92.1k
    case OpCode::I64x2__bitmask:
890
92.5k
    case OpCode::I64x2__extend_low_i32x4_s:
891
93.2k
    case OpCode::I64x2__extend_high_i32x4_s:
892
93.4k
    case OpCode::I64x2__extend_low_i32x4_u:
893
94.0k
    case OpCode::I64x2__extend_high_i32x4_u:
894
94.1k
    case OpCode::I64x2__shl:
895
94.4k
    case OpCode::I64x2__shr_s:
896
94.5k
    case OpCode::I64x2__shr_u:
897
94.5k
    case OpCode::I64x2__add:
898
94.8k
    case OpCode::I64x2__sub:
899
94.8k
    case OpCode::I64x2__mul:
900
94.9k
    case OpCode::I64x2__extmul_low_i32x4_s:
901
95.3k
    case OpCode::I64x2__extmul_high_i32x4_s:
902
95.3k
    case OpCode::I64x2__extmul_low_i32x4_u:
903
95.5k
    case OpCode::I64x2__extmul_high_i32x4_u:
904
95.6k
    case OpCode::F32x4__abs:
905
95.8k
    case OpCode::F32x4__neg:
906
95.9k
    case OpCode::F32x4__sqrt:
907
96.0k
    case OpCode::F32x4__add:
908
96.3k
    case OpCode::F32x4__sub:
909
96.3k
    case OpCode::F32x4__mul:
910
96.5k
    case OpCode::F32x4__div:
911
96.6k
    case OpCode::F32x4__min:
912
96.7k
    case OpCode::F32x4__max:
913
96.7k
    case OpCode::F32x4__pmin:
914
97.0k
    case OpCode::F32x4__pmax:
915
98.0k
    case OpCode::F32x4__ceil:
916
100k
    case OpCode::F32x4__floor:
917
102k
    case OpCode::F32x4__trunc:
918
102k
    case OpCode::F32x4__nearest:
919
102k
    case OpCode::F64x2__abs:
920
103k
    case OpCode::F64x2__neg:
921
103k
    case OpCode::F64x2__sqrt:
922
103k
    case OpCode::F64x2__add:
923
103k
    case OpCode::F64x2__sub:
924
103k
    case OpCode::F64x2__mul:
925
104k
    case OpCode::F64x2__div:
926
104k
    case OpCode::F64x2__min:
927
104k
    case OpCode::F64x2__max:
928
104k
    case OpCode::F64x2__pmin:
929
104k
    case OpCode::F64x2__pmax:
930
105k
    case OpCode::F64x2__ceil:
931
106k
    case OpCode::F64x2__floor:
932
106k
    case OpCode::F64x2__trunc:
933
106k
    case OpCode::F64x2__nearest:
934
106k
    case OpCode::I32x4__trunc_sat_f32x4_s:
935
110k
    case OpCode::I32x4__trunc_sat_f32x4_u:
936
110k
    case OpCode::F32x4__convert_i32x4_s:
937
111k
    case OpCode::F32x4__convert_i32x4_u:
938
112k
    case OpCode::I32x4__trunc_sat_f64x2_s_zero:
939
114k
    case OpCode::I32x4__trunc_sat_f64x2_u_zero:
940
114k
    case OpCode::F64x2__convert_low_i32x4_s:
941
115k
    case OpCode::F64x2__convert_low_i32x4_u:
942
116k
    case OpCode::F32x4__demote_f64x2_zero:
943
117k
    case OpCode::F64x2__promote_low_f32x4:
944
117k
    case OpCode::I8x16__relaxed_swizzle:
945
117k
    case OpCode::I32x4__relaxed_trunc_f32x4_s:
946
117k
    case OpCode::I32x4__relaxed_trunc_f32x4_u:
947
117k
    case OpCode::I32x4__relaxed_trunc_f64x2_s_zero:
948
117k
    case OpCode::I32x4__relaxed_trunc_f64x2_u_zero:
949
117k
    case OpCode::F32x4__relaxed_madd:
950
117k
    case OpCode::F32x4__relaxed_nmadd:
951
117k
    case OpCode::F64x2__relaxed_madd:
952
117k
    case OpCode::F64x2__relaxed_nmadd:
953
117k
    case OpCode::I8x16__relaxed_laneselect:
954
117k
    case OpCode::I16x8__relaxed_laneselect:
955
117k
    case OpCode::I32x4__relaxed_laneselect:
956
117k
    case OpCode::I64x2__relaxed_laneselect:
957
117k
    case OpCode::F32x4__relaxed_min:
958
117k
    case OpCode::F32x4__relaxed_max:
959
117k
    case OpCode::F64x2__relaxed_min:
960
117k
    case OpCode::F64x2__relaxed_max:
961
117k
    case OpCode::I16x8__relaxed_q15mulr_s:
962
117k
    case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s:
963
117k
    case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s:
964
117k
      return compileVectorOp(Instr);
965
192
    case OpCode::Atomic__fence:
966
231
    case OpCode::Memory__atomic__notify:
967
236
    case OpCode::Memory__atomic__wait32:
968
238
    case OpCode::Memory__atomic__wait64:
969
238
    case OpCode::I32__atomic__load:
970
238
    case OpCode::I64__atomic__load:
971
238
    case OpCode::I32__atomic__load8_u:
972
238
    case OpCode::I32__atomic__load16_u:
973
238
    case OpCode::I64__atomic__load8_u:
974
238
    case OpCode::I64__atomic__load16_u:
975
238
    case OpCode::I64__atomic__load32_u:
976
238
    case OpCode::I32__atomic__store:
977
238
    case OpCode::I64__atomic__store:
978
238
    case OpCode::I32__atomic__store8:
979
238
    case OpCode::I32__atomic__store16:
980
238
    case OpCode::I64__atomic__store8:
981
238
    case OpCode::I64__atomic__store16:
982
238
    case OpCode::I64__atomic__store32:
983
238
    case OpCode::I32__atomic__rmw__add:
984
238
    case OpCode::I64__atomic__rmw__add:
985
238
    case OpCode::I32__atomic__rmw8__add_u:
986
238
    case OpCode::I32__atomic__rmw16__add_u:
987
238
    case OpCode::I64__atomic__rmw8__add_u:
988
238
    case OpCode::I64__atomic__rmw16__add_u:
989
238
    case OpCode::I64__atomic__rmw32__add_u:
990
238
    case OpCode::I32__atomic__rmw__sub:
991
238
    case OpCode::I64__atomic__rmw__sub:
992
238
    case OpCode::I32__atomic__rmw8__sub_u:
993
238
    case OpCode::I32__atomic__rmw16__sub_u:
994
238
    case OpCode::I64__atomic__rmw8__sub_u:
995
238
    case OpCode::I64__atomic__rmw16__sub_u:
996
238
    case OpCode::I64__atomic__rmw32__sub_u:
997
238
    case OpCode::I32__atomic__rmw__and:
998
238
    case OpCode::I64__atomic__rmw__and:
999
238
    case OpCode::I32__atomic__rmw8__and_u:
1000
238
    case OpCode::I32__atomic__rmw16__and_u:
1001
238
    case OpCode::I64__atomic__rmw8__and_u:
1002
238
    case OpCode::I64__atomic__rmw16__and_u:
1003
238
    case OpCode::I64__atomic__rmw32__and_u:
1004
238
    case OpCode::I32__atomic__rmw__or:
1005
238
    case OpCode::I64__atomic__rmw__or:
1006
238
    case OpCode::I32__atomic__rmw8__or_u:
1007
238
    case OpCode::I32__atomic__rmw16__or_u:
1008
238
    case OpCode::I64__atomic__rmw8__or_u:
1009
238
    case OpCode::I64__atomic__rmw16__or_u:
1010
238
    case OpCode::I64__atomic__rmw32__or_u:
1011
238
    case OpCode::I32__atomic__rmw__xor:
1012
238
    case OpCode::I64__atomic__rmw__xor:
1013
238
    case OpCode::I32__atomic__rmw8__xor_u:
1014
238
    case OpCode::I32__atomic__rmw16__xor_u:
1015
238
    case OpCode::I64__atomic__rmw8__xor_u:
1016
238
    case OpCode::I64__atomic__rmw16__xor_u:
1017
238
    case OpCode::I64__atomic__rmw32__xor_u:
1018
238
    case OpCode::I32__atomic__rmw__xchg:
1019
238
    case OpCode::I64__atomic__rmw__xchg:
1020
238
    case OpCode::I32__atomic__rmw8__xchg_u:
1021
238
    case OpCode::I32__atomic__rmw16__xchg_u:
1022
238
    case OpCode::I64__atomic__rmw8__xchg_u:
1023
238
    case OpCode::I64__atomic__rmw16__xchg_u:
1024
238
    case OpCode::I64__atomic__rmw32__xchg_u:
1025
238
    case OpCode::I32__atomic__rmw__cmpxchg:
1026
238
    case OpCode::I64__atomic__rmw__cmpxchg:
1027
238
    case OpCode::I32__atomic__rmw8__cmpxchg_u:
1028
238
    case OpCode::I32__atomic__rmw16__cmpxchg_u:
1029
238
    case OpCode::I64__atomic__rmw8__cmpxchg_u:
1030
238
    case OpCode::I64__atomic__rmw16__cmpxchg_u:
1031
238
    case OpCode::I64__atomic__rmw32__cmpxchg_u:
1032
238
      return compileAtomicOp(Instr);
1033
0
    default:
1034
0
      assumingUnreachable();
1035
991k
    }
1036
69.4k
    return {};
1037
991k
  };
1038
1039
1.48M
  for (const auto &Instr : Instrs) {
1040
    // Update instruction count
1041
1.48M
    if (LocalInstrCount) {
1042
0
      Builder.createStore(Builder.createAdd(Builder.createLoad(Context.Int64Ty,
1043
0
                                                               LocalInstrCount),
1044
0
                                            LLContext.getInt64(1)),
1045
0
                          LocalInstrCount);
1046
0
    }
1047
1.48M
    if (LocalGas) {
1048
0
      auto NewGas = Builder.createAdd(
1049
0
          Builder.createLoad(Context.Int64Ty, LocalGas),
1050
0
          Builder.createLoad(
1051
0
              Context.Int64Ty,
1052
0
              Builder.createConstInBoundsGEP2_64(
1053
0
                  LLVM::Type::getArrayType(Context.Int64Ty, UINT16_MAX + 1),
1054
0
                  Context.getCostTable(Builder, ExecCtx), 0,
1055
0
                  uint16_t(Instr.getOpCode()))));
1056
0
      Builder.createStore(NewGas, LocalGas);
1057
0
    }
1058
1059
    // Make the instruction node according to Code.
1060
1.48M
    EXPECTED_TRY(Dispatch(Instr));
1061
1.48M
  }
1062
10.5k
  return {};
1063
10.5k
}
1064
1065
11.2k
void FunctionCompiler::compileReturn() noexcept {
1066
11.2k
  updateInstrCount();
1067
11.2k
  updateGas();
1068
11.2k
  auto Ty = F.Ty.getReturnType();
1069
11.2k
  if (Ty.isVoidTy()) {
1070
2.16k
    Builder.createRetVoid();
1071
9.03k
  } else if (Ty.isStructTy()) {
1072
340
    const auto Count = Ty.getStructNumElements();
1073
340
    std::vector<LLVM::Value> Ret(Count);
1074
1.29k
    for (unsigned I = 0; I < Count; ++I) {
1075
952
      const unsigned J = Count - 1 - I;
1076
952
      Ret[J] = stackPop();
1077
952
    }
1078
340
    Builder.createAggregateRet(Ret);
1079
8.69k
  } else {
1080
8.69k
    Builder.createRet(stackPop());
1081
8.69k
  }
1082
11.2k
}
1083
1084
19.0k
void FunctionCompiler::updateInstrCount() noexcept {
1085
19.0k
  if (LocalInstrCount) {
1086
0
    auto Store [[maybe_unused]] = Builder.createAtomicRMW(
1087
0
        LLVMAtomicRMWBinOpAdd, Context.getInstrCount(Builder, ExecCtx),
1088
0
        Builder.createLoad(Context.Int64Ty, LocalInstrCount),
1089
0
        LLVMAtomicOrderingMonotonic);
1090
#if LLVM_VERSION_MAJOR >= 13
1091
    Store.setAlignment(8);
1092
#endif
1093
0
    Builder.createStore(LLContext.getInt64(0), LocalInstrCount);
1094
0
  }
1095
19.0k
}
1096
1097
21.1k
void FunctionCompiler::updateGas() noexcept {
1098
21.1k
  if (LocalGas) {
1099
0
    auto CurrBB = Builder.getInsertBlock();
1100
0
    auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_check");
1101
0
    auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_ok");
1102
0
    auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "gas_end");
1103
1104
0
    auto Cost = Builder.createLoad(Context.Int64Ty, LocalGas);
1105
0
    Cost.setAlignment(64);
1106
0
    auto GasPtr = Context.getGas(Builder, ExecCtx);
1107
0
    auto GasLimit = Context.getGasLimit(Builder, ExecCtx);
1108
0
    auto Gas = Builder.createLoad(Context.Int64Ty, GasPtr);
1109
0
    Gas.setAlignment(64);
1110
0
    Gas.setOrdering(LLVMAtomicOrderingMonotonic);
1111
0
    Builder.createBr(CheckBB);
1112
0
    Builder.positionAtEnd(CheckBB);
1113
1114
0
    auto PHIOldGas = Builder.createPHI(Context.Int64Ty);
1115
0
    auto NewGas = Builder.createAdd(PHIOldGas, Cost);
1116
0
    auto IsGasRemain =
1117
0
        Builder.createLikely(Builder.createICmpULE(NewGas, GasLimit));
1118
0
    Builder.createCondBr(IsGasRemain, OkBB,
1119
0
                         getTrapBB(ErrCode::Value::CostLimitExceeded));
1120
0
    Builder.positionAtEnd(OkBB);
1121
1122
0
    auto RGasAndSucceed = Builder.createAtomicCmpXchg(
1123
0
        GasPtr, PHIOldGas, NewGas, LLVMAtomicOrderingMonotonic,
1124
0
        LLVMAtomicOrderingMonotonic);
1125
#if LLVM_VERSION_MAJOR >= 13
1126
    RGasAndSucceed.setAlignment(8);
1127
#endif
1128
0
    RGasAndSucceed.setWeak(true);
1129
0
    auto RGas = Builder.createExtractValue(RGasAndSucceed, 0);
1130
0
    auto Succeed = Builder.createExtractValue(RGasAndSucceed, 1);
1131
0
    Builder.createCondBr(Builder.createLikely(Succeed), EndBB, CheckBB);
1132
0
    Builder.positionAtEnd(EndBB);
1133
1134
0
    Builder.createStore(LLContext.getInt64(0), LocalGas);
1135
1136
0
    PHIOldGas.addIncoming(Gas, CurrBB);
1137
0
    PHIOldGas.addIncoming(RGas, OkBB);
1138
0
  }
1139
21.1k
}
1140
1141
3.16k
void FunctionCompiler::updateGasAtTrap() noexcept {
1142
3.16k
  if (LocalGas) {
1143
0
    auto Update [[maybe_unused]] = Builder.createAtomicRMW(
1144
0
        LLVMAtomicRMWBinOpAdd, Context.getGas(Builder, ExecCtx),
1145
0
        Builder.createLoad(Context.Int64Ty, LocalGas),
1146
0
        LLVMAtomicOrderingMonotonic);
1147
#if LLVM_VERSION_MAJOR >= 13
1148
    Update.setAlignment(8);
1149
#endif
1150
0
  }
1151
3.16k
}
1152
1153
3.42k
void FunctionCompiler::compileCallOp(const unsigned int FuncIndex) noexcept {
1154
3.42k
  const auto &FuncType =
1155
3.42k
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1156
3.42k
          ->getFuncType();
1157
3.42k
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1158
3.42k
  const auto &ParamTypes = FuncType.getParamTypes();
1159
1160
3.42k
  std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
1161
3.42k
  Args[0] = F.Fn.getFirstParam();
1162
4.25k
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1163
832
    const size_t J = ParamTypes.size() - 1 - I;
1164
832
    Args[J + 1] = stackPop();
1165
832
  }
1166
1167
3.42k
  LLVM::Value Ret;
1168
3.42k
  if (IsLazyJIT) {
1169
0
    bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1170
0
    if (IsImport) {
1171
0
      Ret = Builder.createCall(Function, Args);
1172
0
    } else {
1173
0
      auto FTy = toLLVMType(LLContext, Context.ExecCtxPtrTy, FuncType);
1174
1175
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1176
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1177
0
      }
1178
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1179
0
      if (!CacheVar) {
1180
0
        CacheVar = Context.LLModule.get().addGlobal(
1181
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1182
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1183
0
      }
1184
1185
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.check");
1186
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.resolve");
1187
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "ic.call");
1188
1189
0
      Builder.createBr(CheckBB);
1190
0
      Builder.positionAtEnd(CheckBB);
1191
1192
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1193
0
      CachedPtr.setAlignment(8);
1194
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1195
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1196
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1197
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1198
1199
0
      Builder.positionAtEnd(ResolveBB);
1200
0
      auto FPtr = Builder.createCall(
1201
0
          Context.getIntrinsic(
1202
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1203
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int32Ty},
1204
0
                                          false)),
1205
0
          {LLContext.getInt32(FuncIndex)});
1206
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1207
0
      Store.setAlignment(8);
1208
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1209
0
      Builder.createBr(CallBB);
1210
1211
0
      Builder.positionAtEnd(CallBB);
1212
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1213
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1214
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1215
1216
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1217
0
    }
1218
3.42k
  } else {
1219
3.42k
    Ret = Builder.createCall(Function, Args);
1220
3.42k
  }
1221
1222
3.42k
  auto Ty = Ret.getType();
1223
3.42k
  if (Ty.isVoidTy()) {
1224
    // nothing to do
1225
1.77k
  } else if (Ty.isStructTy()) {
1226
186
    for (auto Val : unpackStruct(Builder, Ret)) {
1227
186
      stackPush(Val);
1228
186
    }
1229
1.56k
  } else {
1230
1.56k
    stackPush(Ret);
1231
1.56k
  }
1232
3.42k
}
1233
1234
void FunctionCompiler::compileIndirectCallOp(
1235
795
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1236
795
  auto TryFastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.tryfast");
1237
795
  auto NonNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.nonnull");
1238
795
  auto FastBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.fast");
1239
795
  auto SlowBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.slow");
1240
795
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1241
795
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1242
795
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1243
1244
795
  LLVM::Value FuncIndex = stackPop();
1245
795
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1246
795
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1247
795
  auto RTy = FTy.getReturnType();
1248
795
  auto FPtrTy = FTy.getPointerTo();
1249
795
  auto TableIdx = LLContext.getInt32(TableIndex);
1250
795
  auto TypeIdx = LLContext.getInt32(FuncTypeIndex);
1251
1252
795
  const size_t ArgSize = FuncType.getParamTypes().size();
1253
795
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1254
795
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1255
795
  ArgsVec[0] = F.Fn.getFirstParam();
1256
1.44k
  for (size_t I = 0; I < ArgSize; ++I) {
1257
648
    const size_t J = ArgSize - I;
1258
648
    ArgsVec[J] = stackPop();
1259
648
  }
1260
1.59k
  auto UnpackRets = [&](LLVM::Value Ret) -> std::vector<LLVM::Value> {
1261
1.59k
    if (RetSize == 0) {
1262
426
      return {};
1263
1.16k
    } else if (RetSize == 1) {
1264
1.13k
      return {Ret};
1265
1.13k
    } else {
1266
26
      return unpackStruct(Builder, Ret);
1267
26
    }
1268
1.59k
  };
1269
1270
795
  auto Idx64 = Builder.createZExt(FuncIndex, Context.Int64Ty);
1271
1272
  // Fast path: an in-bounds funcref defined in the running module with the
1273
  // call site's type index and compiled code is called directly.
1274
795
  std::vector<LLVM::Value> FastRetsVec;
1275
795
  {
1276
795
    Builder.createCondBr(
1277
795
        Builder.createLikely(Builder.createICmpULT(
1278
795
            Idx64, Context.getTableSize(Builder, ExecCtx, TableIndex))),
1279
795
        TryFastBB, SlowBB);
1280
795
    Builder.positionAtEnd(TryFastBB);
1281
1282
795
    auto FuncRef = Builder.createLoad(
1283
795
        Context.Int64x2Ty,
1284
795
        Builder.createInBoundsGEP1(
1285
795
            Context.Int64x2Ty, Context.getTable(Builder, ExecCtx, TableIndex),
1286
795
            Idx64));
1287
795
    auto FuncInstInt =
1288
795
        Builder.createExtractElement(FuncRef, LLContext.getInt64(1));
1289
795
    Builder.createCondBr(Builder.createLikely(Builder.createICmpNE(
1290
795
                             FuncInstInt, LLContext.getInt64(0))),
1291
795
                         NonNullBB, SlowBB);
1292
795
    Builder.positionAtEnd(NonNullBB);
1293
1294
795
    auto FuncInstPtr = Builder.createIntToPtr(FuncInstInt, Context.Int8PtrTy);
1295
2.38k
    auto LoadField = [&](uint64_t Off, LLVM::Type Ty) {
1296
2.38k
      return Builder.createLoad(
1297
2.38k
          Ty, Builder.createBitCast(
1298
2.38k
                  Builder.createInBoundsGEP1(Context.Int8Ty, FuncInstPtr,
1299
2.38k
                                             LLContext.getInt64(Off)),
1300
2.38k
                  Ty.getPointerTo()));
1301
2.38k
    };
1302
795
    using Runtime::Instance::FunctionInstance;
1303
795
    auto DefModule =
1304
795
        LoadField(FunctionInstance::getModuleOffset(), Context.Int8PtrTy);
1305
795
    auto CalleeTypeIdx =
1306
795
        LoadField(FunctionInstance::getTypeIndexOffset(), Context.Int32Ty);
1307
795
    auto Code =
1308
795
        LoadField(FunctionInstance::getCompiledCodeOffset(), Context.Int8PtrTy);
1309
795
    auto Hit = Builder.createAnd(
1310
795
        Builder.createAnd(
1311
795
            Builder.createICmpEQ(DefModule,
1312
795
                                 Context.getModuleInst(Builder, ExecCtx)),
1313
795
            Builder.createICmpEQ(CalleeTypeIdx, TypeIdx)),
1314
795
        Builder.createNot(Builder.createIsNull(Code)));
1315
795
    Builder.createCondBr(Builder.createLikely(Hit), FastBB, SlowBB);
1316
1317
795
    Builder.positionAtEnd(FastBB);
1318
795
    auto FastRet = Builder.createCall(
1319
795
        LLVM::FunctionCallee{FTy, Builder.createBitCast(Code, FPtrTy)},
1320
795
        ArgsVec);
1321
795
    FastRetsVec = UnpackRets(FastRet);
1322
795
    Builder.createBr(EndBB);
1323
795
  }
1324
1325
  // Slow path: resolve through the runtime, which handles cross-module, host,
1326
  // subtype, uninitialized, and not-yet-compiled cases.
1327
795
  Builder.positionAtEnd(SlowBB);
1328
795
  std::vector<LLVM::Value> FPtrRetsVec;
1329
795
  {
1330
795
    auto FPtr = Builder.createCall(
1331
795
        Context.getIntrinsic(
1332
795
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1333
795
            LLVM::Type::getFunctionType(
1334
795
                FPtrTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty},
1335
795
                false)),
1336
795
        {TableIdx, TypeIdx, FuncIndex});
1337
795
    Builder.createCondBr(
1338
795
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1339
795
        NotNullBB, IsNullBB);
1340
795
    Builder.positionAtEnd(NotNullBB);
1341
1342
795
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
1343
795
    FPtrRetsVec = UnpackRets(FPtrRet);
1344
795
  }
1345
1346
795
  Builder.createBr(EndBB);
1347
795
  Builder.positionAtEnd(IsNullBB);
1348
1349
795
  std::vector<LLVM::Value> RetsVec;
1350
795
  {
1351
795
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1352
795
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1353
795
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1354
795
                                Args, Context.Int8Ty, LLVM::kValSize);
1355
1356
795
    Builder.createCall(
1357
795
        Context.getIntrinsic(
1358
795
            Builder, Executable::Intrinsics::kCallIndirect,
1359
795
            LLVM::Type::getFunctionType(Context.VoidTy,
1360
795
                                        {Context.Int32Ty, Context.Int32Ty,
1361
795
                                         Context.Int32Ty, Context.Int8PtrTy,
1362
795
                                         Context.Int8PtrTy},
1363
795
                                        false)),
1364
795
        {TableIdx, TypeIdx, FuncIndex, Args, Rets});
1365
1366
795
    if (RetSize == 0) {
1367
      // nothing to do
1368
582
    } else if (RetSize == 1) {
1369
569
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1370
569
    } else {
1371
13
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1372
13
                                           LLVM::kValSize);
1373
13
    }
1374
795
    Builder.createBr(EndBB);
1375
795
    Builder.positionAtEnd(EndBB);
1376
795
  }
1377
1378
1.39k
  for (unsigned I = 0; I < RetSize; ++I) {
1379
595
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1380
595
    PHIRet.addIncoming(FastRetsVec[I], FastBB);
1381
595
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1382
595
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1383
595
    stackPush(PHIRet);
1384
595
  }
1385
795
}
1386
1387
void FunctionCompiler::compileReturnCallOp(
1388
65
    const unsigned int FuncIndex) noexcept {
1389
65
  const auto &FuncType =
1390
65
      Context.CompositeTypes[std::get<0>(Context.Functions[FuncIndex])]
1391
65
          ->getFuncType();
1392
65
  const auto &Function = std::get<1>(Context.Functions[FuncIndex]);
1393
65
  const auto &ParamTypes = FuncType.getParamTypes();
1394
1395
65
  std::vector<LLVM::Value> Args(ParamTypes.size() + 1);
1396
65
  Args[0] = F.Fn.getFirstParam();
1397
110
  for (size_t I = 0; I < ParamTypes.size(); ++I) {
1398
45
    const size_t J = ParamTypes.size() - 1 - I;
1399
45
    Args[J + 1] = stackPop();
1400
45
  }
1401
1402
65
  LLVM::Value Ret;
1403
65
  if (IsLazyJIT) {
1404
0
    bool IsImport = std::get<2>(Context.Functions[FuncIndex]) == nullptr;
1405
0
    if (IsImport) {
1406
0
      Ret = Builder.createCall(Function, Args);
1407
0
    } else {
1408
0
      auto FTy = toLLVMType(LLContext, Context.ExecCtxPtrTy, FuncType);
1409
1410
0
      if (Context.LazyJITCacheVars.size() <= FuncIndex) {
1411
0
        Context.LazyJITCacheVars.resize(Context.Functions.size());
1412
0
      }
1413
0
      auto &CacheVar = Context.LazyJITCacheVars[FuncIndex];
1414
0
      if (!CacheVar) {
1415
0
        CacheVar = Context.LLModule.get().addGlobal(
1416
0
            FTy.getPointerTo(), false, LLVMPrivateLinkage,
1417
0
            LLVM::Value::getConstNull(FTy.getPointerTo()), "");
1418
0
      }
1419
1420
0
      auto CheckBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.check");
1421
0
      auto ResolveBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.resolve");
1422
0
      auto CallBB = LLVM::BasicBlock::create(LLContext, F.Fn, "rc.call");
1423
1424
0
      Builder.createBr(CheckBB);
1425
0
      Builder.positionAtEnd(CheckBB);
1426
1427
0
      auto CachedPtr = Builder.createLoad(FTy.getPointerTo(), CacheVar, false);
1428
0
      CachedPtr.setAlignment(8);
1429
0
      CachedPtr.setOrdering(LLVMAtomicOrderingAcquire);
1430
0
      auto IsNull = Builder.createIsNull(CachedPtr);
1431
0
      auto IsNotNull = Builder.createLikely(Builder.createNot(IsNull));
1432
0
      Builder.createCondBr(IsNotNull, CallBB, ResolveBB);
1433
1434
0
      Builder.positionAtEnd(ResolveBB);
1435
0
      auto FPtr = Builder.createCall(
1436
0
          Context.getIntrinsic(
1437
0
              Builder, Executable::Intrinsics::kFuncGetFuncSymbol,
1438
0
              LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int32Ty},
1439
0
                                          false)),
1440
0
          {LLContext.getInt32(FuncIndex)});
1441
0
      auto Store = Builder.createStore(FPtr, CacheVar);
1442
0
      Store.setAlignment(8);
1443
0
      Store.setOrdering(LLVMAtomicOrderingRelease);
1444
0
      Builder.createBr(CallBB);
1445
1446
0
      Builder.positionAtEnd(CallBB);
1447
0
      auto FinalPtr = Builder.createPHI(FTy.getPointerTo());
1448
0
      FinalPtr.addIncoming(CachedPtr, CheckBB);
1449
0
      FinalPtr.addIncoming(FPtr, ResolveBB);
1450
1451
0
      Ret = Builder.createCall(LLVM::FunctionCallee(FTy, FinalPtr), Args);
1452
0
    }
1453
65
  } else {
1454
65
    Ret = Builder.createCall(Function, Args);
1455
65
  }
1456
1457
65
  Ret.setMustTailCall();
1458
65
  auto Ty = Ret.getType();
1459
65
  if (Ty.isVoidTy()) {
1460
22
    Builder.createRetVoid();
1461
43
  } else {
1462
43
    Builder.createRet(Ret);
1463
43
  }
1464
65
}
1465
1466
void FunctionCompiler::compileReturnIndirectCallOp(
1467
119
    const uint32_t TableIndex, const uint32_t FuncTypeIndex) noexcept {
1468
119
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.not_null");
1469
119
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.is_null");
1470
1471
119
  LLVM::Value FuncIndex = stackPop();
1472
119
  const auto &FuncType = Context.CompositeTypes[FuncTypeIndex]->getFuncType();
1473
119
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1474
119
  auto RTy = FTy.getReturnType();
1475
1476
119
  const size_t ArgSize = FuncType.getParamTypes().size();
1477
119
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1478
119
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1479
119
  ArgsVec[0] = F.Fn.getFirstParam();
1480
238
  for (size_t I = 0; I < ArgSize; ++I) {
1481
119
    const size_t J = ArgSize - I;
1482
119
    ArgsVec[J] = stackPop();
1483
119
  }
1484
1485
119
  {
1486
119
    auto FPtr = Builder.createCall(
1487
119
        Context.getIntrinsic(
1488
119
            Builder, Executable::Intrinsics::kTableGetFuncSymbol,
1489
119
            LLVM::Type::getFunctionType(
1490
119
                FTy.getPointerTo(),
1491
119
                {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)),
1492
119
        {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
1493
119
         FuncIndex});
1494
119
    Builder.createCondBr(
1495
119
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1496
119
        NotNullBB, IsNullBB);
1497
119
    Builder.positionAtEnd(NotNullBB);
1498
1499
119
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
1500
119
    FPtrRet.setMustTailCall();
1501
119
    if (RetSize == 0) {
1502
40
      Builder.createRetVoid();
1503
79
    } else {
1504
79
      Builder.createRet(FPtrRet);
1505
79
    }
1506
119
  }
1507
1508
119
  Builder.positionAtEnd(IsNullBB);
1509
1510
119
  {
1511
119
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1512
119
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1513
119
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1514
119
                                Args, Context.Int8Ty, LLVM::kValSize);
1515
1516
119
    Builder.createCall(
1517
119
        Context.getIntrinsic(
1518
119
            Builder, Executable::Intrinsics::kCallIndirect,
1519
119
            LLVM::Type::getFunctionType(Context.VoidTy,
1520
119
                                        {Context.Int32Ty, Context.Int32Ty,
1521
119
                                         Context.Int32Ty, Context.Int8PtrTy,
1522
119
                                         Context.Int8PtrTy},
1523
119
                                        false)),
1524
119
        {LLContext.getInt32(TableIndex), LLContext.getInt32(FuncTypeIndex),
1525
119
         FuncIndex, Args, Rets});
1526
1527
119
    if (RetSize == 0) {
1528
40
      Builder.createRetVoid();
1529
79
    } else if (RetSize == 1) {
1530
70
      Builder.createRet(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1531
70
    } else {
1532
9
      Builder.createAggregateRet(Builder.createArrayPtrLoad(
1533
9
          RetSize, RTy, Rets, Context.Int8Ty, LLVM::kValSize));
1534
9
    }
1535
119
  }
1536
119
}
1537
1538
193
void FunctionCompiler::compileCallRefOp(const unsigned int TypeIndex) noexcept {
1539
193
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1540
193
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
1541
193
  auto EndBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_i.end");
1542
1543
193
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1544
193
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
1545
193
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1546
193
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1547
193
      LLContext.getInt64(0)));
1548
193
  Builder.createCondBr(IsRefNotNull, OkBB,
1549
193
                       getTrapBB(ErrCode::Value::AccessNullFunc));
1550
193
  Builder.positionAtEnd(OkBB);
1551
1552
193
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
1553
193
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1554
193
  auto RTy = FTy.getReturnType();
1555
1556
193
  const size_t ArgSize = FuncType.getParamTypes().size();
1557
193
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1558
193
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1559
193
  ArgsVec[0] = F.Fn.getFirstParam();
1560
356
  for (size_t I = 0; I < ArgSize; ++I) {
1561
163
    const size_t J = ArgSize - I;
1562
163
    ArgsVec[J] = stackPop();
1563
163
  }
1564
1565
193
  std::vector<LLVM::Value> FPtrRetsVec;
1566
193
  FPtrRetsVec.reserve(RetSize);
1567
193
  {
1568
193
    auto FPtr = Builder.createCall(
1569
193
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1570
193
                             LLVM::Type::getFunctionType(FTy.getPointerTo(),
1571
193
                                                         {Context.Int64x2Ty},
1572
193
                                                         false)),
1573
193
        {Ref});
1574
193
    Builder.createCondBr(
1575
193
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1576
193
        NotNullBB, IsNullBB);
1577
193
    Builder.positionAtEnd(NotNullBB);
1578
1579
193
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee{FTy, FPtr}, ArgsVec);
1580
193
    if (RetSize == 0) {
1581
      // nothing to do
1582
108
    } else if (RetSize == 1) {
1583
73
      FPtrRetsVec.push_back(FPtrRet);
1584
73
    } else {
1585
24
      for (auto Val : unpackStruct(Builder, FPtrRet)) {
1586
24
        FPtrRetsVec.push_back(Val);
1587
24
      }
1588
12
    }
1589
193
  }
1590
1591
193
  Builder.createBr(EndBB);
1592
193
  Builder.positionAtEnd(IsNullBB);
1593
1594
193
  std::vector<LLVM::Value> RetsVec;
1595
193
  {
1596
193
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1597
193
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1598
193
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1599
193
                                Args, Context.Int8Ty, LLVM::kValSize);
1600
1601
193
    Builder.createCall(
1602
193
        Context.getIntrinsic(
1603
193
            Builder, Executable::Intrinsics::kCallRef,
1604
193
            LLVM::Type::getFunctionType(
1605
193
                Context.VoidTy,
1606
193
                {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
1607
193
                false)),
1608
193
        {Ref, Args, Rets});
1609
1610
193
    if (RetSize == 0) {
1611
      // nothing to do
1612
108
    } else if (RetSize == 1) {
1613
73
      RetsVec.push_back(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1614
73
    } else {
1615
12
      RetsVec = Builder.createArrayPtrLoad(RetSize, RTy, Rets, Context.Int8Ty,
1616
12
                                           LLVM::kValSize);
1617
12
    }
1618
193
    Builder.createBr(EndBB);
1619
193
    Builder.positionAtEnd(EndBB);
1620
193
  }
1621
1622
290
  for (unsigned I = 0; I < RetSize; ++I) {
1623
97
    auto PHIRet = Builder.createPHI(FPtrRetsVec[I].getType());
1624
97
    PHIRet.addIncoming(FPtrRetsVec[I], NotNullBB);
1625
97
    PHIRet.addIncoming(RetsVec[I], IsNullBB);
1626
97
    stackPush(PHIRet);
1627
97
  }
1628
193
}
1629
1630
void FunctionCompiler::compileReturnCallRefOp(
1631
49
    const unsigned int TypeIndex) noexcept {
1632
49
  auto NotNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.not_null");
1633
49
  auto IsNullBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.is_null");
1634
1635
49
  auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty);
1636
49
  auto OkBB = LLVM::BasicBlock::create(LLContext, F.Fn, "c_r.ref_not_null");
1637
49
  auto IsRefNotNull = Builder.createLikely(Builder.createICmpNE(
1638
49
      Builder.createExtractElement(Ref, LLContext.getInt64(1)),
1639
49
      LLContext.getInt64(0)));
1640
49
  Builder.createCondBr(IsRefNotNull, OkBB,
1641
49
                       getTrapBB(ErrCode::Value::AccessNullFunc));
1642
49
  Builder.positionAtEnd(OkBB);
1643
1644
49
  const auto &FuncType = Context.CompositeTypes[TypeIndex]->getFuncType();
1645
49
  auto FTy = toLLVMType(Context.LLContext, Context.ExecCtxPtrTy, FuncType);
1646
49
  auto RTy = FTy.getReturnType();
1647
1648
49
  const size_t ArgSize = FuncType.getParamTypes().size();
1649
49
  const size_t RetSize = RTy.isVoidTy() ? 0 : FuncType.getReturnTypes().size();
1650
49
  std::vector<LLVM::Value> ArgsVec(ArgSize + 1, nullptr);
1651
49
  ArgsVec[0] = F.Fn.getFirstParam();
1652
69
  for (size_t I = 0; I < ArgSize; ++I) {
1653
20
    const size_t J = ArgSize - I;
1654
20
    ArgsVec[J] = stackPop();
1655
20
  }
1656
1657
49
  {
1658
49
    auto FPtr = Builder.createCall(
1659
49
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefGetFuncSymbol,
1660
49
                             LLVM::Type::getFunctionType(FTy.getPointerTo(),
1661
49
                                                         {Context.Int64x2Ty},
1662
49
                                                         false)),
1663
49
        {Ref});
1664
49
    Builder.createCondBr(
1665
49
        Builder.createLikely(Builder.createNot(Builder.createIsNull(FPtr))),
1666
49
        NotNullBB, IsNullBB);
1667
49
    Builder.positionAtEnd(NotNullBB);
1668
1669
49
    auto FPtrRet = Builder.createCall(LLVM::FunctionCallee(FTy, FPtr), ArgsVec);
1670
49
    FPtrRet.setMustTailCall();
1671
49
    if (RetSize == 0) {
1672
32
      Builder.createRetVoid();
1673
32
    } else {
1674
17
      Builder.createRet(FPtrRet);
1675
17
    }
1676
49
  }
1677
1678
49
  Builder.positionAtEnd(IsNullBB);
1679
1680
49
  {
1681
49
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
1682
49
    LLVM::Value Rets = Builder.createArray(RetSize, LLVM::kValSize);
1683
49
    Builder.createArrayPtrStore(Span<LLVM::Value>(ArgsVec.begin() + 1, ArgSize),
1684
49
                                Args, Context.Int8Ty, LLVM::kValSize);
1685
1686
49
    Builder.createCall(
1687
49
        Context.getIntrinsic(
1688
49
            Builder, Executable::Intrinsics::kCallRef,
1689
49
            LLVM::Type::getFunctionType(
1690
49
                Context.VoidTy,
1691
49
                {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy},
1692
49
                false)),
1693
49
        {Ref, Args, Rets});
1694
1695
49
    if (RetSize == 0) {
1696
32
      Builder.createRetVoid();
1697
32
    } else if (RetSize == 1) {
1698
15
      Builder.createRet(Builder.createValuePtrLoad(RTy, Rets, Context.Int8Ty));
1699
15
    } else {
1700
2
      Builder.createAggregateRet(Builder.createArrayPtrLoad(
1701
2
          RetSize, RTy, Rets, Context.Int8Ty, LLVM::kValSize));
1702
2
    }
1703
49
  }
1704
49
}
1705
1706
void FunctionCompiler::enterBlock(
1707
    LLVM::BasicBlock JumpBlock, LLVM::BasicBlock NextBlock,
1708
    LLVM::BasicBlock ElseBlock, std::vector<LLVM::Value> Args,
1709
    std::pair<std::vector<ValType>, std::vector<ValType>> Type,
1710
    std::vector<std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
1711
21.3k
        ReturnPHI) noexcept {
1712
21.3k
  assuming(Type.first.size() == Args.size());
1713
21.3k
  for (auto &Value : Args) {
1714
4.27k
    stackPush(Value);
1715
4.27k
  }
1716
21.3k
  const auto Unreachable = isUnreachable();
1717
21.3k
  ControlStack.emplace_back(Stack.size() - Args.size(), Unreachable, JumpBlock,
1718
21.3k
                            NextBlock, ElseBlock, std::move(Args),
1719
21.3k
                            std::move(Type), std::move(ReturnPHI));
1720
21.3k
}
1721
1722
21.3k
FunctionCompiler::Control FunctionCompiler::leaveBlock() noexcept {
1723
21.3k
  Control Entry = std::move(ControlStack.back());
1724
21.3k
  ControlStack.pop_back();
1725
1726
21.3k
  auto NextBlock = Entry.NextBlock ? Entry.NextBlock : Entry.JumpBlock;
1727
21.3k
  if (!Entry.Unreachable) {
1728
12.8k
    const auto &ReturnType = Entry.Type.second;
1729
12.8k
    if (!ReturnType.empty()) {
1730
9.67k
      std::vector<LLVM::Value> Rets(ReturnType.size());
1731
19.7k
      for (size_t I = 0; I < Rets.size(); ++I) {
1732
10.0k
        const size_t J = Rets.size() - 1 - I;
1733
10.0k
        Rets[J] = stackPop();
1734
10.0k
      }
1735
9.67k
      Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
1736
9.67k
    }
1737
12.8k
    Builder.createBr(NextBlock);
1738
12.8k
  } else {
1739
8.47k
    Builder.createUnreachable();
1740
8.47k
  }
1741
21.3k
  Builder.positionAtEnd(NextBlock);
1742
21.3k
  Stack.erase(Stack.begin() + static_cast<int64_t>(Entry.StackSize),
1743
21.3k
              Stack.end());
1744
21.3k
  return Entry;
1745
21.3k
}
1746
1747
5.28k
void FunctionCompiler::checkStop() noexcept {
1748
5.28k
  if (!Interruptible) {
1749
5.28k
    return;
1750
5.28k
  }
1751
0
  auto NotStopBB = LLVM::BasicBlock::create(LLContext, F.Fn, "NotStop");
1752
0
  auto StopToken = Builder.createAtomicRMW(
1753
0
      LLVMAtomicRMWBinOpXchg, Context.getStopToken(Builder, ExecCtx),
1754
0
      LLContext.getInt32(0), LLVMAtomicOrderingMonotonic);
1755
#if LLVM_VERSION_MAJOR >= 13
1756
  StopToken.setAlignment(32);
1757
#endif
1758
0
  auto NotStop = Builder.createLikely(
1759
0
      Builder.createICmpEQ(StopToken, LLContext.getInt32(0)));
1760
0
  Builder.createCondBr(NotStop, NotStopBB,
1761
0
                       getTrapBB(ErrCode::Value::Interrupted));
1762
1763
0
  Builder.positionAtEnd(NotStopBB);
1764
0
}
1765
1766
5.84k
void FunctionCompiler::setUnreachable() noexcept {
1767
5.84k
  if (ControlStack.empty()) {
1768
0
    IsUnreachable = true;
1769
5.84k
  } else {
1770
5.84k
    ControlStack.back().Unreachable = true;
1771
5.84k
  }
1772
5.84k
}
1773
1774
1.49M
bool FunctionCompiler::isUnreachable() const noexcept {
1775
1.49M
  if (ControlStack.empty()) {
1776
10.5k
    return IsUnreachable;
1777
1.48M
  } else {
1778
1.48M
    return ControlStack.back().Unreachable;
1779
1.48M
  }
1780
1.49M
}
1781
1782
void FunctionCompiler::buildPHI(
1783
    Span<const ValType> RetType,
1784
    Span<const std::tuple<std::vector<LLVM::Value>, LLVM::BasicBlock>>
1785
18.5k
        Incomings) noexcept {
1786
18.5k
  if (LLVM::isVoidReturn(RetType)) {
1787
6.03k
    return;
1788
6.03k
  }
1789
12.5k
  std::vector<LLVM::Value> Nodes;
1790
12.5k
  if (Incomings.size() == 0) {
1791
2.78k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
1792
2.78k
    Nodes.reserve(Types.size());
1793
3.27k
    for (LLVM::Type Type : Types) {
1794
3.27k
      Nodes.push_back(LLVM::Value::getUndef(Type));
1795
3.27k
    }
1796
9.74k
  } else if (Incomings.size() == 1) {
1797
8.67k
    Nodes = std::move(std::get<0>(Incomings.front()));
1798
8.67k
  } else {
1799
1.07k
    const auto &Types = toLLVMTypeVector(LLContext, RetType);
1800
1.07k
    Nodes.reserve(Types.size());
1801
2.23k
    for (size_t I = 0; I < Types.size(); ++I) {
1802
1.16k
      auto PHIRet = Builder.createPHI(Types[I]);
1803
3.04k
      for (auto &[Value, BB] : Incomings) {
1804
3.04k
        assuming(Value.size() == Types.size());
1805
3.04k
        PHIRet.addIncoming(Value[I], BB);
1806
3.04k
      }
1807
1.16k
      Nodes.push_back(PHIRet);
1808
1.16k
    }
1809
1.07k
  }
1810
13.4k
  for (auto &Val : Nodes) {
1811
13.4k
    stackPush(Val);
1812
13.4k
  }
1813
12.5k
}
1814
1815
21.3k
void FunctionCompiler::setLableJumpPHI(unsigned int Index) noexcept {
1816
21.3k
  assuming(Index < ControlStack.size());
1817
21.3k
  auto &Entry = *(ControlStack.rbegin() + Index);
1818
21.3k
  if (Entry.NextBlock) { // is loop
1819
2.20k
    std::vector<LLVM::Value> Args(Entry.Type.first.size());
1820
4.68k
    for (size_t I = 0; I < Args.size(); ++I) {
1821
2.48k
      const size_t J = Args.size() - 1 - I;
1822
2.48k
      Args[J] = stackPop();
1823
2.48k
    }
1824
4.68k
    for (size_t I = 0; I < Args.size(); ++I) {
1825
2.48k
      Entry.Args[I].addIncoming(Args[I], Builder.getInsertBlock());
1826
2.48k
      stackPush(Args[I]);
1827
2.48k
    }
1828
19.1k
  } else if (!Entry.Type.second.empty()) { // has return value
1829
1.84k
    std::vector<LLVM::Value> Rets(Entry.Type.second.size());
1830
3.81k
    for (size_t I = 0; I < Rets.size(); ++I) {
1831
1.96k
      const size_t J = Rets.size() - 1 - I;
1832
1.96k
      Rets[J] = stackPop();
1833
1.96k
    }
1834
3.81k
    for (size_t I = 0; I < Rets.size(); ++I) {
1835
1.96k
      stackPush(Rets[I]);
1836
1.96k
    }
1837
1.84k
    Entry.ReturnPHI.emplace_back(std::move(Rets), Builder.getInsertBlock());
1838
1.84k
  }
1839
21.3k
}
1840
1841
21.3k
LLVM::BasicBlock FunctionCompiler::getLabel(unsigned int Index) const noexcept {
1842
21.3k
  return (ControlStack.rbegin() + Index)->JumpBlock;
1843
21.3k
}
1844
1845
332k
LLVM::Value FunctionCompiler::stackPop() noexcept {
1846
332k
  assuming(!ControlStack.empty() || !Stack.empty());
1847
332k
  assuming(ControlStack.empty() ||
1848
332k
           Stack.size() > ControlStack.back().StackSize);
1849
332k
  auto Value = Stack.back();
1850
332k
  Stack.pop_back();
1851
332k
  return Value;
1852
332k
}
1853
1854
21.5k
LLVM::Value FunctionCompiler::switchEndian(LLVM::Value Value) {
1855
  if constexpr (Endian::native == Endian::big) {
1856
    auto Type = Value.getType();
1857
    if ((Type.isIntegerTy() && Type.getIntegerBitWidth() > 8) ||
1858
        (Type.isVectorTy() && Type.getVectorSize() == 1)) {
1859
      return Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
1860
    }
1861
    if (Type.isVectorTy()) {
1862
      LLVM::Type VecType = Type.getElementType().getIntegerBitWidth() == 128
1863
                               ? Context.Int128Ty
1864
                               : Context.Int64Ty;
1865
      Value = Builder.createBitCast(Value, VecType);
1866
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
1867
      return Builder.createBitCast(Value, Type);
1868
    }
1869
    if (Type.isFloatTy() || Type.isDoubleTy()) {
1870
      LLVM::Type IntType = Type.isFloatTy() ? Context.Int32Ty : Context.Int64Ty;
1871
      Value = Builder.createBitCast(Value, IntType);
1872
      Value = Builder.createUnaryIntrinsic(LLVM::Core::Bswap, Value);
1873
      return Builder.createBitCast(Value, Type);
1874
    }
1875
  }
1876
21.5k
  return Value;
1877
21.5k
}
1878
1879
} // namespace WasmEdge