Coverage Report

Created: 2026-11-12 06:35

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.5k
FunctionCompiler::compileRefOp(const AST::Instruction &Instr) noexcept {
13
14.5k
  switch (Instr.getOpCode()) {
14
5.90k
  case OpCode::Ref__null: {
15
    // For null references, dynamic type downscaling is needed.
16
5.90k
    auto NullVal = toLLVMConstantZero(LLContext, Instr.getValType(),
17
5.90k
                                      Context.CompositeTypes);
18
5.90k
    stackPush(Builder.createBitCast(NullVal, Context.Int64x2Ty));
19
5.90k
    break;
20
0
  }
21
2.47k
  case OpCode::Ref__is_null:
22
2.47k
    stackPush(Builder.createZExt(
23
2.47k
        Builder.createICmpEQ(
24
2.47k
            Builder.createExtractElement(
25
2.47k
                Builder.createBitCast(stackPop(), Context.Int64x2Ty),
26
2.47k
                LLContext.getInt64(1)),
27
2.47k
            LLContext.getInt64(0)),
28
2.47k
        Context.Int32Ty));
29
2.47k
    break;
30
115
  case OpCode::Ref__func:
31
115
    stackPush(Builder.createCall(
32
115
        Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc,
33
115
                             LLVM::Type::getFunctionType(
34
115
                                 Context.Int64x2Ty,
35
115
                                 {Context.Int8PtrTy, Context.Int32Ty}, false)),
36
115
        {Context.getModuleInst(Builder, ModCtx),
37
115
         LLContext.getInt32(Instr.getTargetIndex())}));
38
115
    break;
39
39
  case OpCode::Ref__eq: {
40
39
    LLVM::Value RHS = stackPop();
41
39
    LLVM::Value LHS = stackPop();
42
39
    stackPush(Builder.createZExt(
43
39
        Builder.createICmpEQ(
44
39
            Builder.createExtractElement(LHS, LLContext.getInt64(1)),
45
39
            Builder.createExtractElement(RHS, LLContext.getInt64(1))),
46
39
        Context.Int32Ty));
47
39
    break;
48
0
  }
49
375
  case OpCode::Ref__as_non_null: {
50
375
    auto Next = LLVM::BasicBlock::create(LLContext, F.Fn, "ref_as_non_null.ok");
51
375
    Stack.back() = Builder.createBitCast(Stack.back(), Context.Int64x2Ty);
52
375
    auto IsNotNull = Builder.createLikely(Builder.createICmpNE(
53
375
        Builder.createExtractElement(Stack.back(), LLContext.getInt64(1)),
54
375
        LLContext.getInt64(0)));
55
375
    Builder.createCondBr(IsNotNull, Next,
56
375
                         getTrapBB(ErrCode::Value::CastNullToNonNull));
57
375
    Builder.positionAtEnd(Next);
58
375
    break;
59
0
  }
60
61
  // Reference Instructions (GC proposal)
62
63
  case OpCode::Struct__new:
63
126
  case OpCode::Struct__new_default: {
64
126
    LLVM::Value Args = LLVM::Value::getConstPointerNull(Context.Int8PtrTy);
65
126
    assuming(Instr.getTargetIndex() < Context.CompositeTypes.size());
66
126
    const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
67
126
    assuming(CompType != nullptr && !CompType->isFunc());
68
126
    auto ArgSize = CompType->getFieldTypes().size();
69
126
    if (Instr.getOpCode() == OpCode::Struct__new) {
70
63
      std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
71
64
      for (size_t I = 0; I < ArgSize; ++I) {
72
1
        ArgsVec[ArgSize - I - 1] = stackPop();
73
1
      }
74
63
      Args = getTmpValues(ArgSize);
75
63
      Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty,
76
63
                                  LLVM::kValSize);
77
63
    } else {
78
63
      ArgSize = 0;
79
63
    }
80
126
    stackPush(Builder.createCall(
81
126
        Context.getIntrinsic(
82
126
            Builder, Executable::Intrinsics::kStructNew,
83
126
            LLVM::Type::getFunctionType(Context.Int64x2Ty,
84
126
                                        {Context.Int8PtrTy, Context.Int32Ty,
85
126
                                         Context.Int8PtrTy, Context.Int32Ty},
86
126
                                        false)),
87
126
        {Context.getModuleInst(Builder, ModCtx),
88
126
         LLContext.getInt32(Instr.getTargetIndex()), Args,
89
126
         LLContext.getInt32(static_cast<uint32_t>(ArgSize))}));
90
126
    if (Instr.getOpCode() == OpCode::Struct__new) {
91
63
      endTmpValues();
92
63
    }
93
126
    break;
94
126
  }
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
132
  case OpCode::Array__new: {
179
132
    auto Length = stackPop();
180
132
    auto Val = stackPop();
181
132
    LLVM::Value Arg = getTmpValues(1);
182
132
    Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
183
132
    stackPush(Builder.createCall(
184
132
        Context.getIntrinsic(
185
132
            Builder, Executable::Intrinsics::kArrayNew,
186
132
            LLVM::Type::getFunctionType(Context.Int64x2Ty,
187
132
                                        {Context.Int8PtrTy, Context.Int32Ty,
188
132
                                         Context.Int32Ty, Context.Int8PtrTy,
189
132
                                         Context.Int32Ty},
190
132
                                        false)),
191
132
        {Context.getModuleInst(Builder, ModCtx),
192
132
         LLContext.getInt32(Instr.getTargetIndex()), Length, Arg,
193
132
         LLContext.getInt32(1)}));
194
132
    endTmpValues();
195
132
    break;
196
0
  }
197
25
  case OpCode::Array__new_default: {
198
25
    auto Length = stackPop();
199
25
    LLVM::Value Arg = LLVM::Value::getConstPointerNull(Context.Int8PtrTy);
200
25
    stackPush(Builder.createCall(
201
25
        Context.getIntrinsic(
202
25
            Builder, Executable::Intrinsics::kArrayNew,
203
25
            LLVM::Type::getFunctionType(Context.Int64x2Ty,
204
25
                                        {Context.Int8PtrTy, Context.Int32Ty,
205
25
                                         Context.Int32Ty, Context.Int8PtrTy,
206
25
                                         Context.Int32Ty},
207
25
                                        false)),
208
25
        {Context.getModuleInst(Builder, ModCtx),
209
25
         LLContext.getInt32(Instr.getTargetIndex()), Length, Arg,
210
25
         LLContext.getInt32(0)}));
211
25
    break;
212
0
  }
213
92
  case OpCode::Array__new_fixed: {
214
92
    const auto ArgSize = Instr.getSourceIndex();
215
92
    std::vector<LLVM::Value> ArgsVec(ArgSize, nullptr);
216
581
    for (size_t I = 0; I < ArgSize; ++I) {
217
489
      ArgsVec[ArgSize - I - 1] = stackPop();
218
489
    }
219
92
    LLVM::Value Args = getTmpValues(ArgSize);
220
92
    Builder.createArrayPtrStore(ArgsVec, Args, Context.Int8Ty, LLVM::kValSize);
221
92
    stackPush(Builder.createCall(
222
92
        Context.getIntrinsic(
223
92
            Builder, Executable::Intrinsics::kArrayNew,
224
92
            LLVM::Type::getFunctionType(Context.Int64x2Ty,
225
92
                                        {Context.Int8PtrTy, Context.Int32Ty,
226
92
                                         Context.Int32Ty, Context.Int8PtrTy,
227
92
                                         Context.Int32Ty},
228
92
                                        false)),
229
92
        {Context.getModuleInst(Builder, ModCtx),
230
92
         LLContext.getInt32(Instr.getTargetIndex()),
231
92
         LLContext.getInt32(ArgSize), Args, LLContext.getInt32(ArgSize)}));
232
92
    endTmpValues();
233
92
    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
140
  case OpCode::Array__get:
256
179
  case OpCode::Array__get_u:
257
260
  case OpCode::Array__get_s: {
258
260
    assuming(static_cast<size_t>(Instr.getTargetIndex()) <
259
260
             Context.CompositeTypes.size());
260
260
    const auto *CompType = Context.CompositeTypes[Instr.getTargetIndex()];
261
260
    assuming(CompType != nullptr && !CompType->isFunc());
262
260
    assuming(static_cast<size_t>(1) == CompType->getFieldTypes().size());
263
260
    const auto &StorageType = CompType->getFieldTypes()[0].getStorageType();
264
260
    auto Idx = stackPop();
265
260
    auto Ref = stackPop();
266
260
    auto IsSigned = (Instr.getOpCode() == OpCode::Array__get_s)
267
260
                        ? LLContext.getInt8(1)
268
260
                        : LLContext.getInt8(0);
269
260
    LLVM::Value Ret = getTmpValues(1);
270
260
    Builder.createCall(
271
260
        Context.getIntrinsic(
272
260
            Builder, Executable::Intrinsics::kArrayGet,
273
260
            LLVM::Type::getFunctionType(Context.VoidTy,
274
260
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
275
260
                                         Context.Int32Ty, Context.Int32Ty,
276
260
                                         Context.Int8Ty, Context.Int8PtrTy},
277
260
                                        false)),
278
260
        {Context.getModuleInst(Builder, ModCtx), Ref,
279
260
         LLContext.getInt32(Instr.getTargetIndex()), Idx, IsSigned, Ret});
280
281
260
    switch (StorageType.getCode()) {
282
60
    case TypeCode::I8:
283
120
    case TypeCode::I16:
284
143
    case TypeCode::I32: {
285
143
      stackPush(
286
143
          Builder.createValuePtrLoad(Context.Int32Ty, Ret, Context.Int64x2Ty));
287
143
      break;
288
120
    }
289
27
    case TypeCode::I64: {
290
27
      stackPush(
291
27
          Builder.createValuePtrLoad(Context.Int64Ty, Ret, Context.Int64x2Ty));
292
27
      break;
293
120
    }
294
26
    case TypeCode::F32: {
295
26
      stackPush(
296
26
          Builder.createValuePtrLoad(Context.FloatTy, Ret, Context.Int64x2Ty));
297
26
      break;
298
120
    }
299
22
    case TypeCode::F64: {
300
22
      stackPush(
301
22
          Builder.createValuePtrLoad(Context.DoubleTy, Ret, Context.Int64x2Ty));
302
22
      break;
303
120
    }
304
21
    case TypeCode::V128:
305
21
    case TypeCode::Ref:
306
42
    case TypeCode::RefNull: {
307
42
      stackPush(Builder.createValuePtrLoad(Context.Int64x2Ty, Ret,
308
42
                                           Context.Int64x2Ty));
309
42
      break;
310
21
    }
311
0
    default:
312
0
      assumingUnreachable();
313
260
    }
314
260
    endTmpValues();
315
260
    break;
316
260
  }
317
36
  case OpCode::Array__set: {
318
36
    auto Val = stackPop();
319
36
    auto Idx = stackPop();
320
36
    auto Ref = stackPop();
321
36
    LLVM::Value Arg = getTmpValues(1);
322
36
    Builder.createValuePtrStore(Val, Arg, Context.Int64x2Ty);
323
36
    Builder.createCall(
324
36
        Context.getIntrinsic(
325
36
            Builder, Executable::Intrinsics::kArraySet,
326
36
            LLVM::Type::getFunctionType(Context.VoidTy,
327
36
                                        {Context.Int8PtrTy, Context.Int64x2Ty,
328
36
                                         Context.Int32Ty, Context.Int32Ty,
329
36
                                         Context.Int8PtrTy},
330
36
                                        false)),
331
36
        {Context.getModuleInst(Builder, ModCtx), Ref,
332
36
         LLContext.getInt32(Instr.getTargetIndex()), Idx, Arg});
333
36
    endTmpValues();
334
36
    break;
335
260
  }
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
260
  }
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
260
  }
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
260
  }
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
12
  case OpCode::Ref__test:
409
36
  case OpCode::Ref__test_null: {
410
36
    auto Ref = stackPop();
411
36
    std::array<uint8_t, 16> Buf = {0};
412
36
    std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
413
36
    auto VType = Builder.createExtractElement(
414
36
        Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
415
36
                              Context.Int64x2Ty),
416
36
        LLContext.getInt64(0));
417
36
    stackPush(Builder.createCall(
418
36
        Context.getIntrinsic(
419
36
            Builder, Executable::Intrinsics::kRefTest,
420
36
            LLVM::Type::getFunctionType(
421
36
                Context.Int32Ty,
422
36
                {Context.Int8PtrTy, Context.Int64x2Ty, Context.Int64Ty},
423
36
                false)),
424
36
        {Context.getModuleInst(Builder, ModCtx), Ref, VType}));
425
36
    break;
426
12
  }
427
39
  case OpCode::Ref__cast:
428
60
  case OpCode::Ref__cast_null: {
429
60
    auto Ref = stackPop();
430
60
    std::array<uint8_t, 16> Buf = {0};
431
60
    std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Buf.begin());
432
60
    auto VType = Builder.createExtractElement(
433
60
        Builder.createBitCast(LLVM::Value::getConstVector8(LLContext, Buf),
434
60
                              Context.Int64x2Ty),
435
60
        LLContext.getInt64(0));
436
60
    stackPush(Builder.createCall(
437
60
        Context.getIntrinsic(
438
60
            Builder, Executable::Intrinsics::kRefCast,
439
60
            LLVM::Type::getFunctionType(
440
60
                Context.Int64x2Ty,
441
60
                {Context.Int8PtrTy, Context.Int64x2Ty, Context.Int64Ty},
442
60
                false)),
443
60
        {Context.getModuleInst(Builder, ModCtx), Ref, VType}));
444
60
    break;
445
39
  }
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
39
  }
500
55
  case OpCode::Extern__convert_any: {
501
55
    std::array<uint8_t, 16> RawRef = {0};
502
55
    auto Ref = stackPop();
503
55
    auto IsNullBB =
504
55
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.null");
505
55
    auto NotNullBB =
506
55
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.not_null");
507
55
    auto EndBB =
508
55
        LLVM::BasicBlock::create(LLContext, F.Fn, "extern_conv_any.end");
509
55
    auto CondIsNull = Builder.createICmpEQ(
510
55
        Builder.createExtractElement(Ref, LLContext.getInt64(1)),
511
55
        LLContext.getInt64(0));
512
55
    Builder.createCondBr(CondIsNull, IsNullBB, NotNullBB);
513
514
55
    Builder.positionAtEnd(IsNullBB);
515
55
    auto VT = ValType(TypeCode::RefNull, TypeCode::NullExternRef);
516
55
    std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
517
55
    auto Ret1 = Builder.createBitCast(
518
55
        LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
519
55
    Builder.createBr(EndBB);
520
521
55
    Builder.positionAtEnd(NotNullBB);
522
55
    auto Ret2 =
523
55
        Builder.createBitCast(Builder.createInsertElement(
524
55
                                  Builder.createBitCast(Ref, Context.Int8x16Ty),
525
55
                                  LLContext.getInt8(1), LLContext.getInt64(1)),
526
55
                              Context.Int64x2Ty);
527
55
    Builder.createBr(EndBB);
528
529
55
    Builder.positionAtEnd(EndBB);
530
55
    auto Ret = Builder.createPHI(Context.Int64x2Ty);
531
55
    Ret.addIncoming(Ret1, IsNullBB);
532
55
    Ret.addIncoming(Ret2, NotNullBB);
533
55
    stackPush(Ret);
534
55
    break;
535
39
  }
536
94
  case OpCode::Ref__i31: {
537
94
    std::array<uint8_t, 16> RawRef = {0};
538
94
    auto VT = ValType(TypeCode::Ref, TypeCode::I31Ref);
539
94
    std::copy_n(VT.getRawData().cbegin(), 8, RawRef.begin());
540
94
    auto Ref = Builder.createBitCast(
541
94
        LLVM::Value::getConstVector8(LLContext, RawRef), Context.Int64x2Ty);
542
94
    auto Val = Builder.createZExt(
543
94
        Builder.createOr(
544
94
            Builder.createAnd(stackPop(), LLContext.getInt32(0x7FFFFFFFU)),
545
94
            LLContext.getInt32(0x80000000U)),
546
94
        Context.Int64Ty);
547
94
    stackPush(Builder.createInsertElement(Ref, Val, LLContext.getInt64(1)));
548
94
    break;
549
39
  }
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
39
  }
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
39
  }
584
585
  // Parametric Instructions
586
3.45k
  case OpCode::Drop:
587
3.45k
    stackPop();
588
3.45k
    break;
589
687
  case OpCode::Select:
590
1.10k
  case OpCode::Select_t: {
591
1.10k
    auto Cond = Builder.createICmpNE(stackPop(), LLContext.getInt32(0));
592
1.10k
    auto False = stackPop();
593
1.10k
    auto True = stackPop();
594
1.10k
    stackPush(Builder.createSelect(Cond, True, False));
595
1.10k
    break;
596
687
  }
597
598
    // Variable Instructions
599
0
  default:
600
0
    assumingUnreachable();
601
14.5k
  }
602
14.5k
  return {};
603
14.5k
}
604
605
} // namespace WasmEdge