/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 | 13.7k | FunctionCompiler::compileRefOp(const AST::Instruction &Instr) noexcept { |
13 | 13.7k | switch (Instr.getOpCode()) { |
14 | 5.55k | case OpCode::Ref__null: { |
15 | 5.55k | std::array<uint8_t, 16> Buf = {0}; |
16 | | // For null references, dynamic type downscaling is needed. |
17 | 5.55k | ValType VType; |
18 | 5.55k | if (Instr.getValType().isAbsHeapType()) { |
19 | 5.27k | switch (Instr.getValType().getHeapTypeCode()) { |
20 | 11 | case TypeCode::NullFuncRef: |
21 | 2.01k | case TypeCode::FuncRef: |
22 | 2.01k | VType = TypeCode::NullFuncRef; |
23 | 2.01k | break; |
24 | 51 | case TypeCode::NullExternRef: |
25 | 2.26k | case TypeCode::ExternRef: |
26 | 2.26k | VType = TypeCode::NullExternRef; |
27 | 2.26k | break; |
28 | 32 | case TypeCode::NullExnRef: |
29 | 97 | case TypeCode::ExnRef: |
30 | 97 | VType = TypeCode::NullExnRef; |
31 | 97 | break; |
32 | 379 | case TypeCode::NullRef: |
33 | 418 | case TypeCode::AnyRef: |
34 | 832 | case TypeCode::EqRef: |
35 | 877 | case TypeCode::I31Ref: |
36 | 901 | case TypeCode::StructRef: |
37 | 906 | case TypeCode::ArrayRef: |
38 | 906 | VType = TypeCode::NullRef; |
39 | 906 | break; |
40 | 0 | default: |
41 | 0 | assumingUnreachable(); |
42 | 5.27k | } |
43 | 5.27k | } else { |
44 | 274 | assuming(Instr.getValType().getTypeIndex() < |
45 | 274 | Context.CompositeTypes.size()); |
46 | 274 | const auto *CompType = |
47 | 274 | Context.CompositeTypes[Instr.getValType().getTypeIndex()]; |
48 | 274 | assuming(CompType != nullptr); |
49 | 274 | if (CompType->isFunc()) { |
50 | 259 | VType = TypeCode::NullFuncRef; |
51 | 259 | } else { |
52 | 15 | VType = TypeCode::NullRef; |
53 | 15 | } |
54 | 274 | } |
55 | 5.55k | std::copy_n(VType.getRawData().cbegin(), 8, Buf.begin()); |
56 | 5.55k | stackPush(Builder.createBitCast( |
57 | 5.55k | LLVM::Value::getConstVector8(LLContext, Buf), Context.Int64x2Ty)); |
58 | 5.55k | break; |
59 | 5.55k | } |
60 | 2.36k | case OpCode::Ref__is_null: |
61 | 2.36k | stackPush(Builder.createZExt( |
62 | 2.36k | Builder.createICmpEQ( |
63 | 2.36k | Builder.createExtractElement( |
64 | 2.36k | Builder.createBitCast(stackPop(), Context.Int64x2Ty), |
65 | 2.36k | LLContext.getInt64(1)), |
66 | 2.36k | LLContext.getInt64(0)), |
67 | 2.36k | Context.Int32Ty)); |
68 | 2.36k | break; |
69 | 29 | case OpCode::Ref__func: |
70 | 29 | stackPush(Builder.createCall( |
71 | 29 | Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc, |
72 | 29 | LLVM::Type::getFunctionType( |
73 | 29 | Context.Int64x2Ty, {Context.Int32Ty}, false)), |
74 | 29 | {LLContext.getInt32(Instr.getTargetIndex())})); |
75 | 29 | break; |
76 | 12 | case OpCode::Ref__eq: { |
77 | 12 | LLVM::Value RHS = stackPop(); |
78 | 12 | LLVM::Value LHS = stackPop(); |
79 | 12 | stackPush(Builder.createZExt( |
80 | 12 | Builder.createICmpEQ( |
81 | 12 | Builder.createExtractElement(LHS, LLContext.getInt64(1)), |
82 | 12 | Builder.createExtractElement(RHS, LLContext.getInt64(1))), |
83 | 12 | Context.Int32Ty)); |
84 | 12 | break; |
85 | 5.55k | } |
86 | 372 | case OpCode::Ref__as_non_null: { |
87 | 372 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "ref_as_non_null.ok"); |
88 | 372 | Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty); |
89 | 372 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
90 | 372 | Builder.createExtractElement(Stack.back(), LLContext.getInt64(1)), |
91 | 372 | LLContext.getInt64(0))); |
92 | 372 | Builder.createCondBr(IsNotNull, Next, |
93 | 372 | getTrapBB(ErrCode::Value::CastNullToNonNull)); |
94 | 372 | Builder.positionAtEnd(Next); |
95 | 372 | break; |
96 | 5.55k | } |
97 | | |
98 | | // Reference Instructions (GC proposal) |
99 | 31 | case OpCode::Struct__new: |
100 | 70 | case OpCode::Struct__new_default: { |
101 | 70 | LLVM::Value Args = LLVM::Value::getConstPointerNull(Context.Int8PtrTy); |
102 | 70 | assuming(Instr.getTargetIndex() < Context.CompositeTypes.size()); |
103 | 70 | const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()]; |
104 | 70 | assuming(CompType != nullptr && !CompType->isFunc()); |
105 | 70 | auto ArgSize = CompType->getFieldTypes().size(); |
106 | 70 | if (Instr.getOpCode() == OpCode::Struct__new) { |
107 | 31 | std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr); |
108 | 32 | for (size_t I = 0; I < ArgSize; ++I) { |
109 | 1 | ArgsVec[ArgSize - I - 1] = stackPop(); |
110 | 1 | } |
111 | 31 | Args = Builder.createArray(ArgSize, LLVM::kValSize); |
112 | 31 | Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, |
113 | 31 | LLVM::kValSize); |
114 | 39 | } else { |
115 | 39 | ArgSize = 0; |
116 | 39 | } |
117 | 70 | stackPush(Builder.createCall( |
118 | 70 | Context.getIntrinsic( |
119 | 70 | Builder, Executable::Intrinsics::kStructNew, |
120 | 70 | LLVM::Type::getFunctionType( |
121 | 70 | Context.Int64x2Ty, |
122 | 70 | {Context.Int32Ty, Context.Int8PtrTy, Context.Int32Ty}, false)), |
123 | 70 | {LLContext.getInt32(Instr.getTargetIndex()), Args, |
124 | 70 | LLContext.getInt32(static_cast<uint32_t>(ArgSize))})); |
125 | 70 | break; |
126 | 70 | } |
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 | 154 | case OpCode::Array__new: { |
206 | 154 | auto Length = stackPop(); |
207 | 154 | auto Val = stackPop(); |
208 | 154 | LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty); |
209 | 154 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
210 | 154 | stackPush(Builder.createCall( |
211 | 154 | Context.getIntrinsic( |
212 | 154 | Builder, Executable::Intrinsics::kArrayNew, |
213 | 154 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
214 | 154 | {Context.Int32Ty, Context.Int32Ty, |
215 | 154 | Context.Int8PtrTy, Context.Int32Ty}, |
216 | 154 | false)), |
217 | 154 | {LLContext.getInt32(Instr.getTargetIndex()), Length, Arg, |
218 | 154 | LLContext.getInt32(1)})); |
219 | 154 | break; |
220 | 0 | } |
221 | 15 | case OpCode::Array__new_default: { |
222 | 15 | auto Length = stackPop(); |
223 | 15 | LLVM::Value Arg = LLVM::Value::getConstPointerNull(Context.Int8PtrTy); |
224 | 15 | stackPush(Builder.createCall( |
225 | 15 | Context.getIntrinsic( |
226 | 15 | Builder, Executable::Intrinsics::kArrayNew, |
227 | 15 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
228 | 15 | {Context.Int32Ty, Context.Int32Ty, |
229 | 15 | Context.Int8PtrTy, Context.Int32Ty}, |
230 | 15 | false)), |
231 | 15 | {LLContext.getInt32(Instr.getTargetIndex()), Length, Arg, |
232 | 15 | LLContext.getInt32(0)})); |
233 | 15 | break; |
234 | 0 | } |
235 | 38 | case OpCode::Array__new_fixed: { |
236 | 38 | const auto ArgSize = Instr.getSourceIndex(); |
237 | 38 | std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr); |
238 | 202 | for (size_t I = 0; I < ArgSize; ++I) { |
239 | 164 | ArgsVec[ArgSize - I - 1] = stackPop(); |
240 | 164 | } |
241 | 38 | LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize); |
242 | 38 | Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, LLVM::kValSize); |
243 | 38 | stackPush(Builder.createCall( |
244 | 38 | Context.getIntrinsic( |
245 | 38 | Builder, Executable::Intrinsics::kArrayNew, |
246 | 38 | LLVM::Type::getFunctionType(Context.Int64x2Ty, |
247 | 38 | {Context.Int32Ty, Context.Int32Ty, |
248 | 38 | Context.Int8PtrTy, Context.Int32Ty}, |
249 | 38 | false)), |
250 | 38 | {LLContext.getInt32(Instr.getTargetIndex()), |
251 | 38 | LLContext.getInt32(ArgSize), Args, LLContext.getInt32(ArgSize)})); |
252 | 38 | 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 | 118 | case OpCode::Array__get: |
273 | 152 | case OpCode::Array__get_u: |
274 | 205 | case OpCode::Array__get_s: { |
275 | 205 | assuming(static_cast<size_t>(Instr.getTargetIndex()) < |
276 | 205 | Context.CompositeTypes.size()); |
277 | 205 | const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()]; |
278 | 205 | assuming(CompType != nullptr && !CompType->isFunc()); |
279 | 205 | assuming(static_cast<size_t>(1) == CompType->getFieldTypes().size()); |
280 | 205 | const auto &StorageType = CompType->getFieldTypes()[0].getStorageType(); |
281 | 205 | auto Idx = stackPop(); |
282 | 205 | auto Ref = stackPop(); |
283 | 205 | auto IsSigned = (Instr.getOpCode() == OpCode::Array__get_s) |
284 | 205 | ? LLContext.getInt8(1) |
285 | 205 | : LLContext.getInt8(0); |
286 | 205 | LLVM::Value Ret = Builder.createAlloca(Context.Int64x2Ty); |
287 | 205 | Builder.createCall( |
288 | 205 | Context.getIntrinsic( |
289 | 205 | Builder, Executable::Intrinsics::kArrayGet, |
290 | 205 | LLVM::Type::getFunctionType(Context.VoidTy, |
291 | 205 | {Context.Int64x2Ty, Context.Int32Ty, |
292 | 205 | Context.Int32Ty, Context.Int8Ty, |
293 | 205 | Context.Int8PtrTy}, |
294 | 205 | false)), |
295 | 205 | {Ref, LLContext.getInt32(Instr.getTargetIndex()), Idx, IsSigned, Ret}); |
296 | | |
297 | 205 | 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 | 14 | case TypeCode::I64: { |
306 | 14 | stackPush( |
307 | 14 | Builder.createValuePtrLoad(Context.Int64Ty, Ret, Context.Int64x2Ty)); |
308 | 14 | break; |
309 | 87 | } |
310 | 17 | case TypeCode::F32: { |
311 | 17 | stackPush( |
312 | 17 | Builder.createValuePtrLoad(Context.FloatTy, Ret, Context.Int64x2Ty)); |
313 | 17 | 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 | 41 | case TypeCode::RefNull: { |
323 | 41 | stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret, |
324 | 41 | Context.Int64x2Ty)); |
325 | 41 | break; |
326 | 18 | } |
327 | 0 | default: |
328 | 0 | assumingUnreachable(); |
329 | 205 | } |
330 | 205 | break; |
331 | 205 | } |
332 | 205 | case OpCode::Array__set: { |
333 | 41 | auto Val = stackPop(); |
334 | 41 | auto Idx = stackPop(); |
335 | 41 | auto Ref = stackPop(); |
336 | 41 | LLVM::Value Arg = Builder.createAlloca(Context.Int64x2Ty); |
337 | 41 | Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty); |
338 | 41 | Builder.createCall( |
339 | 41 | Context.getIntrinsic( |
340 | 41 | Builder, Executable::Intrinsics::kArraySet, |
341 | 41 | LLVM::Type::getFunctionType(Context.VoidTy, |
342 | 41 | {Context.Int64x2Ty, Context.Int32Ty, |
343 | 41 | Context.Int32Ty, Context.Int8PtrTy}, |
344 | 41 | false)), |
345 | 41 | {Ref, LLContext.getInt32(Instr.getTargetIndex()), Idx, Arg}); |
346 | 41 | break; |
347 | 205 | } |
348 | 64 | case OpCode::Array__len: { |
349 | 64 | auto Ref = stackPop(); |
350 | 64 | stackPush(Builder.createCall( |
351 | 64 | Context.getIntrinsic(Builder, Executable::Intrinsics::kArrayLen, |
352 | 64 | LLVM::Type::getFunctionType( |
353 | 64 | Context.Int32Ty, {Context.Int64x2Ty}, false)), |
354 | 64 | {Ref})); |
355 | 64 | break; |
356 | 205 | } |
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 | 205 | } |
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 | 205 | } |
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 | 11 | case OpCode::Ref__test: |
416 | 39 | case OpCode::Ref__test_null: { |
417 | 39 | auto Ref = stackPop(); |
418 | 39 | std::array<uint8_t, 16> Buf = {0}; |
419 | 39 | std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin()); |
420 | 39 | auto VType = Builder.createExtractElement( |
421 | 39 | Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf), |
422 | 39 | Context.Int64x2Ty), |
423 | 39 | LLContext.getInt64(0)); |
424 | 39 | stackPush(Builder.createCall( |
425 | 39 | Context.getIntrinsic( |
426 | 39 | Builder, Executable::Intrinsics::kRefTest, |
427 | 39 | LLVM::Type::getFunctionType( |
428 | 39 | Context.Int32Ty, {Context.Int64x2Ty, Context.Int64Ty}, false)), |
429 | 39 | {Ref, VType})); |
430 | 39 | break; |
431 | 11 | } |
432 | 17 | case OpCode::Ref__cast: |
433 | 26 | case OpCode::Ref__cast_null: { |
434 | 26 | auto Ref = stackPop(); |
435 | 26 | std::array<uint8_t, 16> Buf = {0}; |
436 | 26 | std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin()); |
437 | 26 | auto VType = Builder.createExtractElement( |
438 | 26 | Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf), |
439 | 26 | Context.Int64x2Ty), |
440 | 26 | LLContext.getInt64(0)); |
441 | 26 | stackPush(Builder.createCall( |
442 | 26 | Context.getIntrinsic(Builder, Executable::Intrinsics::kRefCast, |
443 | 26 | LLVM::Type::getFunctionType( |
444 | 26 | Context.Int64x2Ty, |
445 | 26 | {Context.Int64x2Ty, Context.Int64Ty}, false)), |
446 | 26 | {Ref, VType})); |
447 | 26 | break; |
448 | 17 | } |
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 | 17 | } |
503 | 33 | case OpCode::Extern__convert_any: { |
504 | 33 | std::array<uint8_t, 16> RawRef = {0}; |
505 | 33 | auto Ref = stackPop(); |
506 | 33 | auto IsNullBB = |
507 | 33 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.null"); |
508 | 33 | auto NotNullBB = |
509 | 33 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.not_null"); |
510 | 33 | auto EndBB = |
511 | 33 | LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.end"); |
512 | 33 | auto CondIsNull = Builder.createICmpEQ( |
513 | 33 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
514 | 33 | LLContext.getInt64(0)); |
515 | 33 | Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB); |
516 | | |
517 | 33 | Builder.positionAtEnd(IsNullBB); |
518 | 33 | auto VT = ValType(TypeCode::RefNull, TypeCode::NullExternRef); |
519 | 33 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
520 | 33 | auto Ret1 = Builder.createBitCast( |
521 | 33 | LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty); |
522 | 33 | Builder.createBr(EndBB); |
523 | | |
524 | 33 | Builder.positionAtEnd(NotNullBB); |
525 | 33 | auto Ret2 = |
526 | 33 | Builder.createBitCast(Builder.createInsertElement( |
527 | 33 | Builder.createBitCast(Ref, Context.Int8x16Ty), |
528 | 33 | LLContext.getInt8(1), LLContext.getInt64(1)), |
529 | 33 | Context.Int64x2Ty); |
530 | 33 | Builder.createBr(EndBB); |
531 | | |
532 | 33 | Builder.positionAtEnd(EndBB); |
533 | 33 | auto Ret = Builder.createPHI(Context.Int64x2Ty); |
534 | 33 | Ret.addIncoming(Ret1, IsNullBB); |
535 | 33 | Ret.addIncoming(Ret2, NotNullBB); |
536 | 33 | stackPush(Ret); |
537 | 33 | break; |
538 | 17 | } |
539 | 91 | case OpCode::Ref__i31: { |
540 | 91 | std::array<uint8_t, 16> RawRef = {0}; |
541 | 91 | auto VT = ValType(TypeCode::Ref, TypeCode::I31Ref); |
542 | 91 | std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin()); |
543 | 91 | auto Ref = Builder.createBitCast( |
544 | 91 | LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty); |
545 | 91 | auto Val = Builder.createZExt( |
546 | 91 | Builder.createOr( |
547 | 91 | Builder.createAnd(stackPop(), LLContext.getInt32(0x7FFFFFFFU)), |
548 | 91 | LLContext.getInt32(0x80000000U)), |
549 | 91 | Context.Int64Ty); |
550 | 91 | stackPush(Builder.createInsertElement(Ref, Val, LLContext.getInt64(1))); |
551 | 91 | break; |
552 | 17 | } |
553 | 40 | case OpCode::I31__get_s: { |
554 | 40 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok"); |
555 | 40 | auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty); |
556 | 40 | auto Val = Builder.createTrunc( |
557 | 40 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
558 | 40 | Context.Int32Ty); |
559 | 40 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
560 | 40 | Builder.createAnd(Val, LLContext.getInt32(0x80000000U)), |
561 | 40 | LLContext.getInt32(0))); |
562 | 40 | Builder.createCondBr(IsNotNull, Next, |
563 | 40 | getTrapBB(ErrCode::Value::AccessNullI31)); |
564 | 40 | Builder.positionAtEnd(Next); |
565 | 40 | Val = Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU)); |
566 | 40 | stackPush(Builder.createOr( |
567 | 40 | Val, Builder.createShl( |
568 | 40 | Builder.createAnd(Val, LLContext.getInt32(0x40000000U)), |
569 | 40 | LLContext.getInt32(1)))); |
570 | 40 | break; |
571 | 17 | } |
572 | 23 | case OpCode::I31__get_u: { |
573 | 23 | auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "i31.get.ok"); |
574 | 23 | auto Ref = Builder.createBitCast(stackPop(), Context.Int64x2Ty); |
575 | 23 | auto Val = Builder.createTrunc( |
576 | 23 | Builder.createExtractElement(Ref, LLContext.getInt64(1)), |
577 | 23 | Context.Int32Ty); |
578 | 23 | auto IsNotNull = Builder.createLikely(Builder.createICmpNE( |
579 | 23 | Builder.createAnd(Val, LLContext.getInt32(0x80000000U)), |
580 | 23 | LLContext.getInt32(0))); |
581 | 23 | Builder.createCondBr(IsNotNull, Next, |
582 | 23 | getTrapBB(ErrCode::Value::AccessNullI31)); |
583 | 23 | Builder.positionAtEnd(Next); |
584 | 23 | stackPush(Builder.createAnd(Val, LLContext.getInt32(0x7FFFFFFFU))); |
585 | 23 | break; |
586 | 17 | } |
587 | | |
588 | | // Parametric Instructions |
589 | 3.42k | case OpCode::Drop: |
590 | 3.42k | stackPop(); |
591 | 3.42k | break; |
592 | 684 | case OpCode::Select: |
593 | 1.11k | case OpCode::Select_t: { |
594 | 1.11k | auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0)); |
595 | 1.11k | auto False = stackPop(); |
596 | 1.11k | auto True = stackPop(); |
597 | 1.11k | stackPush(Builder.createSelect(Cond, True, False)); |
598 | 1.11k | break; |
599 | 684 | } |
600 | | |
601 | | // Variable Instructions |
602 | 0 | default: |
603 | 0 | assumingUnreachable(); |
604 | 13.7k | } |
605 | 13.7k | return {}; |
606 | 13.7k | } |
607 | | |
608 | | } // namespace WasmEdge |