Coverage Report

Created: 2026-08-14 06:41

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