Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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