Coverage Report

Created: 2026-09-28 06:22

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 <algorithm>
7
#include <array>
8
#include <cstdint>
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.31k
    : LLContext(C), LLModule(M),
21
2.31k
      Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)),
22
2.31k
      NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)),
23
2.31k
      NoInline(LLVM::Attribute::createEnum(C, LLVM::Core::NoInline, 0)),
24
2.31k
      NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)),
25
2.31k
      ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)),
26
2.31k
      StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)),
27
2.31k
      UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable,
28
2.31k
                                          LLVM::Core::UWTableDefault)),
29
      NoStackArgProbe(
30
2.31k
          LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})),
31
2.31k
      VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()),
32
2.31k
      Int16Ty(LLContext.getInt16Ty()), Int32Ty(LLContext.getInt32Ty()),
33
2.31k
      Int64Ty(LLContext.getInt64Ty()), Int128Ty(LLContext.getInt128Ty()),
34
2.31k
      FloatTy(LLContext.getFloatTy()), DoubleTy(LLContext.getDoubleTy()),
35
2.31k
      Int8x16Ty(LLVM::Type::getVectorType(Int8Ty, 16)),
36
2.31k
      Int16x8Ty(LLVM::Type::getVectorType(Int16Ty, 8)),
37
2.31k
      Int32x4Ty(LLVM::Type::getVectorType(Int32Ty, 4)),
38
2.31k
      Floatx4Ty(LLVM::Type::getVectorType(FloatTy, 4)),
39
2.31k
      Int64x2Ty(LLVM::Type::getVectorType(Int64Ty, 2)),
40
2.31k
      Doublex2Ty(LLVM::Type::getVectorType(DoubleTy, 2)),
41
2.31k
      Int128x1Ty(LLVM::Type::getVectorType(Int128Ty, 1)),
42
2.31k
      Int8PtrTy(Int8Ty.getPointerTo()), Int32PtrTy(Int32Ty.getPointerTo()),
43
2.31k
      Int64PtrTy(Int64Ty.getPointerTo()), Int128PtrTy(Int128Ty.getPointerTo()),
44
2.31k
      Int8PtrPtrTy(Int8PtrTy.getPointerTo()),
45
      ModCtxTy(
46
2.31k
          LLVM::Type::getStructType("ModCtx",
47
2.31k
                                    std::initializer_list<LLVM::Type>{
48
                                        // MemoryPtrs
49
2.31k
                                        Int8PtrTy.getPointerTo(),
50
                                        // MemorySizes
51
2.31k
                                        Int64PtrTy.getPointerTo(),
52
                                        // TableRefs
53
2.31k
                                        Int64x2Ty.getPointerTo().getPointerTo(),
54
                                        // TableSizes
55
2.31k
                                        Int64PtrTy.getPointerTo(),
56
                                        // Globals
57
2.31k
                                        Int128PtrTy.getPointerTo(),
58
                                        // ModuleInst
59
2.31k
                                        Int8PtrTy,
60
                                        // Tags
61
2.31k
                                        Int8PtrPtrTy,
62
2.31k
                                    })),
63
2.31k
      ModCtxPtrTy(ModCtxTy.getPointerTo()),
64
2.31k
      ExecCtxTy(LLVM::Type::getStructType(
65
2.31k
          "ExecCtx",
66
2.31k
          std::initializer_list<LLVM::Type>{
67
              // InstrCount
68
2.31k
              Int64PtrTy,
69
              // CostTable
70
2.31k
              LLVM::Type::getArrayType(Int64Ty, UINT16_MAX + 1).getPointerTo(),
71
              // Gas
72
2.31k
              Int64PtrTy,
73
              // GasLimit
74
2.31k
              Int64Ty,
75
              // StopToken
76
2.31k
              Int32PtrTy,
77
              // PendingExnTagAddr
78
2.31k
              Int8PtrPtrTy,
79
2.31k
          })),
80
2.31k
      ExecCtxPtrTy(ExecCtxTy.getPointerTo()),
81
2.31k
      IntrinsicsTableTy(LLVM::Type::getArrayType(
82
2.31k
          Int8Ty.getPointerTo(),
83
2.31k
          static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))),
84
2.31k
      IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()),
85
2.31k
      IntrinsicsTable(LLModule.get().addGlobal(IntrinsicsTablePtrTy, true,
86
2.31k
                                               LLVMExternalLinkage,
87
2.31k
                                               LLVM::Value(), "intrinsics")) {
88
2.31k
  Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
89
2.31k
  Trap.Fn = LLModule.get().addFunction(Trap.Ty, LLVMPrivateLinkage, "trap");
90
2.31k
  Trap.Fn.setDSOLocal(true);
91
2.31k
  Trap.Fn.addFnAttr(NoStackArgProbe);
92
2.31k
  Trap.Fn.addFnAttr(StrictFP);
93
2.31k
  Trap.Fn.addFnAttr(UWTable);
94
2.31k
  Trap.Fn.addFnAttr(NoReturn);
95
2.31k
  Trap.Fn.addFnAttr(Cold);
96
2.31k
  Trap.Fn.addFnAttr(NoInline);
97
98
2.31k
  if (!IsGenericBinary) {
99
2.31k
    SubtargetFeatures = LLVM::getHostCPUFeatures();
100
2.31k
    auto Features = SubtargetFeatures.string_view();
101
201k
    while (!Features.empty()) {
102
199k
      std::string_view Feature;
103
199k
      if (auto Pos = Features.find(','); Pos != std::string_view::npos) {
104
196k
        Feature = Features.substr(0, Pos);
105
196k
        Features = Features.substr(Pos + 1);
106
196k
      } else {
107
2.31k
        Feature = std::exchange(Features, std::string_view());
108
2.31k
      }
109
199k
      if (Feature[0] != '+') {
110
111k
        continue;
111
111k
      }
112
88.0k
      Feature = Feature.substr(1);
113
114
88.0k
#if defined(__x86_64__)
115
88.0k
      if (!SupportXOP && Feature == "xop"sv) {
116
0
        SupportXOP = true;
117
0
      }
118
88.0k
      if (!SupportSSE4_1 && Feature == "sse4.1"sv) {
119
2.31k
        SupportSSE4_1 = true;
120
2.31k
      }
121
88.0k
      if (!SupportSSSE3 && Feature == "ssse3"sv) {
122
2.31k
        SupportSSSE3 = true;
123
2.31k
      }
124
88.0k
      if (!SupportSSE2 && Feature == "sse2"sv) {
125
0
        SupportSSE2 = true;
126
0
      }
127
#elif defined(__aarch64__)
128
      if (!SupportNEON && Feature == "neon"sv) {
129
        SupportNEON = true;
130
      }
131
#endif
132
88.0k
    }
133
2.31k
  }
134
135
2.31k
  compileTrap();
136
2.31k
}
137
138
37.0k
bool isVoidReturn(Span<const ValType> ValTypes) noexcept {
139
37.0k
  return ValTypes.empty();
140
37.0k
}
141
142
LLVM::Type toLLVMType(LLVM::Context LLContext,
143
1.73M
                      const ValType &ValType) noexcept {
144
1.73M
  switch (ValType.getCode()) {
145
53.2k
  case TypeCode::I32:
146
53.2k
    return LLContext.getInt32Ty();
147
193k
  case TypeCode::I64:
148
193k
    return LLContext.getInt64Ty();
149
680
  case TypeCode::Ref:
150
1.29M
  case TypeCode::RefNull:
151
1.33M
  case TypeCode::V128:
152
1.33M
    return LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2);
153
35.7k
  case TypeCode::F32:
154
35.7k
    return LLContext.getFloatTy();
155
119k
  case TypeCode::F64:
156
119k
    return LLContext.getDoubleTy();
157
0
  default:
158
0
    assumingUnreachable();
159
1.73M
  }
160
1.73M
}
161
162
LLVM::Type toLLVMType(LLVM::Context LLContext,
163
1.44k
                      const AddressType AddrType) noexcept {
164
1.44k
  switch (AddrType) {
165
1.29k
  case AddressType::I32:
166
1.29k
    return LLContext.getInt32Ty();
167
150
  case AddressType::I64:
168
150
    return LLContext.getInt64Ty();
169
0
  default:
170
0
    assumingUnreachable();
171
1.44k
  }
172
1.44k
}
173
174
std::vector<LLVM::Type>
175
toLLVMTypeVector(LLVM::Context LLContext,
176
21.6k
                 Span<const ValType> ValTypes) noexcept {
177
21.6k
  std::vector<LLVM::Type> Result;
178
21.6k
  Result.reserve(ValTypes.size());
179
22.0k
  for (const auto &Type : ValTypes) {
180
22.0k
    Result.push_back(toLLVMType(LLContext, Type));
181
22.0k
  }
182
21.6k
  return Result;
183
21.6k
}
184
185
std::vector<LLVM::Type> toLLVMArgsType(LLVM::Context LLContext,
186
                                       LLVM::Type ModCtxPtrTy,
187
                                       LLVM::Type ExecCtxPtrTy,
188
17.4k
                                       Span<const ValType> ValTypes) noexcept {
189
17.4k
  auto Result = toLLVMTypeVector(LLContext, ValTypes);
190
17.4k
  Result.insert(Result.begin(), ExecCtxPtrTy);
191
17.4k
  Result.insert(Result.begin(), ModCtxPtrTy);
192
17.4k
  return Result;
193
17.4k
}
194
195
LLVM::Type toLLVMRetsType(LLVM::Context LLContext,
196
17.4k
                          Span<const ValType> ValTypes) noexcept {
197
17.4k
  if (isVoidReturn(ValTypes)) {
198
4.67k
    return LLContext.getVoidTy();
199
4.67k
  }
200
12.8k
  if (ValTypes.size() == 1) {
201
11.9k
    return toLLVMType(LLContext, ValTypes.front());
202
11.9k
  }
203
852
  std::vector<LLVM::Type> Result;
204
852
  Result.reserve(ValTypes.size());
205
2.72k
  for (const auto &Type : ValTypes) {
206
2.72k
    Result.push_back(toLLVMType(LLContext, Type));
207
2.72k
  }
208
852
  return LLVM::Type::getStructType(Result);
209
12.8k
}
210
211
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ModCtxPtrTy,
212
                      LLVM::Type ExecCtxPtrTy,
213
17.4k
                      const AST::FunctionType &FuncType) noexcept {
214
17.4k
  auto ArgsTy = toLLVMArgsType(LLContext, ModCtxPtrTy, ExecCtxPtrTy,
215
17.4k
                               FuncType.getParamTypes());
216
17.4k
  auto RetTy = toLLVMRetsType(LLContext, FuncType.getReturnTypes());
217
17.4k
  return LLVM::Type::getFunctionType(RetTy, ArgsTy);
218
17.4k
}
219
220
LLVM::Value toLLVMConstantZero(
221
    LLVM::Context LLContext, const ValType &ValType,
222
1.70M
    Span<const AST::CompositeType *const> CompositeTypes) noexcept {
223
1.70M
  switch (ValType.getCode()) {
224
33.1k
  case TypeCode::I32:
225
33.1k
    return LLVM::Value::getConstNull(LLContext.getInt32Ty());
226
189k
  case TypeCode::I64:
227
189k
    return LLVM::Value::getConstNull(LLContext.getInt64Ty());
228
680
  case TypeCode::Ref:
229
1.30M
  case TypeCode::RefNull: {
230
    // Type the null refs with the bottom heap type of their hierarchy so that
231
    // ref.test/ref.cast match them against the concrete types.
232
1.30M
    TypeCode BotTypeCode = TypeCode::NullRef;
233
1.30M
    if (ValType.isAbsHeapType()) {
234
65.8k
      switch (ValType.getHeapTypeCode()) {
235
570
      case TypeCode::NullFuncRef:
236
16.8k
      case TypeCode::FuncRef:
237
16.8k
        BotTypeCode = TypeCode::NullFuncRef;
238
16.8k
        break;
239
322
      case TypeCode::NullExternRef:
240
5.08k
      case TypeCode::ExternRef:
241
5.08k
        BotTypeCode = TypeCode::NullExternRef;
242
5.08k
        break;
243
162
      case TypeCode::NullExnRef:
244
6.65k
      case TypeCode::ExnRef:
245
6.65k
        BotTypeCode = TypeCode::NullExnRef;
246
6.65k
        break;
247
402
      case TypeCode::NullRef:
248
1.43k
      case TypeCode::AnyRef:
249
1.94k
      case TypeCode::EqRef:
250
2.67k
      case TypeCode::I31Ref:
251
28.6k
      case TypeCode::StructRef:
252
37.2k
      case TypeCode::ArrayRef:
253
37.2k
        BotTypeCode = TypeCode::NullRef;
254
37.2k
        break;
255
0
      default:
256
0
        assumingUnreachable();
257
65.8k
      }
258
1.23M
    } else {
259
1.23M
      assuming(ValType.getTypeIndex() < CompositeTypes.size());
260
1.23M
      const auto *CompType = CompositeTypes[ValType.getTypeIndex()];
261
1.23M
      assuming(CompType != nullptr);
262
1.23M
      BotTypeCode =
263
1.23M
          CompType->isFunc() ? TypeCode::NullFuncRef : TypeCode::NullRef;
264
1.23M
    }
265
1.30M
    const WasmEdge::ValType VType(TypeCode::RefNull, BotTypeCode);
266
1.30M
    std::array<uint8_t, 16> Data{};
267
1.30M
    std::copy_n(VType.getRawData().cbegin(), 8, Data.begin());
268
1.30M
    return LLVM::Value::getConstVector8(LLContext, Data);
269
1.30M
  }
270
31.5k
  case TypeCode::V128:
271
31.5k
    return LLVM::Value::getConstNull(
272
31.5k
        LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2));
273
32.6k
  case TypeCode::F32:
274
32.6k
    return LLVM::Value::getConstNull(LLContext.getFloatTy());
275
115k
  case TypeCode::F64:
276
115k
    return LLVM::Value::getConstNull(LLContext.getDoubleTy());
277
0
  default:
278
0
    assumingUnreachable();
279
1.70M
  }
280
1.70M
}
281
282
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
283
499
                                      LLVM::Value Struct) noexcept {
284
499
  const auto N = Struct.getType().getStructNumElements();
285
499
  std::vector<LLVM::Value> Ret;
286
499
  Ret.reserve(N);
287
1.89k
  for (unsigned I = 0; I < N; ++I) {
288
1.39k
    Ret.push_back(Builder.createExtractValue(Struct, I));
289
1.39k
  }
290
499
  return Ret;
291
499
}
292
293
} // namespace WasmEdge::LLVM