Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler/context.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
#pragma once
4
5
#include "llvm/compiler.h"
6
7
#include "llvm.h"
8
9
#include "aot/version.h"
10
#include "system/allocator.h"
11
12
#include <cstdint>
13
#include <functional>
14
15
#include <tuple>
16
#include <utility>
17
#include <vector>
18
19
namespace WasmEdge::LLVM {
20
21
// XXX: Misalignment handler not implemented yet, forcing unalignment
22
// force unalignment load/store
23
inline constexpr const bool kForceUnalignment = true;
24
25
// force checking div/rem on zero
26
inline constexpr const bool kForceDivCheck = true;
27
28
// Size of a ValVariant
29
inline constexpr const uint32_t kValSize = sizeof(WasmEdge::ValVariant);
30
31
struct Compiler::CompileContext {
32
  LLVM::Context LLContext;
33
  std::reference_wrapper<LLVM::Module> LLModule;
34
  LLVM::Attribute Cold;
35
  LLVM::Attribute NoAlias;
36
  LLVM::Attribute NoInline;
37
  LLVM::Attribute NoReturn;
38
  LLVM::Attribute ReadOnly;
39
  LLVM::Attribute StrictFP;
40
  LLVM::Attribute UWTable;
41
  LLVM::Attribute NoStackArgProbe;
42
  LLVM::Type VoidTy;
43
  LLVM::Type Int8Ty;
44
  LLVM::Type Int16Ty;
45
  LLVM::Type Int32Ty;
46
  LLVM::Type Int64Ty;
47
  LLVM::Type Int128Ty;
48
  LLVM::Type FloatTy;
49
  LLVM::Type DoubleTy;
50
  LLVM::Type Int8x16Ty;
51
  LLVM::Type Int16x8Ty;
52
  LLVM::Type Int32x4Ty;
53
  LLVM::Type Floatx4Ty;
54
  LLVM::Type Int64x2Ty;
55
  LLVM::Type Doublex2Ty;
56
  LLVM::Type Int128x1Ty;
57
  LLVM::Type Int8PtrTy;
58
  LLVM::Type Int32PtrTy;
59
  LLVM::Type Int64PtrTy;
60
  LLVM::Type Int128PtrTy;
61
  LLVM::Type Int8PtrPtrTy;
62
  LLVM::Type ModCtxTy;
63
  LLVM::Type ModCtxPtrTy;
64
  LLVM::Type ExecCtxTy;
65
  LLVM::Type ExecCtxPtrTy;
66
  LLVM::Type IntrinsicsTableTy;
67
  LLVM::Type IntrinsicsTablePtrTy;
68
  LLVM::Message SubtargetFeatures;
69
70
#if defined(__x86_64__)
71
#if defined(__XOP__)
72
  bool SupportXOP = true;
73
#else
74
  bool SupportXOP = false;
75
#endif
76
77
#if defined(__SSE4_1__)
78
  bool SupportSSE4_1 = true;
79
#else
80
  bool SupportSSE4_1 = false;
81
#endif
82
83
#if defined(__SSSE3__)
84
  bool SupportSSSE3 = true;
85
#else
86
  bool SupportSSSE3 = false;
87
#endif
88
89
#if defined(__SSE2__)
90
  bool SupportSSE2 = true;
91
#else
92
  bool SupportSSE2 = false;
93
#endif
94
#endif
95
96
#if defined(__aarch64__)
97
#if defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__ARM_NEON_FP)
98
  bool SupportNEON = true;
99
#else
100
  bool SupportNEON = false;
101
#endif
102
#endif
103
104
  std::vector<const AST::CompositeType *> CompositeTypes;
105
  std::vector<LLVM::Value> FunctionWrappers;
106
  std::vector<std::tuple<uint32_t, LLVM::FunctionCallee,
107
                         const WasmEdge::AST::CodeSegment *>>
108
      Functions;
109
  std::vector<LLVM::Value> LazyJITCacheVars;
110
  uint32_t ImportCount = 0;
111
  std::vector<LLVM::Type> MemoryAddrTypes;
112
  std::vector<LLVM::Type> TableAddrTypes;
113
  std::vector<LLVM::Type> Globals;
114
  std::vector<uint32_t> Tags;
115
  LLVM::Value IntrinsicsTable;
116
  LLVM::FunctionCallee Trap;
117
  CompileContext(LLVM::Context C, LLVM::Module &M,
118
                 bool IsGenericBinary) noexcept;
119
  LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ModCtx,
120
20.7k
                        uint32_t Index) noexcept {
121
20.7k
    auto Array = Builder.createExtractValue(ModCtx, 0);
122
#if WASMEDGE_ALLOCATOR_IS_STABLE
123
    auto VPtr = Builder.createLoad(
124
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
125
                                              LLContext.getInt64(Index)));
126
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
127
                     LLVM::Metadata(LLContext, {}));
128
#else
129
20.7k
    auto VPtrPtr = Builder.createLoad(
130
20.7k
        Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array,
131
20.7k
                                                 LLContext.getInt64(Index)));
132
20.7k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
133
20.7k
                        LLVM::Metadata(LLContext, {}));
134
20.7k
    auto VPtr = Builder.createLoad(
135
20.7k
        Int8PtrTy,
136
20.7k
        Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0)));
137
20.7k
#endif
138
20.7k
    return Builder.createBitCast(VPtr, Int8PtrTy);
139
20.7k
  }
140
  LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ModCtx,
141
698
                            uint32_t Index) noexcept {
142
698
    auto Array = Builder.createExtractValue(ModCtx, 1);
143
698
    auto VPtr = Builder.createLoad(
144
698
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
145
698
                                               LLContext.getInt64(Index)));
146
698
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
147
698
                     LLVM::Metadata(LLContext, {}));
148
698
    return Builder.createLoad(Int64Ty, VPtr);
149
698
  }
150
  LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ModCtx,
151
1.05k
                       uint32_t Index) noexcept {
152
1.05k
    auto RefPtrTy = Int64x2Ty.getPointerTo();
153
1.05k
    auto Array = Builder.createExtractValue(ModCtx, 2);
154
1.05k
    auto VPtrPtr = Builder.createLoad(
155
1.05k
        RefPtrTy.getPointerTo(),
156
1.05k
        Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array,
157
1.05k
                                   LLContext.getInt64(Index)));
158
1.05k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
159
1.05k
                        LLVM::Metadata(LLContext, {}));
160
1.05k
    return Builder.createLoad(
161
1.05k
        RefPtrTy,
162
1.05k
        Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0)));
163
1.05k
  }
164
  LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ModCtx,
165
1.07k
                           uint32_t Index) noexcept {
166
1.07k
    auto Array = Builder.createExtractValue(ModCtx, 3);
167
1.07k
    auto VPtr = Builder.createLoad(
168
1.07k
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
169
1.07k
                                               LLContext.getInt64(Index)));
170
1.07k
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
171
1.07k
                     LLVM::Metadata(LLContext, {}));
172
1.07k
    return Builder.createLoad(Int64Ty, VPtr);
173
1.07k
  }
174
  LLVM::Value getModuleInst(LLVM::Builder &Builder,
175
6.78k
                            LLVM::Value ModCtx) noexcept {
176
6.78k
    return Builder.createExtractValue(ModCtx, 5);
177
6.78k
  }
178
  std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder,
179
                                               LLVM::Value ModCtx,
180
448
                                               uint32_t Index) noexcept {
181
448
    auto Ty = Globals[Index];
182
448
    auto Array = Builder.createExtractValue(ModCtx, 4);
183
448
    auto VPtr = Builder.createLoad(
184
448
        Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
185
448
                                                LLContext.getInt64(Index)));
186
448
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
187
448
                     LLVM::Metadata(LLContext, {}));
188
448
    auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo());
189
448
    return {Ty, Ptr};
190
448
  }
191
  LLVM::Value getTag(LLVM::Builder &Builder, LLVM::Value ModCtx,
192
0
                     uint32_t Index) noexcept {
193
0
    auto Array = Builder.createExtractValue(ModCtx, 6);
194
0
    auto VPtr = Builder.createLoad(
195
0
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
196
0
                                              LLContext.getInt64(Index)));
197
0
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
198
0
                     LLVM::Metadata(LLContext, {}));
199
0
    return VPtr;
200
0
  }
201
  LLVM::Value getPendingExnTagAddr(LLVM::Builder &Builder,
202
4.28k
                                   LLVM::Value ExecCtx) noexcept {
203
4.28k
    return Builder.createExtractValue(ExecCtx, 5);
204
4.28k
  }
205
  LLVM::Value getInstrCount(LLVM::Builder &Builder,
206
0
                            LLVM::Value ExecCtx) noexcept {
207
0
    return Builder.createExtractValue(ExecCtx, 0);
208
0
  }
209
  LLVM::Value getCostTable(LLVM::Builder &Builder,
210
0
                           LLVM::Value ExecCtx) noexcept {
211
0
    return Builder.createExtractValue(ExecCtx, 1);
212
0
  }
213
0
  LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept {
214
0
    return Builder.createExtractValue(ExecCtx, 2);
215
0
  }
216
  LLVM::Value getGasLimit(LLVM::Builder &Builder,
217
0
                          LLVM::Value ExecCtx) noexcept {
218
0
    return Builder.createExtractValue(ExecCtx, 3);
219
0
  }
220
  LLVM::Value getStopToken(LLVM::Builder &Builder,
221
0
                           LLVM::Value ExecCtx) noexcept {
222
0
    return Builder.createExtractValue(ExecCtx, 4);
223
0
  }
224
  LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder,
225
                                    Executable::Intrinsics Index,
226
8.20k
                                    LLVM::Type Ty) noexcept {
227
8.20k
    const auto Value = static_cast<uint32_t>(Index);
228
8.20k
    auto PtrTy = Ty.getPointerTo();
229
8.20k
    auto PtrPtrTy = PtrTy.getPointerTo();
230
8.20k
    auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable);
231
8.20k
    IT.setMetadata(LLContext, LLVM::Core::InvariantGroup,
232
8.20k
                   LLVM::Metadata(LLContext, {}));
233
8.20k
    auto VPtr =
234
8.20k
        Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0),
235
8.20k
                                   LLContext.getInt64(Value));
236
8.20k
    auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy);
237
8.20k
    return {Ty, Builder.createLoad(PtrTy, Ptr)};
238
8.20k
  }
239
2.31k
  void compileTrap() noexcept {
240
2.31k
    LLVM::Builder Builder(LLContext);
241
2.31k
    Builder.positionAtEnd(
242
2.31k
        LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry"));
243
2.31k
    auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
244
2.31k
    auto CallTrap = Builder.createCall(
245
2.31k
        getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy),
246
2.31k
        {Trap.Fn.getFirstParam()});
247
2.31k
    CallTrap.addCallSiteAttribute(NoReturn);
248
2.31k
    Builder.createUnreachable();
249
2.31k
  }
250
2.31k
  void addVersionGlobal() noexcept {
251
2.31k
    LLModule.get().addGlobal(
252
2.31k
        Int32Ty, true, LLVMExternalLinkage,
253
2.31k
        LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version");
254
2.31k
  }
255
2.04k
  void finalizeIntrinsicsTable() noexcept {
256
2.04k
    if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) {
257
1.32k
      Table.setInitializer(LLVM::Value::getConstNull(Table.getType()));
258
1.32k
      Table.setGlobalConstant(false);
259
1.32k
    } else {
260
720
      LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage,
261
720
                               LLVM::Value::getConstNull(IntrinsicsTablePtrTy),
262
720
                               "intrinsics");
263
720
    }
264
2.04k
  }
265
  std::pair<std::vector<ValType>, std::vector<ValType>>
266
19.6k
  resolveBlockType(const BlockType &BType) const noexcept {
267
19.6k
    using VecT = std::vector<ValType>;
268
19.6k
    using RetT = std::pair<VecT, VecT>;
269
19.6k
    if (BType.isEmpty()) {
270
2.25k
      return RetT{};
271
2.25k
    }
272
17.3k
    if (BType.isValType()) {
273
2.49k
      return RetT{{}, {BType.getValType()}};
274
14.8k
    } else {
275
      // Type index case. t2* = type[index].returns
276
14.8k
      const uint32_t TypeIdx = BType.getTypeIndex();
277
14.8k
      const auto &FType = CompositeTypes[TypeIdx]->getFuncType();
278
14.8k
      return RetT{
279
14.8k
          VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()),
280
14.8k
          VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())};
281
14.8k
    }
282
17.3k
  }
283
};
284
285
bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
286
LLVM::Type toLLVMType(LLVM::Context LLContext,
287
                      const WasmEdge::ValType &ValType) noexcept;
288
std::vector<LLVM::Type>
289
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
290
               LLVM::Type ExecCtxPtrTy,
291
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
292
LLVM::Type
293
toLLVMRetsType(LLVM::Context LLContext,
294
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
295
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
296
                      LLVM::Type ExecCtxPtrTy,
297
                      const WasmEdge::AST::FunctionType &FuncType) noexcept;
298
LLVM::Value
299
toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType,
300
                   WasmEdge::Span<const WasmEdge::AST::CompositeType *const>
301
                       CompositeTypes) noexcept;
302
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
303
                                      LLVM::Value Struct) noexcept;
304
LLVM::Type toLLVMType(LLVM::Context LLContext,
305
                      const WasmEdge::AddressType AddrType) noexcept;
306
std::vector<LLVM::Type>
307
toLLVMTypeVector(LLVM::Context LLContext,
308
                 WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
309
310
} // namespace WasmEdge::LLVM