Coverage Report

Created: 2026-07-16 07:09

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