Coverage Report

Created: 2026-09-28 06:22

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