Coverage Report

Created: 2026-08-14 06:41

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