/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 |