Coverage Report

Created: 2026-07-16 07:09

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
  LLVM::Value IntrinsicsTable;
113
  LLVM::FunctionCallee Trap;
114
  CompileContext(LLVM::Context C, LLVM::Module &M,
115
                 bool IsGenericBinary) noexcept;
116
  LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ExecCtx,
117
21.5k
                        uint32_t Index) noexcept {
118
21.5k
    auto Array = Builder.createExtractValue(ExecCtx, 0);
119
#if WASMEDGE_ALLOCATOR_IS_STABLE
120
    auto VPtr = Builder.createLoad(
121
        Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
122
                                              LLContext.getInt64(Index)));
123
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
124
                     LLVM::Metadata(LLContext, {}));
125
#else
126
21.5k
    auto VPtrPtr = Builder.createLoad(
127
21.5k
        Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array,
128
21.5k
                                                 LLContext.getInt64(Index)));
129
21.5k
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
130
21.5k
                        LLVM::Metadata(LLContext, {}));
131
21.5k
    auto VPtr = Builder.createLoad(
132
21.5k
        Int8PtrTy,
133
21.5k
        Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0)));
134
21.5k
#endif
135
21.5k
    return Builder.createBitCast(VPtr, Int8PtrTy);
136
21.5k
  }
137
  LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ExecCtx,
138
698
                            uint32_t Index) noexcept {
139
698
    auto Array = Builder.createExtractValue(ExecCtx, 1);
140
698
    auto VPtr = Builder.createLoad(
141
698
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
142
698
                                               LLContext.getInt64(Index)));
143
698
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
144
698
                     LLVM::Metadata(LLContext, {}));
145
698
    return Builder.createLoad(Int64Ty, VPtr);
146
698
  }
147
  LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ExecCtx,
148
873
                       uint32_t Index) noexcept {
149
873
    auto RefPtrTy = Int64x2Ty.getPointerTo();
150
873
    auto Array = Builder.createExtractValue(ExecCtx, 2);
151
873
    auto VPtrPtr = Builder.createLoad(
152
873
        RefPtrTy.getPointerTo(),
153
873
        Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array,
154
873
                                   LLContext.getInt64(Index)));
155
873
    VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
156
873
                        LLVM::Metadata(LLContext, {}));
157
873
    return Builder.createLoad(
158
873
        RefPtrTy,
159
873
        Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0)));
160
873
  }
161
  LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ExecCtx,
162
889
                           uint32_t Index) noexcept {
163
889
    auto Array = Builder.createExtractValue(ExecCtx, 3);
164
889
    auto VPtr = Builder.createLoad(
165
889
        Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array,
166
889
                                               LLContext.getInt64(Index)));
167
889
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
168
889
                     LLVM::Metadata(LLContext, {}));
169
889
    return Builder.createLoad(Int64Ty, VPtr);
170
889
  }
171
  LLVM::Value getModuleInst(LLVM::Builder &Builder,
172
795
                            LLVM::Value ExecCtx) noexcept {
173
795
    return Builder.createExtractValue(ExecCtx, 10);
174
795
  }
175
  std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder,
176
                                               LLVM::Value ExecCtx,
177
452
                                               uint32_t Index) noexcept {
178
452
    auto Ty = Globals[Index];
179
452
    auto Array = Builder.createExtractValue(ExecCtx, 4);
180
452
    auto VPtr = Builder.createLoad(
181
452
        Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array,
182
452
                                                LLContext.getInt64(Index)));
183
452
    VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup,
184
452
                     LLVM::Metadata(LLContext, {}));
185
452
    auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo());
186
452
    return {Ty, Ptr};
187
452
  }
188
  LLVM::Value getInstrCount(LLVM::Builder &Builder,
189
0
                            LLVM::Value ExecCtx) noexcept {
190
0
    return Builder.createExtractValue(ExecCtx, 5);
191
0
  }
192
  LLVM::Value getCostTable(LLVM::Builder &Builder,
193
0
                           LLVM::Value ExecCtx) noexcept {
194
0
    return Builder.createExtractValue(ExecCtx, 6);
195
0
  }
196
0
  LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept {
197
0
    return Builder.createExtractValue(ExecCtx, 7);
198
0
  }
199
  LLVM::Value getGasLimit(LLVM::Builder &Builder,
200
0
                          LLVM::Value ExecCtx) noexcept {
201
0
    return Builder.createExtractValue(ExecCtx, 8);
202
0
  }
203
  LLVM::Value getStopToken(LLVM::Builder &Builder,
204
0
                           LLVM::Value ExecCtx) noexcept {
205
0
    return Builder.createExtractValue(ExecCtx, 9);
206
0
  }
207
  LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder,
208
                                    Executable::Intrinsics Index,
209
7.43k
                                    LLVM::Type Ty) noexcept {
210
7.43k
    const auto Value = static_cast<uint32_t>(Index);
211
7.43k
    auto PtrTy = Ty.getPointerTo();
212
7.43k
    auto PtrPtrTy = PtrTy.getPointerTo();
213
7.43k
    auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable);
214
7.43k
    IT.setMetadata(LLContext, LLVM::Core::InvariantGroup,
215
7.43k
                   LLVM::Metadata(LLContext, {}));
216
7.43k
    auto VPtr =
217
7.43k
        Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0),
218
7.43k
                                   LLContext.getInt64(Value));
219
7.43k
    auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy);
220
7.43k
    return {Ty, Builder.createLoad(PtrTy, Ptr)};
221
7.43k
  }
222
2.23k
  void compileTrap() noexcept {
223
2.23k
    LLVM::Builder Builder(LLContext);
224
2.23k
    Builder.positionAtEnd(
225
2.23k
        LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry"));
226
2.23k
    auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
227
2.23k
    auto CallTrap = Builder.createCall(
228
2.23k
        getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy),
229
2.23k
        {Trap.Fn.getFirstParam()});
230
2.23k
    CallTrap.addCallSiteAttribute(NoReturn);
231
2.23k
    Builder.createUnreachable();
232
2.23k
  }
233
2.23k
  void addVersionGlobal() noexcept {
234
2.23k
    LLModule.get().addGlobal(
235
2.23k
        Int32Ty, true, LLVMExternalLinkage,
236
2.23k
        LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version");
237
2.23k
  }
238
2.22k
  void finalizeIntrinsicsTable() noexcept {
239
2.22k
    if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) {
240
1.27k
      Table.setInitializer(LLVM::Value::getConstNull(Table.getType()));
241
1.27k
      Table.setGlobalConstant(false);
242
1.27k
    } else {
243
949
      LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage,
244
949
                               LLVM::Value::getConstNull(IntrinsicsTablePtrTy),
245
949
                               "intrinsics");
246
949
    }
247
2.22k
  }
248
  std::pair<std::vector<ValType>, std::vector<ValType>>
249
18.5k
  resolveBlockType(const BlockType &BType) const noexcept {
250
18.5k
    using VecT = std::vector<ValType>;
251
18.5k
    using RetT = std::pair<VecT, VecT>;
252
18.5k
    if (BType.isEmpty()) {
253
2.25k
      return RetT{};
254
2.25k
    }
255
16.3k
    if (BType.isValType()) {
256
2.46k
      return RetT{{}, {BType.getValType()}};
257
13.8k
    } else {
258
      // Type index case. t2* = type[index].returns
259
13.8k
      const uint32_t TypeIdx = BType.getTypeIndex();
260
13.8k
      const auto &FType = CompositeTypes[TypeIdx]->getFuncType();
261
13.8k
      return RetT{
262
13.8k
          VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()),
263
13.8k
          VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())};
264
13.8k
    }
265
16.3k
  }
266
};
267
268
bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
269
LLVM::Type toLLVMType(LLVM::Context LLContext,
270
                      const WasmEdge::ValType &ValType) noexcept;
271
std::vector<LLVM::Type>
272
toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
273
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
274
LLVM::Type
275
toLLVMRetsType(LLVM::Context LLContext,
276
               WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
277
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
278
                      const WasmEdge::AST::FunctionType &FuncType) noexcept;
279
LLVM::Value
280
toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType,
281
                   WasmEdge::Span<const WasmEdge::AST::CompositeType *const>
282
                       CompositeTypes) noexcept;
283
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
284
                                      LLVM::Value Struct) noexcept;
285
LLVM::Type toLLVMType(LLVM::Context LLContext,
286
                      const WasmEdge::AddressType AddrType) noexcept;
287
std::vector<LLVM::Type>
288
toLLVMTypeVector(LLVM::Context LLContext,
289
                 WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept;
290
291
} // namespace WasmEdge::LLVM