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