Coverage Report

Created: 2026-11-09 06:49

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