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.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.28k
    : LLContext(C), LLModule(M),
21
2.28k
      Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)),
22
2.28k
      NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)),
23
2.28k
      NoInline(LLVM::Attribute::createEnum(C, LLVM::Core::NoInline, 0)),
24
2.28k
      NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)),
25
2.28k
      ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)),
26
2.28k
      StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)),
27
2.28k
      UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable,
28
2.28k
                                          LLVM::Core::UWTableDefault)),
29
      NoStackArgProbe(
30
2.28k
          LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})),
31
2.28k
      VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()),
32
2.28k
      Int16Ty(LLContext.getInt16Ty()), Int32Ty(LLContext.getInt32Ty()),
33
2.28k
      Int64Ty(LLContext.getInt64Ty()), Int128Ty(LLContext.getInt128Ty()),
34
2.28k
      FloatTy(LLContext.getFloatTy()), DoubleTy(LLContext.getDoubleTy()),
35
2.28k
      Int8x16Ty(LLVM::Type::getVectorType(Int8Ty, 16)),
36
2.28k
      Int16x8Ty(LLVM::Type::getVectorType(Int16Ty, 8)),
37
2.28k
      Int32x4Ty(LLVM::Type::getVectorType(Int32Ty, 4)),
38
2.28k
      Floatx4Ty(LLVM::Type::getVectorType(FloatTy, 4)),
39
2.28k
      Int64x2Ty(LLVM::Type::getVectorType(Int64Ty, 2)),
40
2.28k
      Doublex2Ty(LLVM::Type::getVectorType(DoubleTy, 2)),
41
2.28k
      Int128x1Ty(LLVM::Type::getVectorType(Int128Ty, 1)),
42
2.28k
      Int8PtrTy(Int8Ty.getPointerTo()), Int32PtrTy(Int32Ty.getPointerTo()),
43
2.28k
      Int64PtrTy(Int64Ty.getPointerTo()), Int128PtrTy(Int128Ty.getPointerTo()),
44
2.28k
      Int8PtrPtrTy(Int8PtrTy.getPointerTo()),
45
      ModCtxTy(
46
2.28k
          LLVM::Type::getStructType("ModCtx",
47
2.28k
                                    std::initializer_list<LLVM::Type>{
48
                                        // MemoryPtrs
49
2.28k
                                        Int8PtrTy.getPointerTo(),
50
                                        // MemorySizes
51
2.28k
                                        Int64PtrTy.getPointerTo(),
52
                                        // TableRefs
53
2.28k
                                        Int64x2Ty.getPointerTo().getPointerTo(),
54
                                        // TableSizes
55
2.28k
                                        Int64PtrTy.getPointerTo(),
56
                                        // Globals
57
2.28k
                                        Int128PtrTy.getPointerTo(),
58
                                        // ModuleInst
59
2.28k
                                        Int8PtrTy,
60
                                        // Tags
61
2.28k
                                        Int8PtrPtrTy,
62
2.28k
                                    })),
63
2.28k
      ModCtxPtrTy(ModCtxTy.getPointerTo()),
64
2.28k
      ExecCtxTy(LLVM::Type::getStructType(
65
2.28k
          "ExecCtx",
66
2.28k
          std::initializer_list<LLVM::Type>{
67
              // InstrCount
68
2.28k
              Int64PtrTy,
69
              // CostTable
70
2.28k
              LLVM::Type::getArrayType(Int64Ty, UINT16_MAX + 1).getPointerTo(),
71
              // Gas
72
2.28k
              Int64PtrTy,
73
              // GasLimit
74
2.28k
              Int64Ty,
75
              // StopToken
76
2.28k
              Int32PtrTy,
77
              // PendingExnTagAddr
78
2.28k
              Int8PtrPtrTy,
79
              // StackLimit
80
2.28k
              Int8PtrTy,
81
2.28k
          })),
82
2.28k
      ExecCtxPtrTy(ExecCtxTy.getPointerTo()),
83
2.28k
      IntrinsicsTableTy(LLVM::Type::getArrayType(
84
2.28k
          Int8Ty.getPointerTo(),
85
2.28k
          static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))),
86
2.28k
      IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()),
87
2.28k
      IntrinsicsTable(LLModule.get().addGlobal(IntrinsicsTablePtrTy, true,
88
2.28k
                                               LLVMExternalLinkage,
89
2.28k
                                               LLVM::Value(), "intrinsics")) {
90
2.28k
  Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
91
2.28k
  Trap.Fn = LLModule.get().addFunction(Trap.Ty, LLVMPrivateLinkage, "trap");
92
2.28k
  Trap.Fn.setDSOLocal(true);
93
2.28k
  Trap.Fn.addFnAttr(NoStackArgProbe);
94
2.28k
  Trap.Fn.addFnAttr(StrictFP);
95
2.28k
  Trap.Fn.addFnAttr(UWTable);
96
2.28k
  Trap.Fn.addFnAttr(NoReturn);
97
2.28k
  Trap.Fn.addFnAttr(Cold);
98
2.28k
  Trap.Fn.addFnAttr(NoInline);
99
100
2.28k
  if (!IsGenericBinary) {
101
2.28k
    SubtargetFeatures = LLVM::getHostCPUFeatures();
102
2.28k
    auto Features = SubtargetFeatures.string_view();
103
198k
    while (!Features.empty()) {
104
196k
      std::string_view Feature;
105
196k
      if (auto Pos = Features.find(','); Pos != std::string_view::npos) {
106
193k
        Feature = Features.substr(0, Pos);
107
193k
        Features = Features.substr(Pos + 1);
108
193k
      } else {
109
2.28k
        Feature = std::exchange(Features, std::string_view());
110
2.28k
      }
111
196k
      if (Feature[0] != '+') {
112
120k
        continue;
113
120k
      }
114
75.2k
      Feature = Feature.substr(1);
115
116
75.2k
#if defined(__x86_64__)
117
75.2k
      if (!SupportXOP && Feature == "xop"sv) {
118
0
        SupportXOP = true;
119
0
      }
120
75.2k
      if (!SupportSSE4_1 && Feature == "sse4.1"sv) {
121
2.28k
        SupportSSE4_1 = true;
122
2.28k
      }
123
75.2k
      if (!SupportSSSE3 && Feature == "ssse3"sv) {
124
2.28k
        SupportSSSE3 = true;
125
2.28k
      }
126
75.2k
      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
75.2k
    }
135
2.28k
  }
136
137
2.28k
  compileTrap();
138
2.28k
}
139
140
35.4k
bool isVoidReturn(Span<const ValType> ValTypes) noexcept {
141
35.4k
  return ValTypes.empty();
142
35.4k
}
143
144
LLVM::Type toLLVMType(LLVM::Context LLContext,
145
3.72M
                      const ValType &ValType) noexcept {
146
3.72M
  switch (ValType.getCode()) {
147
305k
  case TypeCode::I32:
148
305k
    return LLContext.getInt32Ty();
149
185k
  case TypeCode::I64:
150
185k
    return LLContext.getInt64Ty();
151
551
  case TypeCode::Ref:
152
3.04M
  case TypeCode::RefNull:
153
3.07M
  case TypeCode::V128:
154
3.07M
    return LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2);
155
34.4k
  case TypeCode::F32:
156
34.4k
    return LLContext.getFloatTy();
157
118k
  case TypeCode::F64:
158
118k
    return LLContext.getDoubleTy();
159
0
  default:
160
0
    assumingUnreachable();
161
3.72M
  }
162
3.72M
}
163
164
LLVM::Type toLLVMType(LLVM::Context LLContext,
165
1.40k
                      const AddressType AddrType) noexcept {
166
1.40k
  switch (AddrType) {
167
1.27k
  case AddressType::I32:
168
1.27k
    return LLContext.getInt32Ty();
169
130
  case AddressType::I64:
170
130
    return LLContext.getInt64Ty();
171
0
  default:
172
0
    assumingUnreachable();
173
1.40k
  }
174
1.40k
}
175
176
std::vector<LLVM::Type>
177
toLLVMTypeVector(LLVM::Context LLContext,
178
20.6k
                 Span<const ValType> ValTypes) noexcept {
179
20.6k
  std::vector<LLVM::Type> Result;
180
20.6k
  Result.reserve(ValTypes.size());
181
20.9k
  for (const auto &Type : ValTypes) {
182
20.9k
    Result.push_back(toLLVMType(LLContext, Type));
183
20.9k
  }
184
20.6k
  return Result;
185
20.6k
}
186
187
std::vector<LLVM::Type> toLLVMArgsType(LLVM::Context LLContext,
188
                                       LLVM::Type ModCtxPtrTy,
189
                                       LLVM::Type ExecCtxPtrTy,
190
16.5k
                                       Span<const ValType> ValTypes) noexcept {
191
16.5k
  auto Result = toLLVMTypeVector(LLContext, ValTypes);
192
16.5k
  Result.insert(Result.begin(), ExecCtxPtrTy);
193
16.5k
  Result.insert(Result.begin(), ModCtxPtrTy);
194
16.5k
  return Result;
195
16.5k
}
196
197
LLVM::Type toLLVMRetsType(LLVM::Context LLContext,
198
16.5k
                          Span<const ValType> ValTypes) noexcept {
199
16.5k
  if (isVoidReturn(ValTypes)) {
200
4.45k
    return LLContext.getVoidTy();
201
4.45k
  }
202
12.0k
  if (ValTypes.size() == 1) {
203
11.3k
    return toLLVMType(LLContext, ValTypes.front());
204
11.3k
  }
205
718
  std::vector<LLVM::Type> Result;
206
718
  Result.reserve(ValTypes.size());
207
2.27k
  for (const auto &Type : ValTypes) {
208
2.27k
    Result.push_back(toLLVMType(LLContext, Type));
209
2.27k
  }
210
718
  return LLVM::Type::getStructType(Result);
211
12.0k
}
212
213
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
214
                      LLVM::Type ExecCtxPtrTy,
215
16.5k
                      const AST::FunctionType &FuncType) noexcept {
216
16.5k
  auto ArgsTy = toLLVMArgsType(LLContext, ModCtxPtrTy, ExecCtxPtrTy,
217
16.5k
                               FuncType.getParamTypes());
218
16.5k
  auto RetTy = toLLVMRetsType(LLContext, FuncType.getReturnTypes());
219
16.5k
  return LLVM::Type::getFunctionType(RetTy, ArgsTy);
220
16.5k
}
221
222
LLVM::Value toLLVMConstantZero(
223
    LLVM::Context LLContext, const ValType &ValType,
224
3.69M
    Span<const AST::CompositeType *const> CompositeTypes) noexcept {
225
3.69M
  switch (ValType.getCode()) {
226
286k
  case TypeCode::I32:
227
286k
    return LLVM::Value::getConstNull(LLContext.getInt32Ty());
228
181k
  case TypeCode::I64:
229
181k
    return LLVM::Value::getConstNull(LLContext.getInt64Ty());
230
551
  case TypeCode::Ref:
231
3.04M
  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.04M
    TypeCode HTCode = ValType.getHeapTypeCode();
235
3.04M
    if (!ValType.isAbsHeapType()) {
236
3.02M
      assuming(ValType.getTypeIndex() < CompositeTypes.size());
237
3.02M
      const auto *CompType = CompositeTypes[ValType.getTypeIndex()];
238
3.02M
      assuming(CompType != nullptr);
239
3.02M
      HTCode = CompType->expand();
240
3.02M
    }
241
3.04M
    const WasmEdge::ValType VType(TypeCode::RefNull,
242
3.04M
                                  AST::TypeMatcher::getBottomHeapType(HTCode));
243
3.04M
    const auto Raw = VType.getRawData();
244
3.04M
    std::array<uint64_t, 2> Data{};
245
3.04M
    std::memcpy(Data.data(), Raw.data(), Raw.size());
246
3.04M
    return LLVM::Value::getConstVector64(LLContext, Data);
247
3.04M
  }
248
31.5k
  case TypeCode::V128:
249
31.5k
    return LLVM::Value::getConstNull(
250
31.5k
        LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2));
251
31.7k
  case TypeCode::F32:
252
31.7k
    return LLVM::Value::getConstNull(LLContext.getFloatTy());
253
115k
  case TypeCode::F64:
254
115k
    return LLVM::Value::getConstNull(LLContext.getDoubleTy());
255
0
  default:
256
0
    assumingUnreachable();
257
3.69M
  }
258
3.69M
}
259
260
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
261
445
                                      LLVM::Value Struct) noexcept {
262
445
  const auto N = Struct.getType().getStructNumElements();
263
445
  std::vector<LLVM::Value> Ret;
264
445
  Ret.reserve(N);
265
1.82k
  for (unsigned I = 0; I < N; ++I) {
266
1.37k
    Ret.push_back(Builder.createExtractValue(Struct, I));
267
1.37k
  }
268
445
  return Ret;
269
445
}
270
271
} // namespace WasmEdge::LLVM