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