Coverage Report

Created: 2026-08-08 06:32

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
16.8k
FunctionCompiler::compileRefOp(const AST::Instruction &Instr) noexcept {
13
16.8k
  switch (Instr.getOpCode()) {
14
7.49k
  case OpCode::Ref__null: {
15
7.49k
    std::array<uint8_t, 16> Buf = {0};
16
    // For null references, dynamic type downscaling is needed.
17
7.49k
    ValType VType;
18
7.49k
    if (Instr.getValType().isAbsHeapType()) {
19
7.11k
      switch (Instr.getValType().getHeapTypeCode()) {
20
26
      case TypeCode::NullFuncRef:
21
2.76k
      case TypeCode::FuncRef:
22
2.76k
        VType = TypeCode::NullFuncRef;
23
2.76k
        break;
24
70
      case TypeCode::NullExternRef:
25
3.05k
      case TypeCode::ExternRef:
26
3.05k
        VType = TypeCode::NullExternRef;
27
3.05k
        break;
28
36
      case TypeCode::NullExnRef:
29
101
      case TypeCode::ExnRef:
30
101
        VType = TypeCode::NullExnRef;
31
101
        break;
32
425
      case TypeCode::NullRef:
33
471
      case TypeCode::AnyRef:
34
1.09k
      case TypeCode::EqRef:
35
1.15k
      case TypeCode::I31Ref:
36
1.17k
      case TypeCode::StructRef:
37
1.19k
      case TypeCode::ArrayRef:
38
1.19k
        VType = TypeCode::NullRef;
39
1.19k
        break;
40
0
      default:
41
0
        assumingUnreachable();
42
7.11k
      }
43
7.11k
    } else {
44
380
      assuming(Instr.getValType().getTypeIndex() <
45
380
               Context.CompositeTypes.size());
46
380
      const auto *CompType =
47
380
          Context.CompositeTypes[Instr.getValType().getTypeIndex()];
48
380
      assuming(CompType != nullptr);
49
380
      if (CompType->isFunc()) {
50
362
        VType = TypeCode::NullFuncRef;
51
362
      } else {
52
18
        VType = TypeCode::NullRef;
53
18
      }
54
380
    }
55
7.49k
    std::copy_n(VType.getRawData().cbegin(), 8, Buf.begin());
56
7.49k
    stackPush(Builder.createBitCast(
57
7.49k
        LLVM::Value::getConstVector8(LLContext, Buf), Context.Int64x2Ty));
58
7.49k
    break;
59
7.49k
  }
60
3.24k
  case OpCode::Ref__is_null:
61
3.24k
    stackPush(Builder.createZExt(
62
3.24k
        Builder.createICmpEQ(
63
3.24k
            Builder.createExtractElement(
64
3.24k
                Builder.createBitCast(stackPop(), Context.Int64x2Ty),
65
3.24k
                LLContext.getInt64(1)),
66
3.24k
            LLContext.getInt64(0)),
67
3.24k
        Context.Int32Ty));
68
3.24k
    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
14
  case OpCode::Ref__eq: {
77
14
    LLVM::Value RHS = stackPop();
78
14
    LLVM::Value LHS = stackPop();
79
14
    stackPush(Builder.createZExt(
80
14
        Builder.createICmpEQ(
81
14
            Builder.createExtractElement(LHS, LLContext.getInt64(1)),
82
14
            Builder.createExtractElement(RHS, LLContext.getInt64(1))),
83
14
        Context.Int32Ty));
84
14
    break;
85
7.49k
  }
86
393
  case OpCode::Ref__as_non_null: {
87
393
    auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "ref_as_non_null.ok");
88
393
    Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
89
393
    auto IsNotNull = Builder.createLikely(Builder.createICmpNE(
90
393
        Builder.createExtractElement(Stack.back(), LLContext.getInt64(1)),
91
393
        LLContext.getInt64(0)));
92
393
    Builder.createCondBr(IsNotNull, Next,
93
393
                         getTrapBB(ErrCode::Value::CastNullToNonNull));
94
393
    Builder.positionAtEnd(Next);
95
393
    break;
96
7.49k
  }
97
98
  // Reference Instructions (GC proposal)
99
44
  case OpCode::Struct__new:
100
110
  case OpCode::Struct__new_default: {
101
110
    LLVM::Value Args = LLVM::Value::getConstPointerNull(Context.Int8PtrTy);
102
110
    assuming(Instr.getTargetIndex() < Context.CompositeTypes.size());
103
110
    const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
104
110
    assuming(CompType != nullptr && !CompType->isFunc());
105
110
    auto ArgSize = CompType->getFieldTypes().size();
106
110
    if (Instr.getOpCode() == OpCode::Struct__new) {
107
44
      std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
108
45
      for (size_t I = 0; I < ArgSize; ++I) {
109
1
        ArgsVec[ArgSize - I - 1] = stackPop();
110
1
      }
111
44
      Args = Builder.createArray(ArgSize, LLVM::kValSize);
112
44
      Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty,
113
44
                                  LLVM::kValSize);
114
66
    } else {
115
66
      ArgSize = 0;
116
66
    }
117
110
    stackPush(Builder.createCall(
118
110
        Context.getIntrinsic(
119
110
            Builder, Executable::Intrinsics::kStructNew,
120
110
            LLVM::Type::getFunctionType(
121
110
                Context.Int64x2Ty,
122
110
                {Context.Int32Ty, Context.Int8PtrTy, Context.Int32Ty}, false)),
123
110
        {LLContext.getInt32(Instr.getTargetIndex()), Args,
124
110
         LLContext.getInt32(static_cast<uint32_t>(ArgSize))}));
125
110
    break;
126
110
  }
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
79
  case OpCode::Array__new_fixed: {
236
79
    const auto ArgSize = Instr.getSourceIndex();
237
79
    std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
238
209
    for (size_t I = 0; I < ArgSize; ++I) {
239
130
      ArgsVec[ArgSize - I - 1] = stackPop();
240
130
    }
241
79
    LLVM::Value Args = Builder.createArray(ArgSize, LLVM::kValSize);
242
79
    Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, LLVM::kValSize);
243
79
    stackPush(Builder.createCall(
244
79
        Context.getIntrinsic(
245
79
            Builder, Executable::Intrinsics::kArrayNew,
246
79
            LLVM::Type::getFunctionType(Context.Int64x2Ty,
247
79
                                        {Context.Int32Ty, Context.Int32Ty,
248
79
                                         Context.Int8PtrTy, Context.Int32Ty},
249
79
                                        false)),
250
79
        {LLContext.getInt32(Instr.getTargetIndex()),
251
79
         LLContext.getInt32(ArgSize), Args, LLContext.getInt32(ArgSize)}));
252
79
    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
132
  case OpCode::Array__get:
273
166
  case OpCode::Array__get_u:
274
219
  case OpCode::Array__get_s: {
275
219
    assuming(static_cast<size_t>(Instr.getTargetIndex()) <
276
219
             Context.CompositeTypes.size());
277
219
    const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
278
219
    assuming(CompType != nullptr && !CompType->isFunc());
279
219
    assuming(static_cast<size_t>(1) == CompType->getFieldTypes().size());
280
219
    const auto &StorageType = CompType->getFieldTypes()[0].getStorageType();
281
219
    auto Idx = stackPop();
282
219
    auto Ref = stackPop();
283
219
    auto IsSigned = (Instr.getOpCode() == OpCode::Array__get_s)
284
219
                        ? LLContext.getInt8(1)
285
219
                        : LLContext.getInt8(0);
286
219
    LLVM::Value Ret = Builder.createAlloca(Context.Int64x2Ty);
287
219
    Builder.createCall(
288
219
        Context.getIntrinsic(
289
219
            Builder, Executable::Intrinsics::kArrayGet,
290
219
            LLVM::Type::getFunctionType(Context.VoidTy,
291
219
                                        {Context.Int64x2Ty, Context.Int32Ty,
292
219
                                         Context.Int32Ty, Context.Int8Ty,
293
219
                                         Context.Int8PtrTy},
294
219
                                        false)),
295
219
        {Ref, LLContext.getInt32(Instr.getTargetIndex()), Idx, IsSigned, Ret});
296
297
219
    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
24
    case TypeCode::I64: {
306
24
      stackPush(
307
24
          Builder.createValuePtrLoad(Context.Int64Ty, Ret, Context.Int64x2Ty));
308
24
      break;
309
87
    }
310
20
    case TypeCode::F32: {
311
20
      stackPush(
312
20
          Builder.createValuePtrLoad(Context.FloatTy, Ret, Context.Int64x2Ty));
313
20
      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
42
    case TypeCode::RefNull: {
323
42
      stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret,
324
42
                                           Context.Int64x2Ty));
325
42
      break;
326
18
    }
327
0
    default:
328
0
      assumingUnreachable();
329
219
    }
330
219
    break;
331
219
  }
332
219
  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
219
  }
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
219
  }
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
219
  }
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
219
  }
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
14
  case OpCode::Ref__test:
416
43
  case OpCode::Ref__test_null: {
417
43
    auto Ref = stackPop();
418
43
    std::array<uint8_t, 16> Buf = {0};
419
43
    std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
420
43
    auto VType = Builder.createExtractElement(
421
43
        Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
422
43
                              Context.Int64x2Ty),
423
43
        LLContext.getInt64(0));
424
43
    stackPush(Builder.createCall(
425
43
        Context.getIntrinsic(
426
43
            Builder, Executable::Intrinsics::kRefTest,
427
43
            LLVM::Type::getFunctionType(
428
43
                Context.Int32Ty, {Context.Int64x2Ty, Context.Int64Ty}, false)),
429
43
        {Ref, VType}));
430
43
    break;
431
14
  }
432
48
  case OpCode::Ref__cast:
433
78
  case OpCode::Ref__cast_null: {
434
78
    auto Ref = stackPop();
435
78
    std::array<uint8_t, 16> Buf = {0};
436
78
    std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
437
78
    auto VType = Builder.createExtractElement(
438
78
        Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
439
78
                              Context.Int64x2Ty),
440
78
        LLContext.getInt64(0));
441
78
    stackPush(Builder.createCall(
442
78
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefCast,
443
78
                             LLVM::Type::getFunctionType(
444
78
                                 Context.Int64x2Ty,
445
78
                                 {Context.Int64x2Ty, Context.Int64Ty}, false)),
446
78
        {Ref, VType}));
447
78
    break;
448
48
  }
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
48
  }
503
62
  case OpCode::Extern__convert_any: {
504
62
    std::array<uint8_t, 16> RawRef = {0};
505
62
    auto Ref = stackPop();
506
62
    auto IsNullBB =
507
62
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.null");
508
62
    auto NotNullBB =
509
62
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.not_null");
510
62
    auto EndBB =
511
62
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.end");
512
62
    auto CondIsNull = Builder.createICmpEQ(
513
62
        Builder.createExtractElement(Ref, LLContext.getInt64(1)),
514
62
        LLContext.getInt64(0));
515
62
    Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB);
516
517
62
    Builder.positionAtEnd(IsNullBB);
518
62
    auto VT = ValType(TypeCode::RefNull, TypeCode::NullExternRef);
519
62
    std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
520
62
    auto Ret1 = Builder.createBitCast(
521
62
        LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
522
62
    Builder.createBr(EndBB);
523
524
62
    Builder.positionAtEnd(NotNullBB);
525
62
    auto Ret2 =
526
62
        Builder.createBitCast(Builder.createInsertElement(
527
62
                                  Builder.createBitCast(Ref, Context.Int8x16Ty),
528
62
                                  LLContext.getInt8(1), LLContext.getInt64(1)),
529
62
                              Context.Int64x2Ty);
530
62
    Builder.createBr(EndBB);
531
532
62
    Builder.positionAtEnd(EndBB);
533
62
    auto Ret = Builder.createPHI(Context.Int64x2Ty);
534
62
    Ret.addIncoming(Ret1, IsNullBB);
535
62
    Ret.addIncoming(Ret2, NotNullBB);
536
62
    stackPush(Ret);
537
62
    break;
538
48
  }
539
126
  case OpCode::Ref__i31: {
540
126
    std::array<uint8_t, 16> RawRef = {0};
541
126
    auto VT = ValType(TypeCode::Ref, TypeCode::I31Ref);
542
126
    std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
543
126
    auto Ref = Builder.createBitCast(
544
126
        LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
545
126
    auto Val = Builder.createZExt(
546
126
        Builder.createOr(
547
126
            Builder.createAnd(stackPop(), LLContext.getInt32(0x7FFFFFFFU)),
548
126
            LLContext.getInt32(0x80000000U)),
549
126
        Context.Int64Ty);
550
126
    stackPush(Builder.createInsertElement(Ref, Val, LLContext.getInt64(1)));
551
126
    break;
552
48
  }
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
48
  }
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
48
  }
587
588
  // Parametric Instructions
589
3.51k
  case OpCode::Drop:
590
3.51k
    stackPop();
591
3.51k
    break;
592
670
  case OpCode::Select:
593
1.08k
  case OpCode::Select_t: {
594
1.08k
    auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
595
1.08k
    auto False = stackPop();
596
1.08k
    auto True = stackPop();
597
1.08k
    stackPush(Builder.createSelect(Cond, True, False));
598
1.08k
    break;
599
670
  }
600
601
    // Variable Instructions
602
0
  default:
603
0
    assumingUnreachable();
604
16.8k
  }
605
16.8k
  return {};
606
16.8k
}
607
608
} // namespace WasmEdge