Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/llvm/compiler/context.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "compiler/context.h"
5
6
#include <array>
7
#include <cstdint>
8
#include <cstring>
9
#include <initializer_list>
10
#include <string_view>
11
#include <utility>
12
#include <vector>
13
14
using namespace std::literals;
15
16
namespace WasmEdge::LLVM {
17
18
Compiler::CompileContext::CompileContext(LLVM::Context C, LLVM::Module &M,
19
                                         bool IsGenericBinary) noexcept
20
2.35k
    : LLContext(C), LLModule(M),
21
2.35k
      Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)),
22
2.35k
      NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)),
23
2.35k
      NoInline(LLVM::Attribute::createEnum(C, LLVM::Core::NoInline, 0)),
24
2.35k
      NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)),
25
2.35k
      ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)),
26
2.35k
      StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)),
27
2.35k
      UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable,
28
2.35k
                                          LLVM::Core::UWTableDefault)),
29
      NoStackArgProbe(
30
2.35k
          LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})),
31
2.35k
      VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()),
32
2.35k
      Int16Ty(LLContext.getInt16Ty()), Int32Ty(LLContext.getInt32Ty()),
33
2.35k
      Int64Ty(LLContext.getInt64Ty()), Int128Ty(LLContext.getInt128Ty()),
34
2.35k
      FloatTy(LLContext.getFloatTy()), DoubleTy(LLContext.getDoubleTy()),
35
2.35k
      Int8x16Ty(LLVM::Type::getVectorType(Int8Ty, 16)),
36
2.35k
      Int16x8Ty(LLVM::Type::getVectorType(Int16Ty, 8)),
37
2.35k
      Int32x4Ty(LLVM::Type::getVectorType(Int32Ty, 4)),
38
2.35k
      Floatx4Ty(LLVM::Type::getVectorType(FloatTy, 4)),
39
2.35k
      Int64x2Ty(LLVM::Type::getVectorType(Int64Ty, 2)),
40
2.35k
      Doublex2Ty(LLVM::Type::getVectorType(DoubleTy, 2)),
41
2.35k
      Int128x1Ty(LLVM::Type::getVectorType(Int128Ty, 1)),
42
2.35k
      Int8PtrTy(Int8Ty.getPointerTo()), Int32PtrTy(Int32Ty.getPointerTo()),
43
2.35k
      Int64PtrTy(Int64Ty.getPointerTo()), Int128PtrTy(Int128Ty.getPointerTo()),
44
2.35k
      Int8PtrPtrTy(Int8PtrTy.getPointerTo()),
45
      ModCtxTy(
46
2.35k
          LLVM::Type::getStructType("ModCtx",
47
2.35k
                                    std::initializer_list<LLVM::Type>{
48
                                        // MemoryPtrs
49
2.35k
                                        Int8PtrTy.getPointerTo(),
50
                                        // MemorySizes
51
2.35k
                                        Int64PtrTy.getPointerTo(),
52
                                        // TableRefs
53
2.35k
                                        Int64x2Ty.getPointerTo().getPointerTo(),
54
                                        // TableSizes
55
2.35k
                                        Int64PtrTy.getPointerTo(),
56
                                        // Globals
57
2.35k
                                        Int128PtrTy.getPointerTo(),
58
                                        // ModuleInst
59
2.35k
                                        Int8PtrTy,
60
                                        // Tags
61
2.35k
                                        Int8PtrPtrTy,
62
2.35k
                                    })),
63
2.35k
      ModCtxPtrTy(ModCtxTy.getPointerTo()),
64
2.35k
      ExecCtxTy(LLVM::Type::getStructType(
65
2.35k
          "ExecCtx",
66
2.35k
          std::initializer_list<LLVM::Type>{
67
              // InstrCount
68
2.35k
              Int64PtrTy,
69
              // CostTable
70
2.35k
              LLVM::Type::getArrayType(Int64Ty, UINT16_MAX + 1).getPointerTo(),
71
              // Gas
72
2.35k
              Int64PtrTy,
73
              // GasLimit
74
2.35k
              Int64Ty,
75
              // StopToken
76
2.35k
              Int32PtrTy,
77
              // PendingExnTagAddr
78
2.35k
              Int8PtrPtrTy,
79
              // StackLimit
80
2.35k
              Int8PtrTy,
81
2.35k
          })),
82
2.35k
      ExecCtxPtrTy(ExecCtxTy.getPointerTo()),
83
2.35k
      IntrinsicsTableTy(LLVM::Type::getArrayType(
84
2.35k
          Int8Ty.getPointerTo(),
85
2.35k
          static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))),
86
2.35k
      IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()),
87
2.35k
      IntrinsicsTable(LLModule.get().addGlobal(IntrinsicsTablePtrTy, true,
88
2.35k
                                               LLVMExternalLinkage,
89
2.35k
                                               LLVM::Value(), "intrinsics")) {
90
2.35k
  Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
91
2.35k
  Trap.Fn = LLModule.get().addFunction(Trap.Ty, LLVMPrivateLinkage, "trap");
92
2.35k
  Trap.Fn.setDSOLocal(true);
93
2.35k
  Trap.Fn.addFnAttr(NoStackArgProbe);
94
2.35k
  Trap.Fn.addFnAttr(StrictFP);
95
2.35k
  Trap.Fn.addFnAttr(UWTable);
96
2.35k
  Trap.Fn.addFnAttr(NoReturn);
97
2.35k
  Trap.Fn.addFnAttr(Cold);
98
2.35k
  Trap.Fn.addFnAttr(NoInline);
99
100
2.35k
  if (!IsGenericBinary) {
101
2.35k
    SubtargetFeatures = LLVM::getHostCPUFeatures();
102
2.35k
    auto Features = SubtargetFeatures.string_view();
103
204k
    while (!Features.empty()) {
104
202k
      std::string_view Feature;
105
202k
      if (auto Pos = Features.find(','); Pos != std::string_view::npos) {
106
200k
        Feature = Features.substr(0, Pos);
107
200k
        Features = Features.substr(Pos + 1);
108
200k
      } else {
109
2.35k
        Feature = std::exchange(Features, std::string_view());
110
2.35k
      }
111
202k
      if (Feature[0] != '+') {
112
124k
        continue;
113
124k
      }
114
77.6k
      Feature = Feature.substr(1);
115
116
77.6k
#if defined(__x86_64__)
117
77.6k
      if (!SupportXOP && Feature == "xop"sv) {
118
0
        SupportXOP = true;
119
0
      }
120
77.6k
      if (!SupportSSE4_1 && Feature == "sse4.1"sv) {
121
2.35k
        SupportSSE4_1 = true;
122
2.35k
      }
123
77.6k
      if (!SupportSSSE3 && Feature == "ssse3"sv) {
124
2.35k
        SupportSSSE3 = true;
125
2.35k
      }
126
77.6k
      if (!SupportSSE2 && Feature == "sse2"sv) {
127
0
        SupportSSE2 = true;
128
0
      }
129
#elif defined(__aarch64__)
130
      if (!SupportNEON && Feature == "neon"sv) {
131
        SupportNEON = true;
132
      }
133
#endif
134
77.6k
    }
135
2.35k
  }
136
137
2.35k
  compileTrap();
138
2.35k
}
139
140
37.0k
bool isVoidReturn(Span<const ValType> ValTypes) noexcept {
141
37.0k
  return ValTypes.empty();
142
37.0k
}
143
144
LLVM::Type toLLVMType(LLVM::Context LLContext,
145
4.37M
                      const ValType &ValType) noexcept {
146
4.37M
  switch (ValType.getCode()) {
147
306k
  case TypeCode::I32:
148
306k
    return LLContext.getInt32Ty();
149
189k
  case TypeCode::I64:
150
189k
    return LLContext.getInt64Ty();
151
682
  case TypeCode::Ref:
152
3.58M
  case TypeCode::RefNull:
153
3.62M
  case TypeCode::V128:
154
3.62M
    return LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2);
155
34.9k
  case TypeCode::F32:
156
34.9k
    return LLContext.getFloatTy();
157
217k
  case TypeCode::F64:
158
217k
    return LLContext.getDoubleTy();
159
0
  default:
160
0
    assumingUnreachable();
161
4.37M
  }
162
4.37M
}
163
164
LLVM::Type toLLVMType(LLVM::Context LLContext,
165
1.77k
                      const AddressType AddrType) noexcept {
166
1.77k
  switch (AddrType) {
167
1.56k
  case AddressType::I32:
168
1.56k
    return LLContext.getInt32Ty();
169
208
  case AddressType::I64:
170
208
    return LLContext.getInt64Ty();
171
0
  default:
172
0
    assumingUnreachable();
173
1.77k
  }
174
1.77k
}
175
176
std::vector<LLVM::Type>
177
toLLVMTypeVector(LLVM::Context LLContext,
178
21.6k
                 Span<const ValType> ValTypes) noexcept {
179
21.6k
  std::vector<LLVM::Type> Result;
180
21.6k
  Result.reserve(ValTypes.size());
181
22.0k
  for (const auto &Type : ValTypes) {
182
22.0k
    Result.push_back(toLLVMType(LLContext, Type));
183
22.0k
  }
184
21.6k
  return Result;
185
21.6k
}
186
187
std::vector<LLVM::Type> toLLVMArgsType(LLVM::Context LLContext,
188
                                       LLVM::Type ModCtxPtrTy,
189
                                       LLVM::Type ExecCtxPtrTy,
190
17.3k
                                       Span<const ValType> ValTypes) noexcept {
191
17.3k
  auto Result = toLLVMTypeVector(LLContext, ValTypes);
192
17.3k
  Result.insert(Result.begin(), ExecCtxPtrTy);
193
17.3k
  Result.insert(Result.begin(), ModCtxPtrTy);
194
17.3k
  return Result;
195
17.3k
}
196
197
LLVM::Type toLLVMRetsType(LLVM::Context LLContext,
198
17.3k
                          Span<const ValType> ValTypes) noexcept {
199
17.3k
  if (isVoidReturn(ValTypes)) {
200
4.77k
    return LLContext.getVoidTy();
201
4.77k
  }
202
12.5k
  if (ValTypes.size() == 1) {
203
11.7k
    return toLLVMType(LLContext, ValTypes.front());
204
11.7k
  }
205
839
  std::vector<LLVM::Type> Result;
206
839
  Result.reserve(ValTypes.size());
207
2.53k
  for (const auto &Type : ValTypes) {
208
2.53k
    Result.push_back(toLLVMType(LLContext, Type));
209
2.53k
  }
210
839
  return LLVM::Type::getStructType(Result);
211
12.5k
}
212
213
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
214
                      LLVM::Type ExecCtxPtrTy,
215
17.3k
                      const AST::FunctionType &FuncType) noexcept {
216
17.3k
  auto ArgsTy = toLLVMArgsType(LLContext, ModCtxPtrTy, ExecCtxPtrTy,
217
17.3k
                               FuncType.getParamTypes());
218
17.3k
  auto RetTy = toLLVMRetsType(LLContext, FuncType.getReturnTypes());
219
17.3k
  return LLVM::Type::getFunctionType(RetTy, ArgsTy);
220
17.3k
}
221
222
LLVM::Value toLLVMConstantZero(
223
    LLVM::Context LLContext, const ValType &ValType,
224
4.34M
    Span<const AST::CompositeType *const> CompositeTypes) noexcept {
225
4.34M
  switch (ValType.getCode()) {
226
286k
  case TypeCode::I32:
227
286k
    return LLVM::Value::getConstNull(LLContext.getInt32Ty());
228
185k
  case TypeCode::I64:
229
185k
    return LLVM::Value::getConstNull(LLContext.getInt64Ty());
230
682
  case TypeCode::Ref:
231
3.59M
  case TypeCode::RefNull: {
232
    // Type the null refs with the bottom heap type of their hierarchy so that
233
    // ref.test/ref.cast match them against the concrete types.
234
3.59M
    TypeCode HTCode = ValType.getHeapTypeCode();
235
3.59M
    if (!ValType.isAbsHeapType()) {
236
3.53M
      assuming(ValType.getTypeIndex() < CompositeTypes.size());
237
3.53M
      const auto *CompType = CompositeTypes[ValType.getTypeIndex()];
238
3.53M
      assuming(CompType != nullptr);
239
3.53M
      HTCode = CompType->expand();
240
3.53M
    }
241
3.59M
    const WasmEdge::ValType VType(TypeCode::RefNull,
242
3.59M
                                  AST::TypeMatcher::getBottomHeapType(HTCode));
243
3.59M
    const auto Raw = VType.getRawData();
244
3.59M
    std::array<uint64_t, 2> Data{};
245
3.59M
    std::memcpy(Data.data(), Raw.data(), Raw.size());
246
3.59M
    return LLVM::Value::getConstVector64(LLContext, Data);
247
3.59M
  }
248
31.5k
  case TypeCode::V128:
249
31.5k
    return LLVM::Value::getConstNull(
250
31.5k
        LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2));
251
31.9k
  case TypeCode::F32:
252
31.9k
    return LLVM::Value::getConstNull(LLContext.getFloatTy());
253
214k
  case TypeCode::F64:
254
214k
    return LLVM::Value::getConstNull(LLContext.getDoubleTy());
255
0
  default:
256
0
    assumingUnreachable();
257
4.34M
  }
258
4.34M
}
259
260
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
261
514
                                      LLVM::Value Struct) noexcept {
262
514
  const auto N = Struct.getType().getStructNumElements();
263
514
  std::vector<LLVM::Value> Ret;
264
514
  Ret.reserve(N);
265
2.03k
  for (unsigned I = 0; I < N; ++I) {
266
1.52k
    Ret.push_back(Builder.createExtractValue(Struct, I));
267
1.52k
  }
268
514
  return Ret;
269
514
}
270
271
} // namespace WasmEdge::LLVM