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/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
18.9k
                        uint32_t Index) noexcept {
121
18.9k
    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
18.9k
    auto VPtrPtr = Builder.createLoad(
130
18.9k
        Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array,
131
18.9k
                                                 LLContext.getInt64(Index)));
132
18.9k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
133
18.9k
                        LLVM::Metadata(LLContext, {}));
134
18.9k
    auto VPtr = Builder.createLoad(
135
18.9k
        Int8PtrTy,
136
18.9k
        Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0)));
137
18.9k
#endif
138
18.9k
    return Builder.createBitCast(VPtr, Int8PtrTy);
139
18.9k
  }
140
  LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ModCtx,
141
653
                            uint32_t Index) noexcept {
142
653
    auto Array = Builder.createExtractValue(ModCtx, 1);
143
653
    auto VPtr = Builder.createLoad(
144
653
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
145
653
                                               LLContext.getInt64(Index)));
146
653
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
147
653
                     LLVM::Metadata(LLContext, {}));
148
653
    return Builder.createLoad(Int64Ty, VPtr);
149
653
  }
150
  LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ModCtx,
151
980
                       uint32_t Index) noexcept {
152
980
    auto RefPtrTy = Int64x2Ty.getPointerTo();
153
980
    auto Array = Builder.createExtractValue(ModCtx, 2);
154
980
    auto VPtrPtr = Builder.createLoad(
155
980
        RefPtrTy.getPointerTo(),
156
980
        Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array,
157
980
                                   LLContext.getInt64(Index)));
158
980
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
159
980
                        LLVM::Metadata(LLContext, {}));
160
980
    return Builder.createLoad(
161
980
        RefPtrTy,
162
980
        Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0)));
163
980
  }
164
  LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ModCtx,
165
995
                           uint32_t Index) noexcept {
166
995
    auto Array = Builder.createExtractValue(ModCtx, 3);
167
995
    auto VPtr = Builder.createLoad(
168
995
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
169
995
                                               LLContext.getInt64(Index)));
170
995
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
171
995
                     LLVM::Metadata(LLContext, {}));
172
995
    return Builder.createLoad(Int64Ty, VPtr);
173
995
  }
174
  LLVM::Value getModuleInst(LLVM::Builder &Builder,
175
6.53k
                            LLVM::Value ModCtx) noexcept {
176
6.53k
    return Builder.createExtractValue(ModCtx, 5);
177
6.53k
  }
178
  std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder,
179
                                               LLVM::Value ModCtx,
180
563
                                               uint32_t Index) noexcept {
181
563
    auto Ty = Globals[Index];
182
563
    auto Array = Builder.createExtractValue(ModCtx, 4);
183
563
    auto VPtr = Builder.createLoad(
184
563
        Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
185
563
                                                LLContext.getInt64(Index)));
186
563
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
187
563
                     LLVM::Metadata(LLContext, {}));
188
563
    auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo());
189
563
    return {Ty, Ptr};
190
563
  }
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.43k
                                   LLVM::Value ExecCtx) noexcept {
203
4.43k
    return Builder.createExtractValue(ExecCtx, 5);
204
4.43k
  }
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::Value getStackLimit(LLVM::Builder &Builder,
225
2.72k
                            LLVM::Value ExecCtx) noexcept {
226
2.72k
    return Builder.createExtractValue(ExecCtx, 6);
227
2.72k
  }
228
  LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder,
229
                                    Executable::Intrinsics Index,
230
8.00k
                                    LLVM::Type Ty) noexcept {
231
8.00k
    const auto Value = static_cast<uint32_t>(Index);
232
8.00k
    auto PtrTy = Ty.getPointerTo();
233
8.00k
    auto PtrPtrTy = PtrTy.getPointerTo();
234
8.00k
    auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable);
235
8.00k
    IT.setMetadata(LLContext, LLVM::Core::InvariantGroup,
236
8.00k
                   LLVM::Metadata(LLContext, {}));
237
8.00k
    auto VPtr =
238
8.00k
        Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0),
239
8.00k
                                   LLContext.getInt64(Value));
240
8.00k
    auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy);
241
8.00k
    return {Ty, Builder.createLoad(PtrTy, Ptr)};
242
8.00k
  }
243
2.28k
  void compileTrap() noexcept {
244
2.28k
    LLVM::Builder Builder(LLContext);
245
2.28k
    Builder.positionAtEnd(
246
2.28k
        LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry"));
247
2.28k
    auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
248
2.28k
    auto CallTrap = Builder.createCall(
249
2.28k
        getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy),
250
2.28k
        {Trap.Fn.getFirstParam()});
251
2.28k
    CallTrap.addCallSiteAttribute(NoReturn);
252
2.28k
    Builder.createUnreachable();
253
2.28k
  }
254
2.28k
  void addVersionGlobal() noexcept {
255
2.28k
    LLModule.get().addGlobal(
256
2.28k
        Int32Ty, true, LLVMExternalLinkage,
257
2.28k
        LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version");
258
2.28k
  }
259
2.27k
  void finalizeIntrinsicsTable() noexcept {
260
2.27k
    if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) {
261
1.60k
      Table.setInitializer(LLVM::Value::getConstNull(IntrinsicsTablePtrTy));
262
1.60k
      Table.setGlobalConstant(false);
263
1.60k
    } else {
264
677
      LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage,
265
677
                               LLVM::Value::getConstNull(IntrinsicsTablePtrTy),
266
677
                               "intrinsics");
267
677
    }
268
2.27k
  }
269
  std::pair<std::vector<ValType>, std::vector<ValType>>
270
18.8k
  resolveBlockType(const BlockType &BType) const noexcept {
271
18.8k
    using VecT = std::vector<ValType>;
272
18.8k
    using RetT = std::pair<VecT, VecT>;
273
18.8k
    if (BType.isEmpty()) {
274
2.28k
      return RetT{};
275
2.28k
    }
276
16.5k
    if (BType.isValType()) {
277
2.51k
      return RetT{{}, {BType.getValType()}};
278
14.0k
    } else {
279
      // Type index case. t2* = type[index].returns
280
14.0k
      const uint32_t TypeIdx = BType.getTypeIndex();
281
14.0k
      const auto &FType = CompositeTypes[TypeIdx]->getFuncType();
282
14.0k
      return RetT{
283
14.0k
          VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()),
284
14.0k
          VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())};
285
14.0k
    }
286
16.5k
  }
287
};
288
289
bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
290
LLVM::Type toLLVMType(LLVM::Context LLContext,
291
                      const WasmEdge::ValType &ValType) noexcept;
292
std::vector<LLVM::Type>
293
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
294
               LLVM::Type ExecCtxPtrTy,
295
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
296
LLVM::Type
297
toLLVMRetsType(LLVM::Context LLContext,
298
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
299
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
300
                      LLVM::Type ExecCtxPtrTy,
301
                      const WasmEdge::AST::FunctionType &FuncType) noexcept;
302
LLVM::Value
303
toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType,
304
                   WasmEdge::Span<const WasmEdge::AST::CompositeType *const>
305
                       CompositeTypes) noexcept;
306
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
307
                                      LLVM::Value Struct) noexcept;
308
LLVM::Type toLLVMType(LLVM::Context LLContext,
309
                      const WasmEdge::AddressType AddrType) noexcept;
310
std::vector<LLVM::Type>
311
toLLVMTypeVector(LLVM::Context LLContext,
312
                 WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
313
314
} // namespace WasmEdge::LLVM