Coverage Report

Created: 2026-08-14 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler/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 ExecCtxTy;
63
  LLVM::Type ExecCtxPtrTy;
64
  LLVM::Type IntrinsicsTableTy;
65
  LLVM::Type IntrinsicsTablePtrTy;
66
  LLVM::Message SubtargetFeatures;
67
68
#if defined(__x86_64__)
69
#if defined(__XOP__)
70
  bool SupportXOP = true;
71
#else
72
  bool SupportXOP = false;
73
#endif
74
75
#if defined(__SSE4_1__)
76
  bool SupportSSE4_1 = true;
77
#else
78
  bool SupportSSE4_1 = false;
79
#endif
80
81
#if defined(__SSSE3__)
82
  bool SupportSSSE3 = true;
83
#else
84
  bool SupportSSSE3 = false;
85
#endif
86
87
#if defined(__SSE2__)
88
  bool SupportSSE2 = true;
89
#else
90
  bool SupportSSE2 = false;
91
#endif
92
#endif
93
94
#if defined(__aarch64__)
95
#if defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__ARM_NEON_FP)
96
  bool SupportNEON = true;
97
#else
98
  bool SupportNEON = false;
99
#endif
100
#endif
101
102
  std::vector<const AST::CompositeType *> CompositeTypes;
103
  std::vector<LLVM::Value> FunctionWrappers;
104
  std::vector<std::tuple<uint32_t, LLVM::FunctionCallee,
105
                         const WasmEdge::AST::CodeSegment *>>
106
      Functions;
107
  std::vector<LLVM::Value> LazyJITCacheVars;
108
  uint32_t ImportCount = 0;
109
  std::vector<LLVM::Type> MemoryAddrTypes;
110
  std::vector<LLVM::Type> TableAddrTypes;
111
  std::vector<LLVM::Type> Globals;
112
  std::vector<uint32_t> Tags;
113
  LLVM::Value IntrinsicsTable;
114
  LLVM::FunctionCallee Trap;
115
  CompileContext(LLVM::Context C, LLVM::Module &M,
116
                 bool IsGenericBinary) noexcept;
117
  LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ExecCtx,
118
21.8k
                        uint32_t Index) noexcept {
119
21.8k
    auto Array = Builder.createExtractValue(ExecCtx, 0);
120
#if WASMEDGE_ALLOCATOR_IS_STABLE
121
    auto VPtr = Builder.createLoad(
122
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
123
                                              LLContext.getInt64(Index)));
124
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
125
                     LLVM::Metadata(LLContext, {}));
126
#else
127
21.8k
    auto VPtrPtr = Builder.createLoad(
128
21.8k
        Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array,
129
21.8k
                                                 LLContext.getInt64(Index)));
130
21.8k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
131
21.8k
                        LLVM::Metadata(LLContext, {}));
132
21.8k
    auto VPtr = Builder.createLoad(
133
21.8k
        Int8PtrTy,
134
21.8k
        Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0)));
135
21.8k
#endif
136
21.8k
    return Builder.createBitCast(VPtr, Int8PtrTy);
137
21.8k
  }
138
  LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ExecCtx,
139
767
                            uint32_t Index) noexcept {
140
767
    auto Array = Builder.createExtractValue(ExecCtx, 1);
141
767
    auto VPtr = Builder.createLoad(
142
767
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
143
767
                                               LLContext.getInt64(Index)));
144
767
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
145
767
                     LLVM::Metadata(LLContext, {}));
146
767
    return Builder.createLoad(Int64Ty, VPtr);
147
767
  }
148
  LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ExecCtx,
149
1.00k
                       uint32_t Index) noexcept {
150
1.00k
    auto RefPtrTy = Int64x2Ty.getPointerTo();
151
1.00k
    auto Array = Builder.createExtractValue(ExecCtx, 2);
152
1.00k
    auto VPtrPtr = Builder.createLoad(
153
1.00k
        RefPtrTy.getPointerTo(),
154
1.00k
        Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array,
155
1.00k
                                   LLContext.getInt64(Index)));
156
1.00k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
157
1.00k
                        LLVM::Metadata(LLContext, {}));
158
1.00k
    return Builder.createLoad(
159
1.00k
        RefPtrTy,
160
1.00k
        Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0)));
161
1.00k
  }
162
  LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ExecCtx,
163
1.02k
                           uint32_t Index) noexcept {
164
1.02k
    auto Array = Builder.createExtractValue(ExecCtx, 3);
165
1.02k
    auto VPtr = Builder.createLoad(
166
1.02k
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
167
1.02k
                                               LLContext.getInt64(Index)));
168
1.02k
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
169
1.02k
                     LLVM::Metadata(LLContext, {}));
170
1.02k
    return Builder.createLoad(Int64Ty, VPtr);
171
1.02k
  }
172
  std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder,
173
                                               LLVM::Value ExecCtx,
174
462
                                               uint32_t Index) noexcept {
175
462
    auto Ty = Globals[Index];
176
462
    auto Array = Builder.createExtractValue(ExecCtx, 4);
177
462
    auto VPtr = Builder.createLoad(
178
462
        Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
179
462
                                                LLContext.getInt64(Index)));
180
462
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
181
462
                     LLVM::Metadata(LLContext, {}));
182
462
    auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo());
183
462
    return {Ty, Ptr};
184
462
  }
185
  LLVM::Value getTag(LLVM::Builder &Builder, LLVM::Value ExecCtx,
186
0
                     uint32_t Index) noexcept {
187
0
    auto Array = Builder.createExtractValue(ExecCtx, 5);
188
0
    auto VPtr = Builder.createLoad(
189
0
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
190
0
                                              LLContext.getInt64(Index)));
191
0
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
192
0
                     LLVM::Metadata(LLContext, {}));
193
0
    return VPtr;
194
0
  }
195
  LLVM::Value getPendingExnTagAddr(LLVM::Builder &Builder,
196
4.16k
                                   LLVM::Value ExecCtx) noexcept {
197
4.16k
    return Builder.createExtractValue(ExecCtx, 6);
198
4.16k
  }
199
  LLVM::Value getInstrCount(LLVM::Builder &Builder,
200
0
                            LLVM::Value ExecCtx) noexcept {
201
0
    return Builder.createExtractValue(ExecCtx, 7);
202
0
  }
203
  LLVM::Value getCostTable(LLVM::Builder &Builder,
204
0
                           LLVM::Value ExecCtx) noexcept {
205
0
    return Builder.createExtractValue(ExecCtx, 8);
206
0
  }
207
0
  LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept {
208
0
    return Builder.createExtractValue(ExecCtx, 9);
209
0
  }
210
  LLVM::Value getGasLimit(LLVM::Builder &Builder,
211
0
                          LLVM::Value ExecCtx) noexcept {
212
0
    return Builder.createExtractValue(ExecCtx, 10);
213
0
  }
214
  LLVM::Value getStopToken(LLVM::Builder &Builder,
215
0
                           LLVM::Value ExecCtx) noexcept {
216
0
    return Builder.createExtractValue(ExecCtx, 11);
217
0
  }
218
  LLVM::Value getModuleInst(LLVM::Builder &Builder,
219
927
                            LLVM::Value ExecCtx) noexcept {
220
927
    return Builder.createExtractValue(ExecCtx, 12);
221
927
  }
222
  LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder,
223
                                    Executable::Intrinsics Index,
224
8.06k
                                    LLVM::Type Ty) noexcept {
225
8.06k
    const auto Value = static_cast<uint32_t>(Index);
226
8.06k
    auto PtrTy = Ty.getPointerTo();
227
8.06k
    auto PtrPtrTy = PtrTy.getPointerTo();
228
8.06k
    auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable);
229
8.06k
    IT.setMetadata(LLContext, LLVM::Core::InvariantGroup,
230
8.06k
                   LLVM::Metadata(LLContext, {}));
231
8.06k
    auto VPtr =
232
8.06k
        Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0),
233
8.06k
                                   LLContext.getInt64(Value));
234
8.06k
    auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy);
235
8.06k
    return {Ty, Builder.createLoad(PtrTy, Ptr)};
236
8.06k
  }
237
2.31k
  void compileTrap() noexcept {
238
2.31k
    LLVM::Builder Builder(LLContext);
239
2.31k
    Builder.positionAtEnd(
240
2.31k
        LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry"));
241
2.31k
    auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
242
2.31k
    auto CallTrap = Builder.createCall(
243
2.31k
        getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy),
244
2.31k
        {Trap.Fn.getFirstParam()});
245
2.31k
    CallTrap.addCallSiteAttribute(NoReturn);
246
2.31k
    Builder.createUnreachable();
247
2.31k
  }
248
2.31k
  void addVersionGlobal() noexcept {
249
2.31k
    LLModule.get().addGlobal(
250
2.31k
        Int32Ty, true, LLVMExternalLinkage,
251
2.31k
        LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version");
252
2.31k
  }
253
2.31k
  void finalizeIntrinsicsTable() noexcept {
254
2.31k
    if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) {
255
1.55k
      Table.setInitializer(LLVM::Value::getConstNull(Table.getType()));
256
1.55k
      Table.setGlobalConstant(false);
257
1.55k
    } else {
258
766
      LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage,
259
766
                               LLVM::Value::getConstNull(IntrinsicsTablePtrTy),
260
766
                               "intrinsics");
261
766
    }
262
2.31k
  }
263
  std::pair<std::vector<ValType>, std::vector<ValType>>
264
19.4k
  resolveBlockType(const BlockType &BType) const noexcept {
265
19.4k
    using VecT = std::vector<ValType>;
266
19.4k
    using RetT = std::pair<VecT, VecT>;
267
19.4k
    if (BType.isEmpty()) {
268
2.32k
      return RetT{};
269
2.32k
    }
270
17.1k
    if (BType.isValType()) {
271
2.53k
      return RetT{{}, {BType.getValType()}};
272
14.6k
    } else {
273
      // Type index case. t2* = type[index].returns
274
14.6k
      const uint32_t TypeIdx = BType.getTypeIndex();
275
14.6k
      const auto &FType = CompositeTypes[TypeIdx]->getFuncType();
276
14.6k
      return RetT{
277
14.6k
          VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()),
278
14.6k
          VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())};
279
14.6k
    }
280
17.1k
  }
281
};
282
283
bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
284
LLVM::Type toLLVMType(LLVM::Context LLContext,
285
                      const WasmEdge::ValType &ValType) noexcept;
286
std::vector<LLVM::Type>
287
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
288
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
289
LLVM::Type
290
toLLVMRetsType(LLVM::Context LLContext,
291
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
292
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
293
                      const WasmEdge::AST::FunctionType &FuncType) noexcept;
294
LLVM::Value
295
toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType,
296
                   WasmEdge::Span<const WasmEdge::AST::CompositeType *const>
297
                       CompositeTypes) noexcept;
298
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
299
                                      LLVM::Value Struct) noexcept;
300
LLVM::Type toLLVMType(LLVM::Context LLContext,
301
                      const WasmEdge::AddressType AddrType) noexcept;
302
std::vector<LLVM::Type>
303
toLLVMTypeVector(LLVM::Context LLContext,
304
                 WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
305
306
} // namespace WasmEdge::LLVM