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