Coverage Report

Created: 2026-11-09 06:49

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