/src/WasmEdge/lib/llvm/compiler/refInstr.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "compiler/function_compiler.h" |
5 | | |
6 | | #include <algorithm> |
7 | | #include <array> |
8 | | |
9 | | namespace WasmEdge { |
10 | | |
11 | | Expect<void> |
12 | 14.5k | FunctionCompiler::compileRefOp(const AST::Instruction &Instr) noexcept { |
13 | 14.5k | switch (Instr.getOpCode()) { |
14 | 5.90k | case OpCode::Ref__null: { |
15 | | // For null references, dynamic type downscaling is needed. |
16 | 5.90k | auto NullVal = toLLVMConstantZero(LLContext, Instr.getValType(), |
17 | 5.90k | Context.CompositeTypes); |
18 | 5.90k | stackPush(Builder.createBitCast(NullVal, Context.Int64x2Ty)); |
19 | 5.90k | break; |
20 | 0 | } |
21 | 2.47k | case OpCode::Ref__is_null: |
22 | 2.47k | stackPush(Builder.createZExt( |
23 | 2.47k | Builder.createICmpEQ( |
24 | 2.47k | Builder.createExtractElement( |
25 | 2.47k | Builder.createBitCast(stackPop(), Context.Int64x2Ty), |
26 | 2.47k | LLContext.getInt64(1)), |
27 | 2.47k | LLContext.getInt64(0)), |
28 | 2.47k | Context.Int32Ty)); |
29 | 2.47k | break; |
30 | 115 | case OpCode::Ref__func: |
31 | 115 | stackPush(Builder.createCall( |
32 | 115 | Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc, |
33 | 115 | LLVM::Type::getFunctionType( |
34 | 115 | Context.Int64x2Ty, |
35 | 115 | {Context.Int8PtrTy, Context.Int32Ty}, false)), |
36 | 115 | {Context.getModuleInst(Builder, ModCtx), |
37 | 115 | LLContext.getInt32(Instr.getTargetIndex())})); |
38 | 115 | break; |
39 | 39 | case OpCode::Ref__eq: { |
40 | 39 | LLVM::Value RHS = stackPop(); |
41 | 39 | LLVM::Value LHS = stackPop(); |
42 | 39 | stackPush(Builder.createZExt( |
43 | 39 | Builder.createICmpEQ( |
44 | 39 | Builder.createExtractElement(LHS, LLContext.getInt64(1)), |
45 | 39 | Builder.createExtractElement(RHS, LLContext.getInt64(1))), |
46 | 39 | Context.Int32Ty)); |
47 | 39 | break; |
48 | 0 | } |
49 | 375 | case OpCode::Ref__as_non_null: { |
50 | 375 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "ref_as_non_null.ok"); |
51 | 375 | Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty); |
52 | 375 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
53 | 375 | Builder.createExtractElement(Stack.back(), LLContext.getInt64(1)), |
54 | 375 | LLContext.getInt64(0))); |
55 | 375 | Builder.createCondBr(IsNotNull, Next, |
56 | 375 | getTrapBB(ErrCode::Value::CastNullToNonNull)); |
57 | 375 | Builder.positionAtEnd(Next); |
58 | 375 | break; |
59 | 0 | } |
60 | | |
61 | | // Reference Instructions (GC proposal) |
62 | 63 | case OpCode::Struct__new: |
63 | 126 | case OpCode::Struct__new_default: { |
64 | 126 | LLVM::Value Args = LLVM::Value::getConstPointerNull(Context.Int8PtrTy); |
65 | 126 | assuming(Instr.getTargetIndex() < Context.CompositeTypes.size()); |
66 | 126 | const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()]; |
67 | 126 | assuming(CompType != nullptr && !CompType->isFunc()); |
68 | 126 | auto ArgSize = CompType->getFieldTypes().size(); |
69 | 126 | if (Instr.getOpCode() == OpCode::Struct__new) { |
70 | 63 | std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr); |
71 | 64 | for (size_t I = 0; I < ArgSize; ++I) { |
72 | 1 | ArgsVec[ArgSize - I - 1] = stackPop(); |
73 | 1 | } |
74 | 63 | Args = getTmpValues(ArgSize); |
75 | 63 | Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, |
76 | 63 | LLVM::kValSize); |
77 | 63 | } else { |
78 | 63 | ArgSize = 0; |
79 | 63 | } |
80 | 126 | stackPush(Builder.createCall( |
81 | 126 | Context.getIntrinsic( |
82 | 126 | Builder, Executable::Intrinsics::kStructNew, |
83 | 126 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
84 | 126 | {Context.Int8PtrTy, Context.Int32Ty, |
85 | 126 | Context.Int8PtrTy, Context.Int32Ty}, |
86 | 126 | false)), |
87 | 126 | {Context.getModuleInst(Builder, ModCtx), |
88 | 126 | LLContext.getInt32(Instr.getTargetIndex()), Args, |
89 | 126 | LLContext.getInt32(static_cast<uint32_t>(ArgSize))})); |
90 | 126 | if (Instr.getOpCode() == OpCode::Struct__new) { |
91 | 63 | endTmpValues(); |
92 | 63 | } |
93 | 126 | break; |
94 | 126 | } |
95 | 0 | case OpCode::Struct__get: |
96 | 0 | case OpCode::Struct__get_u: |
97 | 0 | case OpCode::Struct__get_s: { |
98 | 0 | assuming(static_cast<size_t>(Instr.getTargetIndex()) < |
99 | 0 | Context.CompositeTypes.size()); |
100 | 0 | const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()]; |
101 | 0 | assuming(CompType != nullptr && !CompType->isFunc()); |
102 | 0 | assuming(static_cast<size_t>(Instr.getSourceIndex()) < |
103 | 0 | CompType->getFieldTypes().size()); |
104 | 0 | const auto &StorageType = |
105 | 0 | CompType->getFieldTypes()[Instr.getSourceIndex()].getStorageType(); |
106 | 0 | auto Ref = stackPop(); |
107 | 0 | auto IsSigned = (Instr.getOpCode() == OpCode::Struct__get_s) |
108 | 0 | ? LLContext.getInt8(1) |
109 | 0 | : LLContext.getInt8(0); |
110 | 0 | LLVM::Value Ret = getTmpValues(1); |
111 | 0 | Builder.createCall( |
112 | 0 | Context.getIntrinsic( |
113 | 0 | Builder, Executable::Intrinsics::kStructGet, |
114 | 0 | LLVM::Type::getFunctionType(Context.VoidTy, |
115 | 0 | {Context.Int8PtrTy, Context.Int64x2Ty, |
116 | 0 | Context.Int32Ty, Context.Int32Ty, |
117 | 0 | Context.Int8Ty, Context.Int8PtrTy}, |
118 | 0 | false)), |
119 | 0 | {Context.getModuleInst(Builder, ModCtx), Ref, |
120 | 0 | LLContext.getInt32(Instr.getTargetIndex()), |
121 | 0 | LLContext.getInt32(Instr.getSourceIndex()), IsSigned, Ret}); |
122 | |
|
123 | 0 | switch (StorageType.getCode()) { |
124 | 0 | case TypeCode::I8: |
125 | 0 | case TypeCode::I16: |
126 | 0 | case TypeCode::I32: { |
127 | 0 | stackPush( |
128 | 0 | Builder.createValuePtrLoad(Context.Int32Ty, Ret, Context.Int64x2Ty)); |
129 | 0 | break; |
130 | 0 | } |
131 | 0 | case TypeCode::I64: { |
132 | 0 | stackPush( |
133 | 0 | Builder.createValuePtrLoad(Context.Int64Ty, Ret, Context.Int64x2Ty)); |
134 | 0 | break; |
135 | 0 | } |
136 | 0 | case TypeCode::F32: { |
137 | 0 | stackPush( |
138 | 0 | Builder.createValuePtrLoad(Context.FloatTy, Ret, Context.Int64x2Ty)); |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | case TypeCode::F64: { |
142 | 0 | stackPush( |
143 | 0 | Builder.createValuePtrLoad(Context.DoubleTy, Ret, Context.Int64x2Ty)); |
144 | 0 | break; |
145 | 0 | } |
146 | 0 | case TypeCode::V128: |
147 | 0 | case TypeCode::Ref: |
148 | 0 | case TypeCode::RefNull: { |
149 | 0 | stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret, |
150 | 0 | Context.Int64x2Ty)); |
151 | 0 | break; |
152 | 0 | } |
153 | 0 | default: |
154 | 0 | assumingUnreachable(); |
155 | 0 | } |
156 | 0 | endTmpValues(); |
157 | 0 | break; |
158 | 0 | } |
159 | 0 | case OpCode::Struct__set: { |
160 | 0 | auto Val = stackPop(); |
161 | 0 | auto Ref = stackPop(); |
162 | 0 | LLVM::Value Arg = getTmpValues(1); |
163 | 0 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
164 | 0 | Builder.createCall( |
165 | 0 | Context.getIntrinsic( |
166 | 0 | Builder, Executable::Intrinsics::kStructSet, |
167 | 0 | LLVM::Type::getFunctionType(Context.VoidTy, |
168 | 0 | {Context.Int8PtrTy, Context.Int64x2Ty, |
169 | 0 | Context.Int32Ty, Context.Int32Ty, |
170 | 0 | Context.Int8PtrTy}, |
171 | 0 | false)), |
172 | 0 | {Context.getModuleInst(Builder, ModCtx), Ref, |
173 | 0 | LLContext.getInt32(Instr.getTargetIndex()), |
174 | 0 | LLContext.getInt32(Instr.getSourceIndex()), Arg}); |
175 | 0 | endTmpValues(); |
176 | 0 | break; |
177 | 0 | } |
178 | 132 | case OpCode::Array__new: { |
179 | 132 | auto Length = stackPop(); |
180 | 132 | auto Val = stackPop(); |
181 | 132 | LLVM::Value Arg = getTmpValues(1); |
182 | 132 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
183 | 132 | stackPush(Builder.createCall( |
184 | 132 | Context.getIntrinsic( |
185 | 132 | Builder, Executable::Intrinsics::kArrayNew, |
186 | 132 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
187 | 132 | {Context.Int8PtrTy, Context.Int32Ty, |
188 | 132 | Context.Int32Ty, Context.Int8PtrTy, |
189 | 132 | Context.Int32Ty}, |
190 | 132 | false)), |
191 | 132 | {Context.getModuleInst(Builder, ModCtx), |
192 | 132 | LLContext.getInt32(Instr.getTargetIndex()), Length, Arg, |
193 | 132 | LLContext.getInt32(1)})); |
194 | 132 | endTmpValues(); |
195 | 132 | break; |
196 | 0 | } |
197 | 25 | case OpCode::Array__new_default: { |
198 | 25 | auto Length = stackPop(); |
199 | 25 | LLVM::Value Arg = LLVM::Value::getConstPointerNull(Context.Int8PtrTy); |
200 | 25 | stackPush(Builder.createCall( |
201 | 25 | Context.getIntrinsic( |
202 | 25 | Builder, Executable::Intrinsics::kArrayNew, |
203 | 25 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
204 | 25 | {Context.Int8PtrTy, Context.Int32Ty, |
205 | 25 | Context.Int32Ty, Context.Int8PtrTy, |
206 | 25 | Context.Int32Ty}, |
207 | 25 | false)), |
208 | 25 | {Context.getModuleInst(Builder, ModCtx), |
209 | 25 | LLContext.getInt32(Instr.getTargetIndex()), Length, Arg, |
210 | 25 | LLContext.getInt32(0)})); |
211 | 25 | break; |
212 | 0 | } |
213 | 92 | case OpCode::Array__new_fixed: { |
214 | 92 | const auto ArgSize = Instr.getSourceIndex(); |
215 | 92 | std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr); |
216 | 581 | for (size_t I = 0; I < ArgSize; ++I) { |
217 | 489 | ArgsVec[ArgSize - I - 1] = stackPop(); |
218 | 489 | } |
219 | 92 | LLVM::Value Args = getTmpValues(ArgSize); |
220 | 92 | Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, LLVM::kValSize); |
221 | 92 | stackPush(Builder.createCall( |
222 | 92 | Context.getIntrinsic( |
223 | 92 | Builder, Executable::Intrinsics::kArrayNew, |
224 | 92 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
225 | 92 | {Context.Int8PtrTy, Context.Int32Ty, |
226 | 92 | Context.Int32Ty, Context.Int8PtrTy, |
227 | 92 | Context.Int32Ty}, |
228 | 92 | false)), |
229 | 92 | {Context.getModuleInst(Builder, ModCtx), |
230 | 92 | LLContext.getInt32(Instr.getTargetIndex()), |
231 | 92 | LLContext.getInt32(ArgSize), Args, LLContext.getInt32(ArgSize)})); |
232 | 92 | endTmpValues(); |
233 | 92 | break; |
234 | 0 | } |
235 | 0 | case OpCode::Array__new_data: |
236 | 0 | case OpCode::Array__new_elem: { |
237 | 0 | auto Length = stackPop(); |
238 | 0 | auto Start = stackPop(); |
239 | 0 | stackPush(Builder.createCall( |
240 | 0 | Context.getIntrinsic( |
241 | 0 | Builder, |
242 | 0 | ((Instr.getOpCode() == OpCode::Array__new_data) |
243 | 0 | ? Executable::Intrinsics::kArrayNewData |
244 | 0 | : Executable::Intrinsics::kArrayNewElem), |
245 | 0 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
246 | 0 | {Context.Int8PtrTy, Context.Int32Ty, |
247 | 0 | Context.Int32Ty, Context.Int32Ty, |
248 | 0 | Context.Int32Ty}, |
249 | 0 | false)), |
250 | 0 | {Context.getModuleInst(Builder, ModCtx), |
251 | 0 | LLContext.getInt32(Instr.getTargetIndex()), |
252 | 0 | LLContext.getInt32(Instr.getSourceIndex()), Start, Length})); |
253 | 0 | break; |
254 | 0 | } |
255 | 140 | case OpCode::Array__get: |
256 | 179 | case OpCode::Array__get_u: |
257 | 260 | case OpCode::Array__get_s: { |
258 | 260 | assuming(static_cast<size_t>(Instr.getTargetIndex()) < |
259 | 260 | Context.CompositeTypes.size()); |
260 | 260 | const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()]; |
261 | 260 | assuming(CompType != nullptr && !CompType->isFunc()); |
262 | 260 | assuming(static_cast<size_t>(1) == CompType->getFieldTypes().size()); |
263 | 260 | const auto &StorageType = CompType->getFieldTypes()[0].getStorageType(); |
264 | 260 | auto Idx = stackPop(); |
265 | 260 | auto Ref = stackPop(); |
266 | 260 | auto IsSigned = (Instr.getOpCode() == OpCode::Array__get_s) |
267 | 260 | ? LLContext.getInt8(1) |
268 | 260 | : LLContext.getInt8(0); |
269 | 260 | LLVM::Value Ret = getTmpValues(1); |
270 | 260 | Builder.createCall( |
271 | 260 | Context.getIntrinsic( |
272 | 260 | Builder, Executable::Intrinsics::kArrayGet, |
273 | 260 | LLVM::Type::getFunctionType(Context.VoidTy, |
274 | 260 | {Context.Int8PtrTy, Context.Int64x2Ty, |
275 | 260 | Context.Int32Ty, Context.Int32Ty, |
276 | 260 | Context.Int8Ty, Context.Int8PtrTy}, |
277 | 260 | false)), |
278 | 260 | {Context.getModuleInst(Builder, ModCtx), Ref, |
279 | 260 | LLContext.getInt32(Instr.getTargetIndex()), Idx, IsSigned, Ret}); |
280 | | |
281 | 260 | switch (StorageType.getCode()) { |
282 | 60 | case TypeCode::I8: |
283 | 120 | case TypeCode::I16: |
284 | 143 | case TypeCode::I32: { |
285 | 143 | stackPush( |
286 | 143 | Builder.createValuePtrLoad(Context.Int32Ty, Ret, Context.Int64x2Ty)); |
287 | 143 | break; |
288 | 120 | } |
289 | 27 | case TypeCode::I64: { |
290 | 27 | stackPush( |
291 | 27 | Builder.createValuePtrLoad(Context.Int64Ty, Ret, Context.Int64x2Ty)); |
292 | 27 | break; |
293 | 120 | } |
294 | 26 | case TypeCode::F32: { |
295 | 26 | stackPush( |
296 | 26 | Builder.createValuePtrLoad(Context.FloatTy, Ret, Context.Int64x2Ty)); |
297 | 26 | break; |
298 | 120 | } |
299 | 22 | case TypeCode::F64: { |
300 | 22 | stackPush( |
301 | 22 | Builder.createValuePtrLoad(Context.DoubleTy, Ret, Context.Int64x2Ty)); |
302 | 22 | break; |
303 | 120 | } |
304 | 21 | case TypeCode::V128: |
305 | 21 | case TypeCode::Ref: |
306 | 42 | case TypeCode::RefNull: { |
307 | 42 | stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret, |
308 | 42 | Context.Int64x2Ty)); |
309 | 42 | break; |
310 | 21 | } |
311 | 0 | default: |
312 | 0 | assumingUnreachable(); |
313 | 260 | } |
314 | 260 | endTmpValues(); |
315 | 260 | break; |
316 | 260 | } |
317 | 36 | case OpCode::Array__set: { |
318 | 36 | auto Val = stackPop(); |
319 | 36 | auto Idx = stackPop(); |
320 | 36 | auto Ref = stackPop(); |
321 | 36 | LLVM::Value Arg = getTmpValues(1); |
322 | 36 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
323 | 36 | Builder.createCall( |
324 | 36 | Context.getIntrinsic( |
325 | 36 | Builder, Executable::Intrinsics::kArraySet, |
326 | 36 | LLVM::Type::getFunctionType(Context.VoidTy, |
327 | 36 | {Context.Int8PtrTy, Context.Int64x2Ty, |
328 | 36 | Context.Int32Ty, Context.Int32Ty, |
329 | 36 | Context.Int8PtrTy}, |
330 | 36 | false)), |
331 | 36 | {Context.getModuleInst(Builder, ModCtx), Ref, |
332 | 36 | LLContext.getInt32(Instr.getTargetIndex()), Idx, Arg}); |
333 | 36 | endTmpValues(); |
334 | 36 | break; |
335 | 260 | } |
336 | 64 | case OpCode::Array__len: { |
337 | 64 | auto Ref = stackPop(); |
338 | 64 | stackPush(Builder.createCall( |
339 | 64 | Context.getIntrinsic(Builder, Executable::Intrinsics::kArrayLen, |
340 | 64 | LLVM::Type::getFunctionType( |
341 | 64 | Context.Int32Ty, {Context.Int64x2Ty}, false)), |
342 | 64 | {Ref})); |
343 | 64 | break; |
344 | 260 | } |
345 | 10 | case OpCode::Array__fill: { |
346 | 10 | auto Cnt = stackPop(); |
347 | 10 | auto Val = stackPop(); |
348 | 10 | auto Off = stackPop(); |
349 | 10 | auto Ref = stackPop(); |
350 | 10 | LLVM::Value Arg = getTmpValues(1); |
351 | 10 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
352 | 10 | Builder.createCall( |
353 | 10 | Context.getIntrinsic( |
354 | 10 | Builder, Executable::Intrinsics::kArrayFill, |
355 | 10 | LLVM::Type::getFunctionType(Context.VoidTy, |
356 | 10 | {Context.Int8PtrTy, Context.Int64x2Ty, |
357 | 10 | Context.Int32Ty, Context.Int32Ty, |
358 | 10 | Context.Int32Ty, Context.Int8PtrTy}, |
359 | 10 | false)), |
360 | 10 | {Context.getModuleInst(Builder, ModCtx), Ref, |
361 | 10 | LLContext.getInt32(Instr.getTargetIndex()), Off, Cnt, Arg}); |
362 | 10 | endTmpValues(); |
363 | 10 | break; |
364 | 260 | } |
365 | 11 | case OpCode::Array__copy: { |
366 | 11 | auto Cnt = stackPop(); |
367 | 11 | auto SrcOff = stackPop(); |
368 | 11 | auto SrcRef = stackPop(); |
369 | 11 | auto DstOff = stackPop(); |
370 | 11 | auto DstRef = stackPop(); |
371 | 11 | Builder.createCall( |
372 | 11 | Context.getIntrinsic( |
373 | 11 | Builder, Executable::Intrinsics::kArrayCopy, |
374 | 11 | LLVM::Type::getFunctionType(Context.VoidTy, |
375 | 11 | {Context.Int8PtrTy, Context.Int64x2Ty, |
376 | 11 | Context.Int32Ty, Context.Int32Ty, |
377 | 11 | Context.Int64x2Ty, Context.Int32Ty, |
378 | 11 | Context.Int32Ty, Context.Int32Ty}, |
379 | 11 | false)), |
380 | 11 | {Context.getModuleInst(Builder, ModCtx), DstRef, |
381 | 11 | LLContext.getInt32(Instr.getTargetIndex()), DstOff, SrcRef, |
382 | 11 | LLContext.getInt32(Instr.getSourceIndex()), SrcOff, Cnt}); |
383 | 11 | break; |
384 | 260 | } |
385 | 0 | case OpCode::Array__init_data: |
386 | 0 | case OpCode::Array__init_elem: { |
387 | 0 | auto Cnt = stackPop(); |
388 | 0 | auto SrcOff = stackPop(); |
389 | 0 | auto DstOff = stackPop(); |
390 | 0 | auto Ref = stackPop(); |
391 | 0 | Builder.createCall( |
392 | 0 | Context.getIntrinsic( |
393 | 0 | Builder, |
394 | 0 | ((Instr.getOpCode() == OpCode::Array__init_data) |
395 | 0 | ? Executable::Intrinsics::kArrayInitData |
396 | 0 | : Executable::Intrinsics::kArrayInitElem), |
397 | 0 | LLVM::Type::getFunctionType(Context.VoidTy, |
398 | 0 | {Context.Int8PtrTy, Context.Int64x2Ty, |
399 | 0 | Context.Int32Ty, Context.Int32Ty, |
400 | 0 | Context.Int32Ty, Context.Int32Ty, |
401 | 0 | Context.Int32Ty}, |
402 | 0 | false)), |
403 | 0 | {Context.getModuleInst(Builder, ModCtx), Ref, |
404 | 0 | LLContext.getInt32(Instr.getTargetIndex()), |
405 | 0 | LLContext.getInt32(Instr.getSourceIndex()), DstOff, SrcOff, Cnt}); |
406 | 0 | break; |
407 | 0 | } |
408 | 12 | case OpCode::Ref__test: |
409 | 36 | case OpCode::Ref__test_null: { |
410 | 36 | auto Ref = stackPop(); |
411 | 36 | std::array<uint8_t, 16> Buf = {0}; |
412 | 36 | std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin()); |
413 | 36 | auto VType = Builder.createExtractElement( |
414 | 36 | Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf), |
415 | 36 | Context.Int64x2Ty), |
416 | 36 | LLContext.getInt64(0)); |
417 | 36 | stackPush(Builder.createCall( |
418 | 36 | Context.getIntrinsic( |
419 | 36 | Builder, Executable::Intrinsics::kRefTest, |
420 | 36 | LLVM::Type::getFunctionType( |
421 | 36 | Context.Int32Ty, |
422 | 36 | {Context.Int8PtrTy, Context.Int64x2Ty, Context.Int64Ty}, |
423 | 36 | false)), |
424 | 36 | {Context.getModuleInst(Builder, ModCtx), Ref, VType})); |
425 | 36 | break; |
426 | 12 | } |
427 | 39 | case OpCode::Ref__cast: |
428 | 60 | case OpCode::Ref__cast_null: { |
429 | 60 | auto Ref = stackPop(); |
430 | 60 | std::array<uint8_t, 16> Buf = {0}; |
431 | 60 | std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin()); |
432 | 60 | auto VType = Builder.createExtractElement( |
433 | 60 | Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf), |
434 | 60 | Context.Int64x2Ty), |
435 | 60 | LLContext.getInt64(0)); |
436 | 60 | stackPush(Builder.createCall( |
437 | 60 | Context.getIntrinsic( |
438 | 60 | Builder, Executable::Intrinsics::kRefCast, |
439 | 60 | LLVM::Type::getFunctionType( |
440 | 60 | Context.Int64x2Ty, |
441 | 60 | {Context.Int8PtrTy, Context.Int64x2Ty, Context.Int64Ty}, |
442 | 60 | false)), |
443 | 60 | {Context.getModuleInst(Builder, ModCtx), Ref, VType})); |
444 | 60 | break; |
445 | 39 | } |
446 | 12 | case OpCode::Any__convert_extern: { |
447 | 12 | std::array<uint8_t, 16> RawRef = {0}; |
448 | 12 | auto Ref = stackPop(); |
449 | 12 | auto PtrVal = Builder.createExtractElement(Ref, LLContext.getInt64(1)); |
450 | 12 | auto IsNullBB = |
451 | 12 | LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.null"); |
452 | 12 | auto NotNullBB = |
453 | 12 | LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.not_null"); |
454 | 12 | auto IsExtrefBB = |
455 | 12 | LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.is_extref"); |
456 | 12 | auto EndBB = |
457 | 12 | LLVM::BasicBlock::create(LLContext, F.Fn, "any_conv_extern.end"); |
458 | 12 | auto CondIsNull = Builder.createICmpEQ(PtrVal, LLContext.getInt64(0)); |
459 | 12 | Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB); |
460 | | |
461 | 12 | Builder.positionAtEnd(IsNullBB); |
462 | 12 | auto VT = ValType(TypeCode::RefNull, TypeCode::NullRef); |
463 | 12 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
464 | 12 | auto Ret1 = Builder.createBitCast( |
465 | 12 | LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty); |
466 | 12 | Builder.createBr(EndBB); |
467 | | |
468 | 12 | Builder.positionAtEnd(NotNullBB); |
469 | 12 | auto Ret2 = |
470 | 12 | Builder.createBitCast(Builder.createInsertElement( |
471 | 12 | Builder.createBitCast(Ref, Context.Int8x16Ty), |
472 | 12 | LLContext.getInt8(0), LLContext.getInt64(1)), |
473 | 12 | Context.Int64x2Ty); |
474 | 12 | auto HType = Builder.createExtractElement( |
475 | 12 | Builder.createBitCast(Ret2, Context.Int8x16Ty), LLContext.getInt64(3)); |
476 | 12 | auto CondIsExtref = Builder.createOr( |
477 | 12 | Builder.createICmpEQ(HType, LLContext.getInt8(static_cast<uint8_t>( |
478 | 12 | TypeCode::ExternRef))), |
479 | 12 | Builder.createICmpEQ(HType, LLContext.getInt8(static_cast<uint8_t>( |
480 | 12 | TypeCode::NullExternRef)))); |
481 | 12 | Builder.createCondBr(CondIsExtref, IsExtrefBB, EndBB); |
482 | | |
483 | 12 | Builder.positionAtEnd(IsExtrefBB); |
484 | 12 | VT = ValType(TypeCode::Ref, TypeCode::AnyRef); |
485 | 12 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
486 | 12 | auto Ret3 = Builder.createInsertElement( |
487 | 12 | Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, RawRef), |
488 | 12 | Context.Int64x2Ty), |
489 | 12 | PtrVal, LLContext.getInt64(1)); |
490 | 12 | Builder.createBr(EndBB); |
491 | | |
492 | 12 | Builder.positionAtEnd(EndBB); |
493 | 12 | auto Ret = Builder.createPHI(Context.Int64x2Ty); |
494 | 12 | Ret.addIncoming(Ret1, IsNullBB); |
495 | 12 | Ret.addIncoming(Ret2, NotNullBB); |
496 | 12 | Ret.addIncoming(Ret3, IsExtrefBB); |
497 | 12 | stackPush(Ret); |
498 | 12 | break; |
499 | 39 | } |
500 | 55 | case OpCode::Extern__convert_any: { |
501 | 55 | std::array<uint8_t, 16> RawRef = {0}; |
502 | 55 | auto Ref = stackPop(); |
503 | 55 | auto IsNullBB = |
504 | 55 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.null"); |
505 | 55 | auto NotNullBB = |
506 | 55 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.not_null"); |
507 | 55 | auto EndBB = |
508 | 55 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.end"); |
509 | 55 | auto CondIsNull = Builder.createICmpEQ( |
510 | 55 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
511 | 55 | LLContext.getInt64(0)); |
512 | 55 | Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB); |
513 | | |
514 | 55 | Builder.positionAtEnd(IsNullBB); |
515 | 55 | auto VT = ValType(TypeCode::RefNull, TypeCode::NullExternRef); |
516 | 55 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
517 | 55 | auto Ret1 = Builder.createBitCast( |
518 | 55 | LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty); |
519 | 55 | Builder.createBr(EndBB); |
520 | | |
521 | 55 | Builder.positionAtEnd(NotNullBB); |
522 | 55 | auto Ret2 = |
523 | 55 | Builder.createBitCast(Builder.createInsertElement( |
524 | 55 | Builder.createBitCast(Ref, Context.Int8x16Ty), |
525 | 55 | LLContext.getInt8(1), LLContext.getInt64(1)), |
526 | 55 | Context.Int64x2Ty); |
527 | 55 | Builder.createBr(EndBB); |
528 | | |
529 | 55 | Builder.positionAtEnd(EndBB); |
530 | 55 | auto Ret = Builder.createPHI(Context.Int64x2Ty); |
531 | 55 | Ret.addIncoming(Ret1, IsNullBB); |
532 | 55 | Ret.addIncoming(Ret2, NotNullBB); |
533 | 55 | stackPush(Ret); |
534 | 55 | break; |
535 | 39 | } |
536 | 94 | case OpCode::Ref__i31: { |
537 | 94 | std::array<uint8_t, 16> RawRef = {0}; |
538 | 94 | auto VT = ValType(TypeCode::Ref, TypeCode::I31Ref); |
539 | 94 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
540 | 94 | auto Ref = Builder.createBitCast( |
541 | 94 | LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty); |
542 | 94 | auto Val = Builder.createZExt( |
543 | 94 | Builder.createOr( |
544 | 94 | Builder.createAnd(stackPop(), LLContext.getInt32(0x7FFFFFFFU)), |
545 | 94 | LLContext.getInt32(0x80000000U)), |
546 | 94 | Context.Int64Ty); |
547 | 94 | stackPush(Builder.createInsertElement(Ref, Val, LLContext.getInt64(1))); |
548 | 94 | break; |
549 | 39 | } |
550 | 42 | case OpCode::I31__get_s: { |
551 | 42 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok"); |
552 | 42 | auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty); |
553 | 42 | auto Val = Builder.createTrunc( |
554 | 42 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
555 | 42 | Context.Int32Ty); |
556 | 42 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
557 | 42 | Builder.createAnd(Val, LLContext.getInt32(0x80000000U)), |
558 | 42 | LLContext.getInt32(0))); |
559 | 42 | Builder.createCondBr(IsNotNull, Next, |
560 | 42 | getTrapBB(ErrCode::Value::AccessNullI31)); |
561 | 42 | Builder.positionAtEnd(Next); |
562 | 42 | Val = Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU)); |
563 | 42 | stackPush(Builder.createOr( |
564 | 42 | Val, Builder.createShl( |
565 | 42 | Builder.createAnd(Val, LLContext.getInt32(0x40000000U)), |
566 | 42 | LLContext.getInt32(1)))); |
567 | 42 | break; |
568 | 39 | } |
569 | 36 | case OpCode::I31__get_u: { |
570 | 36 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok"); |
571 | 36 | auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty); |
572 | 36 | auto Val = Builder.createTrunc( |
573 | 36 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
574 | 36 | Context.Int32Ty); |
575 | 36 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
576 | 36 | Builder.createAnd(Val, LLContext.getInt32(0x80000000U)), |
577 | 36 | LLContext.getInt32(0))); |
578 | 36 | Builder.createCondBr(IsNotNull, Next, |
579 | 36 | getTrapBB(ErrCode::Value::AccessNullI31)); |
580 | 36 | Builder.positionAtEnd(Next); |
581 | 36 | stackPush(Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU))); |
582 | 36 | break; |
583 | 39 | } |
584 | | |
585 | | // Parametric Instructions |
586 | 3.45k | case OpCode::Drop: |
587 | 3.45k | stackPop(); |
588 | 3.45k | break; |
589 | 687 | case OpCode::Select: |
590 | 1.10k | case OpCode::Select_t: { |
591 | 1.10k | auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0)); |
592 | 1.10k | auto False = stackPop(); |
593 | 1.10k | auto True = stackPop(); |
594 | 1.10k | stackPush(Builder.createSelect(Cond, True, False)); |
595 | 1.10k | break; |
596 | 687 | } |
597 | | |
598 | | // Variable Instructions |
599 | 0 | default: |
600 | 0 | assumingUnreachable(); |
601 | 14.5k | } |
602 | 14.5k | return {}; |
603 | 14.5k | } |
604 | | |
605 | | } // namespace WasmEdge |