/src/WasmEdge/lib/llvm/compiler/context.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | #pragma once |
4 | | |
5 | | #include "llvm/compiler.h" |
6 | | |
7 | | #include "llvm.h" |
8 | | |
9 | | #include "aot/version.h" |
10 | | #include "system/allocator.h" |
11 | | |
12 | | #include <cstdint> |
13 | | #include <functional> |
14 | | |
15 | | #include <tuple> |
16 | | #include <utility> |
17 | | #include <vector> |
18 | | |
19 | | namespace WasmEdge::LLVM { |
20 | | |
21 | | // XXX: Misalignment handler not implemented yet, forcing unalignment |
22 | | // force unalignment load/store |
23 | | inline constexpr const bool kForceUnalignment = true; |
24 | | |
25 | | // force checking div/rem on zero |
26 | | inline constexpr const bool kForceDivCheck = true; |
27 | | |
28 | | // Size of a ValVariant |
29 | | inline constexpr const uint32_t kValSize = sizeof(WasmEdge::ValVariant); |
30 | | |
31 | | struct Compiler::CompileContext { |
32 | | LLVM::Context LLContext; |
33 | | std::reference_wrapper<LLVM::Module> LLModule; |
34 | | LLVM::Attribute Cold; |
35 | | LLVM::Attribute NoAlias; |
36 | | LLVM::Attribute NoInline; |
37 | | LLVM::Attribute NoReturn; |
38 | | LLVM::Attribute ReadOnly; |
39 | | LLVM::Attribute StrictFP; |
40 | | LLVM::Attribute UWTable; |
41 | | LLVM::Attribute NoStackArgProbe; |
42 | | LLVM::Type VoidTy; |
43 | | LLVM::Type Int8Ty; |
44 | | LLVM::Type Int16Ty; |
45 | | LLVM::Type Int32Ty; |
46 | | LLVM::Type Int64Ty; |
47 | | LLVM::Type Int128Ty; |
48 | | LLVM::Type FloatTy; |
49 | | LLVM::Type DoubleTy; |
50 | | LLVM::Type Int8x16Ty; |
51 | | LLVM::Type Int16x8Ty; |
52 | | LLVM::Type Int32x4Ty; |
53 | | LLVM::Type Floatx4Ty; |
54 | | LLVM::Type Int64x2Ty; |
55 | | LLVM::Type Doublex2Ty; |
56 | | LLVM::Type Int128x1Ty; |
57 | | LLVM::Type Int8PtrTy; |
58 | | LLVM::Type Int32PtrTy; |
59 | | LLVM::Type Int64PtrTy; |
60 | | LLVM::Type Int128PtrTy; |
61 | | LLVM::Type Int8PtrPtrTy; |
62 | | LLVM::Type ExecCtxTy; |
63 | | LLVM::Type ExecCtxPtrTy; |
64 | | LLVM::Type IntrinsicsTableTy; |
65 | | LLVM::Type IntrinsicsTablePtrTy; |
66 | | LLVM::Message SubtargetFeatures; |
67 | | |
68 | | #if defined(__x86_64__) |
69 | | #if defined(__XOP__) |
70 | | bool SupportXOP = true; |
71 | | #else |
72 | | bool SupportXOP = false; |
73 | | #endif |
74 | | |
75 | | #if defined(__SSE4_1__) |
76 | | bool SupportSSE4_1 = true; |
77 | | #else |
78 | | bool SupportSSE4_1 = false; |
79 | | #endif |
80 | | |
81 | | #if defined(__SSSE3__) |
82 | | bool SupportSSSE3 = true; |
83 | | #else |
84 | | bool SupportSSSE3 = false; |
85 | | #endif |
86 | | |
87 | | #if defined(__SSE2__) |
88 | | bool SupportSSE2 = true; |
89 | | #else |
90 | | bool SupportSSE2 = false; |
91 | | #endif |
92 | | #endif |
93 | | |
94 | | #if defined(__aarch64__) |
95 | | #if defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__ARM_NEON_FP) |
96 | | bool SupportNEON = true; |
97 | | #else |
98 | | bool SupportNEON = false; |
99 | | #endif |
100 | | #endif |
101 | | |
102 | | std::vector<const AST::CompositeType *> CompositeTypes; |
103 | | std::vector<LLVM::Value> FunctionWrappers; |
104 | | std::vector<std::tuple<uint32_t, LLVM::FunctionCallee, |
105 | | const WasmEdge::AST::CodeSegment *>> |
106 | | Functions; |
107 | | std::vector<LLVM::Value> LazyJITCacheVars; |
108 | | uint32_t ImportCount = 0; |
109 | | std::vector<LLVM::Type> MemoryAddrTypes; |
110 | | std::vector<LLVM::Type> TableAddrTypes; |
111 | | std::vector<LLVM::Type> Globals; |
112 | | std::vector<uint32_t> Tags; |
113 | | LLVM::Value IntrinsicsTable; |
114 | | LLVM::FunctionCallee Trap; |
115 | | CompileContext(LLVM::Context C, LLVM::Module &M, |
116 | | bool IsGenericBinary) noexcept; |
117 | | LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
118 | 21.8k | uint32_t Index) noexcept { |
119 | 21.8k | auto Array = Builder.createExtractValue(ExecCtx, 0); |
120 | | #if WASMEDGE_ALLOCATOR_IS_STABLE |
121 | | auto VPtr = Builder.createLoad( |
122 | | Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array, |
123 | | LLContext.getInt64(Index))); |
124 | | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
125 | | LLVM::Metadata(LLContext, {})); |
126 | | #else |
127 | 21.8k | auto VPtrPtr = Builder.createLoad( |
128 | 21.8k | Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array, |
129 | 21.8k | LLContext.getInt64(Index))); |
130 | 21.8k | VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
131 | 21.8k | LLVM::Metadata(LLContext, {})); |
132 | 21.8k | auto VPtr = Builder.createLoad( |
133 | 21.8k | Int8PtrTy, |
134 | 21.8k | Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0))); |
135 | 21.8k | #endif |
136 | 21.8k | return Builder.createBitCast(VPtr, Int8PtrTy); |
137 | 21.8k | } |
138 | | LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
139 | 767 | uint32_t Index) noexcept { |
140 | 767 | auto Array = Builder.createExtractValue(ExecCtx, 1); |
141 | 767 | auto VPtr = Builder.createLoad( |
142 | 767 | Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array, |
143 | 767 | LLContext.getInt64(Index))); |
144 | 767 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
145 | 767 | LLVM::Metadata(LLContext, {})); |
146 | 767 | return Builder.createLoad(Int64Ty, VPtr); |
147 | 767 | } |
148 | | LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
149 | 1.00k | uint32_t Index) noexcept { |
150 | 1.00k | auto RefPtrTy = Int64x2Ty.getPointerTo(); |
151 | 1.00k | auto Array = Builder.createExtractValue(ExecCtx, 2); |
152 | 1.00k | auto VPtrPtr = Builder.createLoad( |
153 | 1.00k | RefPtrTy.getPointerTo(), |
154 | 1.00k | Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array, |
155 | 1.00k | LLContext.getInt64(Index))); |
156 | 1.00k | VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
157 | 1.00k | LLVM::Metadata(LLContext, {})); |
158 | 1.00k | return Builder.createLoad( |
159 | 1.00k | RefPtrTy, |
160 | 1.00k | Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0))); |
161 | 1.00k | } |
162 | | LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
163 | 1.02k | uint32_t Index) noexcept { |
164 | 1.02k | auto Array = Builder.createExtractValue(ExecCtx, 3); |
165 | 1.02k | auto VPtr = Builder.createLoad( |
166 | 1.02k | Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array, |
167 | 1.02k | LLContext.getInt64(Index))); |
168 | 1.02k | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
169 | 1.02k | LLVM::Metadata(LLContext, {})); |
170 | 1.02k | return Builder.createLoad(Int64Ty, VPtr); |
171 | 1.02k | } |
172 | | std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder, |
173 | | LLVM::Value ExecCtx, |
174 | 462 | uint32_t Index) noexcept { |
175 | 462 | auto Ty = Globals[Index]; |
176 | 462 | auto Array = Builder.createExtractValue(ExecCtx, 4); |
177 | 462 | auto VPtr = Builder.createLoad( |
178 | 462 | Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array, |
179 | 462 | LLContext.getInt64(Index))); |
180 | 462 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
181 | 462 | LLVM::Metadata(LLContext, {})); |
182 | 462 | auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo()); |
183 | 462 | return {Ty, Ptr}; |
184 | 462 | } |
185 | | LLVM::Value getTag(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
186 | 0 | uint32_t Index) noexcept { |
187 | 0 | auto Array = Builder.createExtractValue(ExecCtx, 5); |
188 | 0 | auto VPtr = Builder.createLoad( |
189 | 0 | Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array, |
190 | 0 | LLContext.getInt64(Index))); |
191 | 0 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
192 | 0 | LLVM::Metadata(LLContext, {})); |
193 | 0 | return VPtr; |
194 | 0 | } |
195 | | LLVM::Value getPendingExnTagAddr(LLVM::Builder &Builder, |
196 | 4.16k | LLVM::Value ExecCtx) noexcept { |
197 | 4.16k | return Builder.createExtractValue(ExecCtx, 6); |
198 | 4.16k | } |
199 | | LLVM::Value getInstrCount(LLVM::Builder &Builder, |
200 | 0 | LLVM::Value ExecCtx) noexcept { |
201 | 0 | return Builder.createExtractValue(ExecCtx, 7); |
202 | 0 | } |
203 | | LLVM::Value getCostTable(LLVM::Builder &Builder, |
204 | 0 | LLVM::Value ExecCtx) noexcept { |
205 | 0 | return Builder.createExtractValue(ExecCtx, 8); |
206 | 0 | } |
207 | 0 | LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept { |
208 | 0 | return Builder.createExtractValue(ExecCtx, 9); |
209 | 0 | } |
210 | | LLVM::Value getGasLimit(LLVM::Builder &Builder, |
211 | 0 | LLVM::Value ExecCtx) noexcept { |
212 | 0 | return Builder.createExtractValue(ExecCtx, 10); |
213 | 0 | } |
214 | | LLVM::Value getStopToken(LLVM::Builder &Builder, |
215 | 0 | LLVM::Value ExecCtx) noexcept { |
216 | 0 | return Builder.createExtractValue(ExecCtx, 11); |
217 | 0 | } |
218 | | LLVM::Value getModuleInst(LLVM::Builder &Builder, |
219 | 927 | LLVM::Value ExecCtx) noexcept { |
220 | 927 | return Builder.createExtractValue(ExecCtx, 12); |
221 | 927 | } |
222 | | LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder, |
223 | | Executable::Intrinsics Index, |
224 | 8.06k | LLVM::Type Ty) noexcept { |
225 | 8.06k | const auto Value = static_cast<uint32_t>(Index); |
226 | 8.06k | auto PtrTy = Ty.getPointerTo(); |
227 | 8.06k | auto PtrPtrTy = PtrTy.getPointerTo(); |
228 | 8.06k | auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable); |
229 | 8.06k | IT.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
230 | 8.06k | LLVM::Metadata(LLContext, {})); |
231 | 8.06k | auto VPtr = |
232 | 8.06k | Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0), |
233 | 8.06k | LLContext.getInt64(Value)); |
234 | 8.06k | auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy); |
235 | 8.06k | return {Ty, Builder.createLoad(PtrTy, Ptr)}; |
236 | 8.06k | } |
237 | 2.31k | void compileTrap() noexcept { |
238 | 2.31k | LLVM::Builder Builder(LLContext); |
239 | 2.31k | Builder.positionAtEnd( |
240 | 2.31k | LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry")); |
241 | 2.31k | auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty}); |
242 | 2.31k | auto CallTrap = Builder.createCall( |
243 | 2.31k | getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy), |
244 | 2.31k | {Trap.Fn.getFirstParam()}); |
245 | 2.31k | CallTrap.addCallSiteAttribute(NoReturn); |
246 | 2.31k | Builder.createUnreachable(); |
247 | 2.31k | } |
248 | 2.31k | void addVersionGlobal() noexcept { |
249 | 2.31k | LLModule.get().addGlobal( |
250 | 2.31k | Int32Ty, true, LLVMExternalLinkage, |
251 | 2.31k | LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version"); |
252 | 2.31k | } |
253 | 2.31k | void finalizeIntrinsicsTable() noexcept { |
254 | 2.31k | if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) { |
255 | 1.55k | Table.setInitializer(LLVM::Value::getConstNull(Table.getType())); |
256 | 1.55k | Table.setGlobalConstant(false); |
257 | 1.55k | } else { |
258 | 766 | LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage, |
259 | 766 | LLVM::Value::getConstNull(IntrinsicsTablePtrTy), |
260 | 766 | "intrinsics"); |
261 | 766 | } |
262 | 2.31k | } |
263 | | std::pair<std::vector<ValType>, std::vector<ValType>> |
264 | 19.4k | resolveBlockType(const BlockType &BType) const noexcept { |
265 | 19.4k | using VecT = std::vector<ValType>; |
266 | 19.4k | using RetT = std::pair<VecT, VecT>; |
267 | 19.4k | if (BType.isEmpty()) { |
268 | 2.32k | return RetT{}; |
269 | 2.32k | } |
270 | 17.1k | if (BType.isValType()) { |
271 | 2.53k | return RetT{{}, {BType.getValType()}}; |
272 | 14.6k | } else { |
273 | | // Type index case. t2* = type[index].returns |
274 | 14.6k | const uint32_t TypeIdx = BType.getTypeIndex(); |
275 | 14.6k | const auto &FType = CompositeTypes[TypeIdx]->getFuncType(); |
276 | 14.6k | return RetT{ |
277 | 14.6k | VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()), |
278 | 14.6k | VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())}; |
279 | 14.6k | } |
280 | 17.1k | } |
281 | | }; |
282 | | |
283 | | bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
284 | | LLVM::Type toLLVMType(LLVM::Context LLContext, |
285 | | const WasmEdge::ValType &ValType) noexcept; |
286 | | std::vector<LLVM::Type> |
287 | | toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, |
288 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
289 | | LLVM::Type |
290 | | toLLVMRetsType(LLVM::Context LLContext, |
291 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
292 | | LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, |
293 | | const WasmEdge::AST::FunctionType &FuncType) noexcept; |
294 | | LLVM::Value |
295 | | toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType, |
296 | | WasmEdge::Span<const WasmEdge::AST::CompositeType *const> |
297 | | CompositeTypes) noexcept; |
298 | | std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder, |
299 | | LLVM::Value Struct) noexcept; |
300 | | LLVM::Type toLLVMType(LLVM::Context LLContext, |
301 | | const WasmEdge::AddressType AddrType) noexcept; |
302 | | std::vector<LLVM::Type> |
303 | | toLLVMTypeVector(LLVM::Context LLContext, |
304 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
305 | | |
306 | | } // namespace WasmEdge::LLVM |