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.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.23k
    : LLContext(C), LLModule(M),
21
2.23k
      Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)),
22
2.23k
      NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)),
23
2.23k
      NoInline(LLVM::Attribute::createEnum(C, LLVM::Core::NoInline, 0)),
24
2.23k
      NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)),
25
2.23k
      ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)),
26
2.23k
      StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)),
27
2.23k
      UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable,
28
2.23k
                                          LLVM::Core::UWTableDefault)),
29
      NoStackArgProbe(
30
2.23k
          LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})),
31
2.23k
      VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()),
32
2.23k
      Int16Ty(LLContext.getInt16Ty()), Int32Ty(LLContext.getInt32Ty()),
33
2.23k
      Int64Ty(LLContext.getInt64Ty()), Int128Ty(LLContext.getInt128Ty()),
34
2.23k
      FloatTy(LLContext.getFloatTy()), DoubleTy(LLContext.getDoubleTy()),
35
2.23k
      Int8x16Ty(LLVM::Type::getVectorType(Int8Ty, 16)),
36
2.23k
      Int16x8Ty(LLVM::Type::getVectorType(Int16Ty, 8)),
37
2.23k
      Int32x4Ty(LLVM::Type::getVectorType(Int32Ty, 4)),
38
2.23k
      Floatx4Ty(LLVM::Type::getVectorType(FloatTy, 4)),
39
2.23k
      Int64x2Ty(LLVM::Type::getVectorType(Int64Ty, 2)),
40
2.23k
      Doublex2Ty(LLVM::Type::getVectorType(DoubleTy, 2)),
41
2.23k
      Int128x1Ty(LLVM::Type::getVectorType(Int128Ty, 1)),
42
2.23k
      Int8PtrTy(Int8Ty.getPointerTo()), Int32PtrTy(Int32Ty.getPointerTo()),
43
2.23k
      Int64PtrTy(Int64Ty.getPointerTo()), Int128PtrTy(Int128Ty.getPointerTo()),
44
2.23k
      Int8PtrPtrTy(Int8PtrTy.getPointerTo()),
45
2.23k
      ExecCtxTy(LLVM::Type::getStructType(
46
2.23k
          "ExecCtx",
47
2.23k
          std::initializer_list<LLVM::Type>{
48
              // MemoryPtrs
49
2.23k
              Int8PtrTy.getPointerTo(),
50
              // MemorySizes
51
2.23k
              Int64PtrTy.getPointerTo(),
52
              // TableRefs
53
2.23k
              Int64x2Ty.getPointerTo().getPointerTo(),
54
              // TableSizes
55
2.23k
              Int64PtrTy.getPointerTo(),
56
              // Globals
57
2.23k
              Int128PtrTy.getPointerTo(),
58
              // InstrCount
59
2.23k
              Int64PtrTy,
60
              // CostTable
61
2.23k
              LLVM::Type::getArrayType(Int64Ty, UINT16_MAX + 1).getPointerTo(),
62
              // Gas
63
2.23k
              Int64PtrTy,
64
              // GasLimit
65
2.23k
              Int64Ty,
66
              // StopToken
67
2.23k
              Int32PtrTy,
68
              // ModuleInst
69
2.23k
              Int8PtrTy,
70
2.23k
          })),
71
2.23k
      ExecCtxPtrTy(ExecCtxTy.getPointerTo()),
72
2.23k
      IntrinsicsTableTy(LLVM::Type::getArrayType(
73
2.23k
          Int8Ty.getPointerTo(),
74
2.23k
          static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))),
75
2.23k
      IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()),
76
2.23k
      IntrinsicsTable(LLModule.get().addGlobal(IntrinsicsTablePtrTy, true,
77
2.23k
                                               LLVMExternalLinkage,
78
2.23k
                                               LLVM::Value(), "intrinsics")) {
79
2.23k
  Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty});
80
2.23k
  Trap.Fn = LLModule.get().addFunction(Trap.Ty, LLVMPrivateLinkage, "trap");
81
2.23k
  Trap.Fn.setDSOLocal(true);
82
2.23k
  Trap.Fn.addFnAttr(NoStackArgProbe);
83
2.23k
  Trap.Fn.addFnAttr(StrictFP);
84
2.23k
  Trap.Fn.addFnAttr(UWTable);
85
2.23k
  Trap.Fn.addFnAttr(NoReturn);
86
2.23k
  Trap.Fn.addFnAttr(Cold);
87
2.23k
  Trap.Fn.addFnAttr(NoInline);
88
89
2.23k
  if (!IsGenericBinary) {
90
2.23k
    SubtargetFeatures = LLVM::getHostCPUFeatures();
91
2.23k
    auto Features = SubtargetFeatures.string_view();
92
194k
    while (!Features.empty()) {
93
191k
      std::string_view Feature;
94
191k
      if (auto Pos = Features.find(','); Pos != std::string_view::npos) {
95
189k
        Feature = Features.substr(0, Pos);
96
189k
        Features = Features.substr(Pos + 1);
97
189k
      } else {
98
2.23k
        Feature = std::exchange(Features, std::string_view());
99
2.23k
      }
100
191k
      if (Feature[0] != '+') {
101
107k
        continue;
102
107k
      }
103
84.7k
      Feature = Feature.substr(1);
104
105
84.7k
#if defined(__x86_64__)
106
84.7k
      if (!SupportXOP && Feature == "xop"sv) {
107
0
        SupportXOP = true;
108
0
      }
109
84.7k
      if (!SupportSSE4_1 && Feature == "sse4.1"sv) {
110
2.23k
        SupportSSE4_1 = true;
111
2.23k
      }
112
84.7k
      if (!SupportSSSE3 && Feature == "ssse3"sv) {
113
2.23k
        SupportSSSE3 = true;
114
2.23k
      }
115
84.7k
      if (!SupportSSE2 && Feature == "sse2"sv) {
116
0
        SupportSSE2 = true;
117
0
      }
118
#elif defined(__aarch64__)
119
      if (!SupportNEON && Feature == "neon"sv) {
120
        SupportNEON = true;
121
      }
122
#endif
123
84.7k
    }
124
2.23k
  }
125
126
2.23k
  compileTrap();
127
2.23k
}
128
129
34.8k
bool isVoidReturn(Span<const ValType> ValTypes) noexcept {
130
34.8k
  return ValTypes.empty();
131
34.8k
}
132
133
LLVM::Type toLLVMType(LLVM::Context LLContext,
134
699k
                      const ValType &ValType) noexcept {
135
699k
  switch (ValType.getCode()) {
136
56.2k
  case TypeCode::I32:
137
56.2k
    return LLContext.getInt32Ty();
138
190k
  case TypeCode::I64:
139
190k
    return LLContext.getInt64Ty();
140
797
  case TypeCode::Ref:
141
62.3k
  case TypeCode::RefNull:
142
103k
  case TypeCode::V128:
143
103k
    return LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2);
144
34.4k
  case TypeCode::F32:
145
34.4k
    return LLContext.getFloatTy();
146
315k
  case TypeCode::F64:
147
315k
    return LLContext.getDoubleTy();
148
0
  default:
149
0
    assumingUnreachable();
150
699k
  }
151
699k
}
152
153
LLVM::Type toLLVMType(LLVM::Context LLContext,
154
1.16k
                      const AddressType AddrType) noexcept {
155
1.16k
  switch (AddrType) {
156
1.14k
  case AddressType::I32:
157
1.14k
    return LLContext.getInt32Ty();
158
18
  case AddressType::I64:
159
18
    return LLContext.getInt64Ty();
160
0
  default:
161
0
    assumingUnreachable();
162
1.16k
  }
163
1.16k
}
164
165
std::vector<LLVM::Type>
166
toLLVMTypeVector(LLVM::Context LLContext,
167
20.1k
                 Span<const ValType> ValTypes) noexcept {
168
20.1k
  std::vector<LLVM::Type> Result;
169
20.1k
  Result.reserve(ValTypes.size());
170
20.1k
  for (const auto &Type : ValTypes) {
171
19.6k
    Result.push_back(toLLVMType(LLContext, Type));
172
19.6k
  }
173
20.1k
  return Result;
174
20.1k
}
175
176
std::vector<LLVM::Type> toLLVMArgsType(LLVM::Context LLContext,
177
                                       LLVM::Type ExecCtxPtrTy,
178
16.2k
                                       Span<const ValType> ValTypes) noexcept {
179
16.2k
  auto Result = toLLVMTypeVector(LLContext, ValTypes);
180
16.2k
  Result.insert(Result.begin(), ExecCtxPtrTy);
181
16.2k
  return Result;
182
16.2k
}
183
184
LLVM::Type toLLVMRetsType(LLVM::Context LLContext,
185
16.2k
                          Span<const ValType> ValTypes) noexcept {
186
16.2k
  if (isVoidReturn(ValTypes)) {
187
4.20k
    return LLContext.getVoidTy();
188
4.20k
  }
189
12.0k
  if (ValTypes.size() == 1) {
190
11.3k
    return toLLVMType(LLContext, ValTypes.front());
191
11.3k
  }
192
708
  std::vector<LLVM::Type> Result;
193
708
  Result.reserve(ValTypes.size());
194
1.99k
  for (const auto &Type : ValTypes) {
195
1.99k
    Result.push_back(toLLVMType(LLContext, Type));
196
1.99k
  }
197
708
  return LLVM::Type::getStructType(Result);
198
12.0k
}
199
200
LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy,
201
16.2k
                      const AST::FunctionType &FuncType) noexcept {
202
16.2k
  auto ArgsTy =
203
16.2k
      toLLVMArgsType(LLContext, ExecCtxPtrTy, FuncType.getParamTypes());
204
16.2k
  auto RetTy = toLLVMRetsType(LLContext, FuncType.getReturnTypes());
205
16.2k
  return LLVM::Type::getFunctionType(RetTy, ArgsTy);
206
16.2k
}
207
208
LLVM::Value toLLVMConstantZero(
209
    LLVM::Context LLContext, const ValType &ValType,
210
665k
    Span<const AST::CompositeType *const> CompositeTypes) noexcept {
211
665k
  switch (ValType.getCode()) {
212
38.1k
  case TypeCode::I32:
213
38.1k
    return LLVM::Value::getConstNull(LLContext.getInt32Ty());
214
186k
  case TypeCode::I64:
215
186k
    return LLVM::Value::getConstNull(LLContext.getInt64Ty());
216
797
  case TypeCode::Ref:
217
61.5k
  case TypeCode::RefNull: {
218
61.5k
    std::array<uint8_t, 16> Data{};
219
61.5k
    if (ValType.isAbsHeapType()) {
220
      // Abstract heap types are already fine for null refs.
221
22.6k
      const auto Raw = ValType.getRawData();
222
22.6k
      std::copy(Raw.begin(), Raw.end(), Data.begin());
223
38.8k
    } else {
224
      // For non-abstract heap types (concrete type indices), convert to the
225
      // abstract heap type so that ref.cast/ref.test won't dereference a null
226
      // pointer when checking the type.
227
38.8k
      assuming(ValType.getTypeIndex() < CompositeTypes.size());
228
38.8k
      const auto *CompType = CompositeTypes[ValType.getTypeIndex()];
229
38.8k
      assuming(CompType != nullptr);
230
38.8k
      WasmEdge::ValType VType =
231
38.8k
          CompType->isFunc() ? TypeCode::NullFuncRef : TypeCode::NullRef;
232
38.8k
      std::copy_n(VType.getRawData().cbegin(), 8, Data.begin());
233
38.8k
    }
234
61.5k
    return LLVM::Value::getConstVector8(LLContext, Data);
235
61.5k
  }
236
34.8k
  case TypeCode::V128:
237
34.8k
    return LLVM::Value::getConstNull(
238
34.8k
        LLVM::Type::getVectorType(LLContext.getInt64Ty(), 2));
239
31.9k
  case TypeCode::F32:
240
31.9k
    return LLVM::Value::getConstNull(LLContext.getFloatTy());
241
312k
  case TypeCode::F64:
242
312k
    return LLVM::Value::getConstNull(LLContext.getDoubleTy());
243
0
  default:
244
0
    assumingUnreachable();
245
665k
  }
246
665k
}
247
248
std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder,
249
445
                                      LLVM::Value Struct) noexcept {
250
445
  const auto N = Struct.getType().getStructNumElements();
251
445
  std::vector<LLVM::Value> Ret;
252
445
  Ret.reserve(N);
253
1.65k
  for (unsigned I = 0; I < N; ++I) {
254
1.21k
    Ret.push_back(Builder.createExtractValue(Struct, I));
255
1.21k
  }
256
445
  return Ret;
257
445
}
258
259
} // namespace WasmEdge::LLVM