/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 | | LLVM::Value IntrinsicsTable; |
113 | | LLVM::FunctionCallee Trap; |
114 | | CompileContext(LLVM::Context C, LLVM::Module &M, |
115 | | bool IsGenericBinary) noexcept; |
116 | | LLVM::Value getMemory(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
117 | 21.5k | uint32_t Index) noexcept { |
118 | 21.5k | auto Array = Builder.createExtractValue(ExecCtx, 0); |
119 | | #if WASMEDGE_ALLOCATOR_IS_STABLE |
120 | | auto VPtr = Builder.createLoad( |
121 | | Int8PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array, |
122 | | LLContext.getInt64(Index))); |
123 | | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
124 | | LLVM::Metadata(LLContext, {})); |
125 | | #else |
126 | 21.5k | auto VPtrPtr = Builder.createLoad( |
127 | 21.5k | Int8PtrPtrTy, Builder.createInBoundsGEP1(Int8PtrPtrTy, Array, |
128 | 21.5k | LLContext.getInt64(Index))); |
129 | 21.5k | VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
130 | 21.5k | LLVM::Metadata(LLContext, {})); |
131 | 21.5k | auto VPtr = Builder.createLoad( |
132 | 21.5k | Int8PtrTy, |
133 | 21.5k | Builder.createInBoundsGEP1(Int8PtrTy, VPtrPtr, LLContext.getInt64(0))); |
134 | 21.5k | #endif |
135 | 21.5k | return Builder.createBitCast(VPtr, Int8PtrTy); |
136 | 21.5k | } |
137 | | LLVM::Value getMemorySize(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
138 | 698 | uint32_t Index) noexcept { |
139 | 698 | auto Array = Builder.createExtractValue(ExecCtx, 1); |
140 | 698 | auto VPtr = Builder.createLoad( |
141 | 698 | Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array, |
142 | 698 | LLContext.getInt64(Index))); |
143 | 698 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
144 | 698 | LLVM::Metadata(LLContext, {})); |
145 | 698 | return Builder.createLoad(Int64Ty, VPtr); |
146 | 698 | } |
147 | | LLVM::Value getTable(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
148 | 873 | uint32_t Index) noexcept { |
149 | 873 | auto RefPtrTy = Int64x2Ty.getPointerTo(); |
150 | 873 | auto Array = Builder.createExtractValue(ExecCtx, 2); |
151 | 873 | auto VPtrPtr = Builder.createLoad( |
152 | 873 | RefPtrTy.getPointerTo(), |
153 | 873 | Builder.createInBoundsGEP1(RefPtrTy.getPointerTo(), Array, |
154 | 873 | LLContext.getInt64(Index))); |
155 | 873 | VPtrPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
156 | 873 | LLVM::Metadata(LLContext, {})); |
157 | 873 | return Builder.createLoad( |
158 | 873 | RefPtrTy, |
159 | 873 | Builder.createInBoundsGEP1(RefPtrTy, VPtrPtr, LLContext.getInt64(0))); |
160 | 873 | } |
161 | | LLVM::Value getTableSize(LLVM::Builder &Builder, LLVM::Value ExecCtx, |
162 | 889 | uint32_t Index) noexcept { |
163 | 889 | auto Array = Builder.createExtractValue(ExecCtx, 3); |
164 | 889 | auto VPtr = Builder.createLoad( |
165 | 889 | Int64PtrTy, Builder.createInBoundsGEP1(Int64PtrTy, Array, |
166 | 889 | LLContext.getInt64(Index))); |
167 | 889 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
168 | 889 | LLVM::Metadata(LLContext, {})); |
169 | 889 | return Builder.createLoad(Int64Ty, VPtr); |
170 | 889 | } |
171 | | LLVM::Value getModuleInst(LLVM::Builder &Builder, |
172 | 795 | LLVM::Value ExecCtx) noexcept { |
173 | 795 | return Builder.createExtractValue(ExecCtx, 10); |
174 | 795 | } |
175 | | std::pair<LLVM::Type, LLVM::Value> getGlobal(LLVM::Builder &Builder, |
176 | | LLVM::Value ExecCtx, |
177 | 452 | uint32_t Index) noexcept { |
178 | 452 | auto Ty = Globals[Index]; |
179 | 452 | auto Array = Builder.createExtractValue(ExecCtx, 4); |
180 | 452 | auto VPtr = Builder.createLoad( |
181 | 452 | Int128PtrTy, Builder.createInBoundsGEP1(Int8PtrTy, Array, |
182 | 452 | LLContext.getInt64(Index))); |
183 | 452 | VPtr.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
184 | 452 | LLVM::Metadata(LLContext, {})); |
185 | 452 | auto Ptr = Builder.createBitCast(VPtr, Ty.getPointerTo()); |
186 | 452 | return {Ty, Ptr}; |
187 | 452 | } |
188 | | LLVM::Value getInstrCount(LLVM::Builder &Builder, |
189 | 0 | LLVM::Value ExecCtx) noexcept { |
190 | 0 | return Builder.createExtractValue(ExecCtx, 5); |
191 | 0 | } |
192 | | LLVM::Value getCostTable(LLVM::Builder &Builder, |
193 | 0 | LLVM::Value ExecCtx) noexcept { |
194 | 0 | return Builder.createExtractValue(ExecCtx, 6); |
195 | 0 | } |
196 | 0 | LLVM::Value getGas(LLVM::Builder &Builder, LLVM::Value ExecCtx) noexcept { |
197 | 0 | return Builder.createExtractValue(ExecCtx, 7); |
198 | 0 | } |
199 | | LLVM::Value getGasLimit(LLVM::Builder &Builder, |
200 | 0 | LLVM::Value ExecCtx) noexcept { |
201 | 0 | return Builder.createExtractValue(ExecCtx, 8); |
202 | 0 | } |
203 | | LLVM::Value getStopToken(LLVM::Builder &Builder, |
204 | 0 | LLVM::Value ExecCtx) noexcept { |
205 | 0 | return Builder.createExtractValue(ExecCtx, 9); |
206 | 0 | } |
207 | | LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder, |
208 | | Executable::Intrinsics Index, |
209 | 7.43k | LLVM::Type Ty) noexcept { |
210 | 7.43k | const auto Value = static_cast<uint32_t>(Index); |
211 | 7.43k | auto PtrTy = Ty.getPointerTo(); |
212 | 7.43k | auto PtrPtrTy = PtrTy.getPointerTo(); |
213 | 7.43k | auto IT = Builder.createLoad(IntrinsicsTablePtrTy, IntrinsicsTable); |
214 | 7.43k | IT.setMetadata(LLContext, LLVM::Core::InvariantGroup, |
215 | 7.43k | LLVM::Metadata(LLContext, {})); |
216 | 7.43k | auto VPtr = |
217 | 7.43k | Builder.createInBoundsGEP2(IntrinsicsTableTy, IT, LLContext.getInt64(0), |
218 | 7.43k | LLContext.getInt64(Value)); |
219 | 7.43k | auto Ptr = Builder.createBitCast(VPtr, PtrPtrTy); |
220 | 7.43k | return {Ty, Builder.createLoad(PtrTy, Ptr)}; |
221 | 7.43k | } |
222 | 2.23k | void compileTrap() noexcept { |
223 | 2.23k | LLVM::Builder Builder(LLContext); |
224 | 2.23k | Builder.positionAtEnd( |
225 | 2.23k | LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry")); |
226 | 2.23k | auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty}); |
227 | 2.23k | auto CallTrap = Builder.createCall( |
228 | 2.23k | getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy), |
229 | 2.23k | {Trap.Fn.getFirstParam()}); |
230 | 2.23k | CallTrap.addCallSiteAttribute(NoReturn); |
231 | 2.23k | Builder.createUnreachable(); |
232 | 2.23k | } |
233 | 2.23k | void addVersionGlobal() noexcept { |
234 | 2.23k | LLModule.get().addGlobal( |
235 | 2.23k | Int32Ty, true, LLVMExternalLinkage, |
236 | 2.23k | LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version"); |
237 | 2.23k | } |
238 | 2.22k | void finalizeIntrinsicsTable() noexcept { |
239 | 2.22k | if (auto Table = LLModule.get().getNamedGlobal("intrinsics")) { |
240 | 1.27k | Table.setInitializer(LLVM::Value::getConstNull(Table.getType())); |
241 | 1.27k | Table.setGlobalConstant(false); |
242 | 1.27k | } else { |
243 | 949 | LLModule.get().addGlobal(IntrinsicsTablePtrTy, false, LLVMExternalLinkage, |
244 | 949 | LLVM::Value::getConstNull(IntrinsicsTablePtrTy), |
245 | 949 | "intrinsics"); |
246 | 949 | } |
247 | 2.22k | } |
248 | | std::pair<std::vector<ValType>, std::vector<ValType>> |
249 | 18.5k | resolveBlockType(const BlockType &BType) const noexcept { |
250 | 18.5k | using VecT = std::vector<ValType>; |
251 | 18.5k | using RetT = std::pair<VecT, VecT>; |
252 | 18.5k | if (BType.isEmpty()) { |
253 | 2.25k | return RetT{}; |
254 | 2.25k | } |
255 | 16.3k | if (BType.isValType()) { |
256 | 2.46k | return RetT{{}, {BType.getValType()}}; |
257 | 13.8k | } else { |
258 | | // Type index case. t2* = type[index].returns |
259 | 13.8k | const uint32_t TypeIdx = BType.getTypeIndex(); |
260 | 13.8k | const auto &FType = CompositeTypes[TypeIdx]->getFuncType(); |
261 | 13.8k | return RetT{ |
262 | 13.8k | VecT(FType.getParamTypes().begin(), FType.getParamTypes().end()), |
263 | 13.8k | VecT(FType.getReturnTypes().begin(), FType.getReturnTypes().end())}; |
264 | 13.8k | } |
265 | 16.3k | } |
266 | | }; |
267 | | |
268 | | bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
269 | | LLVM::Type toLLVMType(LLVM::Context LLContext, |
270 | | const WasmEdge::ValType &ValType) noexcept; |
271 | | std::vector<LLVM::Type> |
272 | | toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, |
273 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
274 | | LLVM::Type |
275 | | toLLVMRetsType(LLVM::Context LLContext, |
276 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
277 | | LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, |
278 | | const WasmEdge::AST::FunctionType &FuncType) noexcept; |
279 | | LLVM::Value |
280 | | toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType, |
281 | | WasmEdge::Span<const WasmEdge::AST::CompositeType *const> |
282 | | CompositeTypes) noexcept; |
283 | | std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder, |
284 | | LLVM::Value Struct) noexcept; |
285 | | LLVM::Type toLLVMType(LLVM::Context LLContext, |
286 | | const WasmEdge::AddressType AddrType) noexcept; |
287 | | std::vector<LLVM::Type> |
288 | | toLLVMTypeVector(LLVM::Context LLContext, |
289 | | WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; |
290 | | |
291 | | } // namespace WasmEdge::LLVM |