Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/common/int128.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/common/int128.h - 128-bit integer type -------------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the 128-bit integer type.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#if defined(_MSC_VER) && !defined(__clang__)
17
#pragma intrinsic(_BitScanReverse)
18
#pragma intrinsic(_BitScanReverse64)
19
#include <immintrin.h>
20
#endif
21
// We have to detect those environments that don't support __int128 type
22
// natively.
23
#include "endian.h"
24
25
#include <cstdint>
26
#include <limits>
27
#include <stdexcept>
28
29
namespace WasmEdge {
30
31
0
inline constexpr int clz(uint32_t V) noexcept {
32
0
  if (V) {
33
0
#if defined(_MSC_VER) && !defined(__clang__)
34
0
    unsigned long LeadingZero = 0;
35
0
    _BitScanReverse(&LeadingZero, V);
36
0
    return 31 ^ static_cast<int>(LeadingZero);
37
0
#else
38
0
    return __builtin_clz(V);
39
0
#endif
40
0
  }
41
0
  return 32;
42
0
}
43
44
0
inline constexpr int clz(uint64_t V) noexcept {
45
0
  if (V) {
46
0
#if defined(_MSC_VER) && !defined(__clang__)
47
0
    unsigned long LeadingZero = 0;
48
0
    _BitScanReverse64(&LeadingZero, V);
49
0
    return 63 ^ static_cast<int>(LeadingZero);
50
0
#else
51
0
    return __builtin_clzll(V);
52
0
#endif
53
0
  }
54
0
  return 64;
55
0
}
56
57
inline auto udiv128by64to64(uint64_t U1, uint64_t U0, uint64_t V,
58
0
                            uint64_t &R) noexcept {
59
0
  {
60
0
#if defined(_M_X64) && defined(_MSC_VER) && !defined(__clang__)
61
0
    return _udiv128(U1, U0, V, &R);
62
0
#elif defined(__x86_64__)
63
0
    uint64_t Result = 0;
64
0
    __asm__("divq %[v]" : "=a"(Result), "=d"(R) : [v] "r"(V), "a"(U0), "d"(U1));
65
0
    return Result;
66
0
#endif
67
0
  }
68
0
  const uint32_t V0 = static_cast<uint32_t>(V);
69
0
  const uint32_t V1 = static_cast<uint32_t>(V >> 32);
70
0
  if (V1 == 0) {
71
0
    auto Rem = (U1 << 32) | (U0 >> 32);
72
0
    auto Result = Rem / V0;
73
0
    Rem = ((Rem % V0) << 32) | static_cast<uint32_t>(U0);
74
0
    Result = (Result << 32) | (Rem / V0);
75
0
    R = Rem % V0;
76
0
    return Result;
77
0
  }
78
0
  uint64_t Un64 = 0, Un10 = 0;
79
0
  const auto s = clz(V1);
80
0
  if (s > 0) {
81
0
    V <<= s;
82
0
    Un64 = (U1 << s) | (U0 >> (64 - s));
83
0
    Un10 = U0 << s;
84
0
  } else {
85
0
    Un64 = U1;
86
0
    Un10 = U0;
87
0
  }
88
0
  uint64_t Vn1 = static_cast<uint32_t>(V >> 32);
89
0
  uint64_t Vn0 = static_cast<uint32_t>(V);
90
0
  uint64_t Un1 = static_cast<uint32_t>(Un10 >> 32);
91
0
  uint64_t Un0 = static_cast<uint32_t>(Un10);
92
0
  uint64_t Q1 = Un64 / Vn1;
93
0
  uint64_t Rhat = Un64 - Q1 * Vn1;
94
0
  while ((Q1 >> 32) >= 1 || Q1 * Vn0 > (Rhat << 32) + Un1) {
95
0
    --Q1;
96
0
    Rhat += Vn1;
97
0
    if ((Rhat >> 32) >= 1) {
98
0
      break;
99
0
    }
100
0
  }
101
0
102
0
  uint64_t Un21 = (Un64 << 32) + Un1 - Q1 * V;
103
0
  uint64_t Q0 = Un21 / Vn1;
104
0
  Rhat = Un21 - Q0 * Vn1;
105
0
  while ((Q0 >> 32) >= 1 || Q0 * Vn0 > (Rhat << 32) + Un0) {
106
0
    --Q0;
107
0
    Rhat += Vn1;
108
0
    if ((Rhat >> 32) >= 1) {
109
0
      break;
110
0
    }
111
0
  }
112
0
  R = ((Un21 << 32) + Un0 - Q0 * V) >> s;
113
0
  return (Q1 << 32) + Q0;
114
0
}
115
116
class int128;
117
class uint128;
118
119
class uint128 {
120
public:
121
  uint128() noexcept = default;
122
  constexpr uint128(const uint128 &) noexcept = default;
123
  constexpr uint128(uint128 &&) noexcept = default;
124
  constexpr uint128 &operator=(const uint128 &V) noexcept = default;
125
  constexpr uint128 &operator=(uint128 &&V) noexcept = default;
126
127
0
  constexpr uint128(unsigned int V) noexcept : Low(V), High(0) {}
128
0
  constexpr uint128(unsigned long V) noexcept : Low(V), High(0) {}
129
0
  constexpr uint128(unsigned long long V) noexcept : Low(V), High(0) {}
130
  constexpr uint128(int128 V) noexcept;
131
0
  constexpr uint128(uint64_t H, uint64_t L) noexcept : Low(L), High(H) {}
132
133
#if defined(__x86_64__) || defined(__aarch64__) ||                             \
134
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
135
  constexpr uint128(unsigned __int128 V) noexcept
136
0
      : Low(static_cast<uint64_t>(V)), High(static_cast<uint64_t>(V >> 64)) {}
137
#endif
138
139
0
  constexpr operator bool() const noexcept {
140
0
    return static_cast<bool>(Low) || static_cast<bool>(High);
141
0
  }
142
0
  constexpr operator uint8_t() const noexcept {
143
0
    return static_cast<uint8_t>(Low);
144
0
  }
145
0
  constexpr operator uint16_t() const noexcept {
146
0
    return static_cast<uint16_t>(Low);
147
0
  }
148
0
  constexpr operator uint32_t() const noexcept {
149
0
    return static_cast<uint32_t>(Low);
150
0
  }
151
0
  constexpr operator uint64_t() const noexcept {
152
0
    return static_cast<uint64_t>(Low);
153
0
  }
154
155
0
  constexpr uint128 &operator=(unsigned int V) noexcept {
156
0
    return *this = uint128(V);
157
0
  }
158
0
  constexpr uint128 &operator=(unsigned long V) noexcept {
159
0
    return *this = uint128(V);
160
0
  }
161
0
  constexpr uint128 &operator=(unsigned long long V) noexcept {
162
0
    return *this = uint128(V);
163
0
  }
164
0
  constexpr uint128 &operator+=(uint128 Other) noexcept {
165
0
    return *this = *this + Other;
166
0
  }
167
0
  constexpr uint128 &operator-=(uint128 Other) noexcept {
168
0
    return *this = *this - Other;
169
0
  }
170
0
  constexpr uint128 &operator*=(uint128 Other) noexcept {
171
0
    return *this = *this * Other;
172
0
  }
173
0
  constexpr uint128 &operator/=(uint128 Other) noexcept {
174
0
    return *this = *this / Other;
175
0
  }
176
0
  constexpr uint128 &operator%=(uint128 Other) noexcept {
177
0
    return *this = *this % Other;
178
0
  }
179
0
  constexpr uint128 &operator&=(uint128 Other) noexcept {
180
0
    return *this = *this & Other;
181
0
  }
182
0
  constexpr uint128 &operator|=(uint128 Other) noexcept {
183
0
    return *this = *this | Other;
184
0
  }
185
0
  constexpr uint128 &operator^=(uint128 Other) noexcept {
186
0
    return *this = *this ^ Other;
187
0
  }
188
0
  constexpr uint128 &operator<<=(unsigned int Other) noexcept {
189
0
    return *this = *this << Other;
190
0
  }
191
0
  constexpr uint128 &operator>>=(unsigned int Other) noexcept {
192
0
    return *this = *this >> Other;
193
0
  }
194
0
  constexpr uint128 &operator<<=(int Other) noexcept {
195
0
    return *this = *this << Other;
196
0
  }
197
0
  constexpr uint128 &operator>>=(int Other) noexcept {
198
0
    return *this = *this >> Other;
199
0
  }
200
201
  constexpr uint128 &operator=(int128 V) noexcept;
202
203
0
  friend constexpr bool operator==(uint128 LHS, uint128 RHS) noexcept {
204
0
    return LHS.Low == RHS.Low && LHS.High == RHS.High;
205
0
  }
206
0
  friend constexpr bool operator<(uint128 LHS, uint128 RHS) noexcept {
207
0
    return LHS.High == RHS.High ? LHS.Low < RHS.Low : LHS.High < RHS.High;
208
0
  }
209
0
  friend constexpr bool operator>(uint128 LHS, uint128 RHS) noexcept {
210
0
    return RHS < LHS;
211
0
  }
212
0
  friend constexpr bool operator!=(uint128 LHS, uint128 RHS) noexcept {
213
0
    return !(LHS == RHS);
214
0
  }
215
0
  friend constexpr bool operator<=(uint128 LHS, uint128 RHS) noexcept {
216
0
    return !(LHS > RHS);
217
0
  }
218
0
  friend constexpr bool operator>=(uint128 LHS, uint128 RHS) noexcept {
219
0
    return !(LHS < RHS);
220
0
  }
221
222
0
  friend constexpr uint128 operator+(uint128 LHS, uint128 RHS) noexcept {
223
0
    uint64_t Carry =
224
0
        (std::numeric_limits<uint64_t>::max() - LHS.Low) < RHS.Low ? 1 : 0;
225
0
    return uint128(LHS.High + RHS.High + Carry, LHS.Low + RHS.Low);
226
0
  }
227
0
  friend constexpr uint128 operator-(uint128 LHS, uint128 RHS) noexcept {
228
0
    uint64_t Carry = LHS.Low < RHS.Low ? 1 : 0;
229
0
    return uint128(LHS.High - RHS.High - Carry, LHS.Low - RHS.Low);
230
0
  }
231
0
  friend constexpr uint128 operator*(uint128 LHS, uint128 RHS) noexcept {
232
0
    uint64_t A32 = LHS.Low >> 32;
233
0
    uint64_t A00 = LHS.Low & UINT64_C(0xffffffff);
234
0
    uint64_t B32 = RHS.Low >> 32;
235
0
    uint64_t B00 = RHS.Low & UINT64_C(0xffffffff);
236
0
    uint128 Result =
237
0
        uint128(LHS.High * RHS.Low + LHS.Low * RHS.High + A32 * B32, A00 * B00);
238
0
    Result += uint128(A32 * B00) << 32U;
239
0
    Result += uint128(A00 * B32) << 32U;
240
0
    return Result;
241
0
  }
242
0
  friend uint128 operator/(uint128 LHS, uint64_t RHS) noexcept {
243
0
    if (LHS.High == 0 && LHS.Low < RHS) {
244
0
      LHS.Low = 0;
245
0
      return LHS;
246
0
    }
247
0
    if (LHS.High < RHS) {
248
0
      uint64_t Rem = 0;
249
0
      uint64_t QLow = udiv128by64to64(LHS.High, LHS.Low, RHS, Rem);
250
0
      LHS.Low = QLow;
251
0
      LHS.High = 0;
252
0
      return LHS;
253
0
    }
254
0
    uint64_t QHigh = LHS.High / RHS;
255
0
    uint64_t Rem = 0;
256
0
    uint64_t QLow = udiv128by64to64(LHS.High % RHS, LHS.Low, RHS, Rem);
257
0
    LHS.Low = QLow;
258
0
    LHS.High = QHigh;
259
0
    return LHS;
260
0
  }
261
0
  friend constexpr uint128 operator/(uint128 LHS, uint128 RHS) noexcept {
262
0
    if (RHS > LHS) {
263
0
      return 0U;
264
0
    }
265
0
    if (RHS == LHS) {
266
0
      return 1U;
267
0
    }
268
0
    if (RHS.High == 0) {
269
0
      return LHS / RHS.Low;
270
0
    }
271
0
    uint128 Denominator = RHS;
272
0
    uint128 Quotient = 0U;
273
0
    const unsigned int Shift = RHS.clz() - LHS.clz();
274
0
    Denominator <<= Shift;
275
0
    for (unsigned int I = 0U; I <= Shift; ++I) {
276
0
      Quotient <<= 1U;
277
0
      if (LHS >= Denominator) {
278
0
        LHS -= Denominator;
279
0
        Quotient |= 1U;
280
0
      }
281
0
      Denominator >>= 1U;
282
0
    }
283
0
    return Quotient;
284
0
  }
285
0
  friend constexpr uint128 operator%(uint128 LHS, uint128 RHS) noexcept {
286
0
    if (RHS > LHS) {
287
0
      return LHS;
288
0
    }
289
0
    if (RHS == LHS) {
290
0
      return 0U;
291
0
    }
292
0
    uint128 Denominator = RHS;
293
0
    const unsigned int Shift = RHS.clz() - LHS.clz();
294
0
    Denominator <<= Shift;
295
0
    for (unsigned int I = 0; I <= Shift; ++I) {
296
0
      if (LHS >= Denominator) {
297
0
        LHS -= Denominator;
298
0
      }
299
0
      Denominator >>= 1U;
300
0
    }
301
0
    return LHS;
302
0
  }
303
0
  friend constexpr uint128 operator&(uint128 LHS, uint128 RHS) noexcept {
304
0
    return uint128(LHS.High & RHS.High, LHS.Low & RHS.Low);
305
0
  }
306
0
  friend constexpr uint128 operator|(uint128 LHS, uint128 RHS) noexcept {
307
0
    return uint128(LHS.High | RHS.High, LHS.Low | RHS.Low);
308
0
  }
309
0
  friend constexpr uint128 operator^(uint128 LHS, uint128 RHS) noexcept {
310
0
    return uint128(LHS.High ^ RHS.High, LHS.Low ^ RHS.Low);
311
0
  }
312
0
  friend constexpr uint128 operator~(uint128 Value) noexcept {
313
0
    return uint128(~Value.High, ~Value.Low);
314
0
  }
315
  friend constexpr uint128 operator<<(uint128 Value,
316
0
                                      unsigned int Shift) noexcept {
317
0
    if (Shift < 64) {
318
0
      if (Shift != 0) {
319
0
        return uint128((Value.High << Shift) | (Value.Low >> (64 - Shift)),
320
0
                       Value.Low << Shift);
321
0
      }
322
0
      return Value;
323
0
    }
324
0
    if (Shift < 128) {
325
0
      return uint128(Value.Low << (Shift - 64), 0);
326
0
    }
327
0
    return 0U;
328
0
  }
329
  friend constexpr uint128 operator>>(uint128 Value,
330
0
                                      unsigned int Shift) noexcept {
331
0
    if (Shift < 64) {
332
0
      if (Shift != 0) {
333
0
        return uint128((Value.High >> Shift),
334
0
                       Value.Low >> Shift | (Value.High << (64 - Shift)));
335
0
      }
336
0
      return Value;
337
0
    }
338
0
    if (Shift < 128) {
339
0
      return uint128(0, Value.High >> (Shift - 64));
340
0
    }
341
0
    return 0U;
342
0
  }
343
0
  friend constexpr uint128 operator<<(uint128 Value, int Shift) noexcept {
344
0
    return Value << static_cast<unsigned int>(Shift);
345
0
  }
346
0
  friend constexpr uint128 operator>>(uint128 Value, int Shift) noexcept {
347
0
    return Value >> static_cast<unsigned int>(Shift);
348
0
  }
349
  friend constexpr uint128 operator<<(uint128 Value,
350
0
                                      unsigned long long Shift) noexcept {
351
0
    if (Shift >= 128ULL) {
352
0
      return 0U;
353
0
    }
354
0
    return Value << static_cast<unsigned int>(Shift);
355
0
  }
356
  friend constexpr uint128 operator>>(uint128 Value,
357
0
                                      unsigned long long Shift) noexcept {
358
0
    if (Shift >= 128ULL) {
359
0
      return 0U;
360
0
    }
361
0
    return Value >> static_cast<unsigned int>(Shift);
362
0
  }
363
364
0
  static constexpr uint128 numericMin() noexcept {
365
0
    return uint128(std::numeric_limits<uint64_t>::min(),
366
0
                   std::numeric_limits<uint64_t>::min());
367
0
  }
368
0
  static constexpr uint128 numericMax() noexcept {
369
0
    return uint128(std::numeric_limits<uint64_t>::max(),
370
0
                   std::numeric_limits<uint64_t>::max());
371
0
  }
372
373
0
  constexpr uint64_t low() const noexcept { return Low; }
374
0
  constexpr uint64_t high() const noexcept { return High; }
375
0
  constexpr unsigned int clz() const noexcept {
376
0
    if (High) {
377
0
      return static_cast<unsigned int>(WasmEdge::clz(High));
378
0
    }
379
0
    if (Low) {
380
0
      return static_cast<unsigned int>(WasmEdge::clz(Low)) + 64U;
381
0
    }
382
0
    return 128U;
383
0
  }
384
385
private:
386
  uint64_t Low;
387
  uint64_t High;
388
};
389
390
class int128 {
391
public:
392
  int128() noexcept = default;
393
  constexpr int128(const int128 &) noexcept = default;
394
  constexpr int128(int128 &&) noexcept = default;
395
  constexpr int128 &operator=(const int128 &V) noexcept = default;
396
  constexpr int128 &operator=(int128 &&V) noexcept = default;
397
398
  constexpr int128(int V) noexcept
399
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
400
  constexpr int128(long V) noexcept
401
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
402
  constexpr int128(long long V) noexcept
403
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
404
0
  constexpr int128(unsigned int V) noexcept : Low(V), High(INT64_C(0)) {}
405
0
  constexpr int128(unsigned long V) noexcept : Low(V), High(INT64_C(0)) {}
406
0
  constexpr int128(unsigned long long V) noexcept : Low(V), High(INT64_C(0)) {}
407
  constexpr int128(uint128 V) noexcept;
408
0
  constexpr int128(int64_t H, uint64_t L) noexcept : Low(L), High(H) {}
409
#if defined(__x86_64__) || defined(__aarch64__) ||                             \
410
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
411
  constexpr int128(__int128 V) noexcept
412
0
      : Low(static_cast<uint64_t>(V)), High(V >> 64) {}
413
#endif
414
415
0
  constexpr int128 &operator=(int V) noexcept { return *this = int128(V); }
416
0
  constexpr int128 &operator=(long V) noexcept { return *this = int128(V); }
417
0
  constexpr int128 &operator=(long long V) noexcept {
418
0
    return *this = int128(V);
419
0
  }
420
0
  constexpr int128 &operator=(unsigned int V) noexcept {
421
0
    return *this = int128(V);
422
0
  }
423
0
  constexpr int128 &operator=(unsigned long V) noexcept {
424
0
    return *this = int128(V);
425
0
  }
426
0
  constexpr int128 &operator=(unsigned long long V) noexcept {
427
0
    return *this = int128(V);
428
0
  }
429
430
  constexpr int128 &operator=(uint128 V) noexcept;
431
432
0
  static constexpr int128 numericMin() noexcept {
433
0
    return int128(std::numeric_limits<int64_t>::min(), 0);
434
0
  }
435
0
  static constexpr int128 numericMax() noexcept {
436
0
    return int128(std::numeric_limits<int64_t>::max(),
437
0
                  std::numeric_limits<uint64_t>::max());
438
0
  }
439
440
0
  constexpr uint64_t low() const noexcept { return Low; }
441
0
  constexpr int64_t high() const noexcept { return High; }
442
443
private:
444
  uint64_t Low;
445
  int64_t High;
446
};
447
448
inline constexpr uint128::uint128(int128 V) noexcept
449
    : Low(V.low()), High(static_cast<uint64_t>(V.high())) {}
450
451
0
inline constexpr uint128 &uint128::operator=(int128 V) noexcept {
452
0
  return *this = uint128(V);
453
0
}
454
455
inline constexpr int128::int128(uint128 V) noexcept
456
    : Low(V.low()), High(static_cast<int64_t>(V.high())) {}
457
458
0
inline constexpr int128 &int128::operator=(uint128 V) noexcept {
459
0
  return *this = int128(V);
460
0
}
461
462
} // namespace WasmEdge
463
464
namespace std {
465
template <> class numeric_limits<WasmEdge::uint128> {
466
public:
467
  static constexpr bool is_specialized = true;
468
  static constexpr bool is_signed = false;
469
  static constexpr bool is_integer = true;
470
  static constexpr bool is_exact = true;
471
  static constexpr bool has_infinity = false;
472
  static constexpr bool has_quiet_NaN = false;
473
  static constexpr bool has_signaling_NaN = false;
474
  static constexpr float_denorm_style has_denorm = denorm_absent;
475
  static constexpr bool has_denorm_loss = false;
476
  static constexpr float_round_style round_style = round_toward_zero;
477
  static constexpr bool is_iec559 = false;
478
  static constexpr bool is_bounded = true;
479
  static constexpr bool is_modulo = true;
480
  static constexpr int digits = 128;
481
  static constexpr int digits10 = 38;
482
  static constexpr int max_digits10 = 0;
483
  static constexpr int radix = 2;
484
  static constexpr int min_exponent = 0;
485
  static constexpr int min_exponent10 = 0;
486
  static constexpr int max_exponent = 0;
487
  static constexpr int max_exponent10 = 0;
488
  static constexpr bool traps = numeric_limits<uint64_t>::traps;
489
  static constexpr bool tinyness_before = false;
490
491
0
  static constexpr WasmEdge::uint128 min() {
492
0
    return WasmEdge::uint128::numericMin();
493
0
  }
494
0
  static constexpr WasmEdge::uint128 lowest() {
495
0
    return WasmEdge::uint128::numericMin();
496
0
  }
497
0
  static constexpr WasmEdge::uint128 max() {
498
0
    return WasmEdge::uint128::numericMax();
499
0
  }
500
0
  static constexpr WasmEdge::uint128 epsilon() { return 0U; }
501
0
  static constexpr WasmEdge::uint128 round_error() { return 0U; }
502
0
  static constexpr WasmEdge::uint128 infinity() { return 0U; }
503
0
  static constexpr WasmEdge::uint128 quiet_NaN() { return 0U; }
504
0
  static constexpr WasmEdge::uint128 signaling_NaN() { return 0U; }
505
0
  static constexpr WasmEdge::uint128 denorm_min() { return 0U; }
506
};
507
template <> class numeric_limits<WasmEdge::int128> {
508
public:
509
  static constexpr bool is_specialized = true;
510
  static constexpr bool is_signed = true;
511
  static constexpr bool is_integer = true;
512
  static constexpr bool is_exact = true;
513
  static constexpr bool has_infinity = false;
514
  static constexpr bool has_quiet_NaN = false;
515
  static constexpr bool has_signaling_NaN = false;
516
  static constexpr float_denorm_style has_denorm = denorm_absent;
517
  static constexpr bool has_denorm_loss = false;
518
  static constexpr float_round_style round_style = round_toward_zero;
519
  static constexpr bool is_iec559 = false;
520
  static constexpr bool is_bounded = true;
521
  static constexpr bool is_modulo = false;
522
  static constexpr int digits = 127;
523
  static constexpr int digits10 = 38;
524
  static constexpr int max_digits10 = 0;
525
  static constexpr int radix = 2;
526
  static constexpr int min_exponent = 0;
527
  static constexpr int min_exponent10 = 0;
528
  static constexpr int max_exponent = 0;
529
  static constexpr int max_exponent10 = 0;
530
  static constexpr bool traps = numeric_limits<uint64_t>::traps;
531
  static constexpr bool tinyness_before = false;
532
533
0
  static constexpr WasmEdge::int128 min() {
534
0
    return WasmEdge::int128::numericMin();
535
0
  }
536
0
  static constexpr WasmEdge::int128 lowest() {
537
0
    return WasmEdge::int128::numericMin();
538
0
  }
539
0
  static constexpr WasmEdge::int128 max() {
540
0
    return WasmEdge::int128::numericMax();
541
0
  }
542
0
  static constexpr WasmEdge::int128 epsilon() { return 0; }
543
0
  static constexpr WasmEdge::int128 round_error() { return 0; }
544
0
  static constexpr WasmEdge::int128 infinity() { return 0; }
545
0
  static constexpr WasmEdge::int128 quiet_NaN() { return 0; }
546
0
  static constexpr WasmEdge::int128 signaling_NaN() { return 0; }
547
0
  static constexpr WasmEdge::int128 denorm_min() { return 0; }
548
};
549
} // namespace std
550
551
namespace WasmEdge {
552
// If there is a built-in type __int128, then use it directly
553
#if defined(__x86_64__) || defined(__aarch64__) ||                             \
554
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
555
using int128_t = __int128;
556
using uint128_t = unsigned __int128;
557
#else
558
using int128_t = int128;
559
using uint128_t = uint128;
560
#endif
561
} // namespace WasmEdge
562
563
#include <fmt/format.h>
564
565
FMT_BEGIN_NAMESPACE
566
#if FMT_VERSION >= 90000
567
namespace detail {
568
#if FMT_VERSION >= 120200
569
using uint128_fallback = uint128;
570
#endif
571
inline constexpr bool operator>=(detail::uint128_fallback LHS,
572
0
                                 unsigned int RHS) {
573
0
  return LHS.high() != 0 || LHS.low() >= static_cast<uint64_t>(RHS);
574
0
}
575
576
inline constexpr bool operator<(detail::uint128_fallback LHS,
577
0
                                unsigned int RHS) {
578
0
  return LHS.high() == 0 && LHS.low() < static_cast<uint64_t>(RHS);
579
0
}
580
581
inline constexpr bool operator<(detail::uint128_fallback LHS,
582
0
                                detail::uint128_fallback RHS) {
583
0
  return LHS.high() < RHS.high() ||
584
0
         (LHS.high() == RHS.high() && LHS.low() < RHS.low());
585
0
}
586
587
inline constexpr detail::uint128_fallback
588
0
operator+(detail::uint128_fallback LHS, unsigned int RHS) {
589
0
  uint64_t NewLow = LHS.low() + RHS;
590
0
  uint64_t NewHigh = LHS.high() + (NewLow < LHS.low());
591
0
  return {NewHigh, NewLow};
592
0
}
593
594
inline constexpr detail::uint128_fallback
595
0
operator-(unsigned int LHS, detail::uint128_fallback RHS) {
596
0
  detail::uint128_fallback Negated = {~RHS.high(), ~RHS.low()};
597
0
  return Negated + 1 + LHS;
598
0
}
599
600
inline constexpr detail::uint128_fallback &
601
0
operator/=(detail::uint128_fallback &LHS, unsigned int RHSi) {
602
0
  const uint64_t RHS = static_cast<uint64_t>(RHSi);
603
0
  if (LHS.high() == 0 && LHS.low() < RHS) {
604
0
    LHS = 0;
605
0
    return LHS;
606
0
  }
607
0
  if (LHS.high() < RHS) {
608
0
    uint64_t Rem = 0;
609
0
    uint64_t QLo = WasmEdge::udiv128by64to64(LHS.high(), LHS.low(), RHS, Rem);
610
0
    LHS = QLo;
611
0
    return LHS;
612
0
  }
613
0
  uint64_t QHi = LHS.high() / RHS;
614
0
  uint64_t Rem = 0;
615
0
  uint64_t QLo =
616
0
      WasmEdge::udiv128by64to64(LHS.high() % RHS, LHS.low(), RHS, Rem);
617
0
  LHS = (detail::uint128_t{QHi} << 64u) | QLo;
618
0
  return LHS;
619
0
}
620
621
inline constexpr detail::uint128_fallback
622
0
operator%(detail::uint128_fallback LHS, unsigned int RHSi) {
623
0
  const uint64_t RHS = static_cast<uint64_t>(RHSi);
624
0
  if (LHS.high() == 0 && LHS.low() < RHS) {
625
0
    return LHS;
626
0
  }
627
0
  uint64_t Rem = 0;
628
0
  WasmEdge::udiv128by64to64(LHS.high() % RHS, LHS.low(), RHS, Rem);
629
0
  return Rem;
630
0
}
631
632
0
inline int do_count_digits(detail::uint128_fallback N) {
633
0
  const uint64_t Low = static_cast<uint64_t>(N);
634
0
  const uint64_t High = static_cast<uint64_t>(N >> 64);
635
0
  if (High == 0) {
636
0
    return detail::count_digits(Low);
637
0
  }
638
0
  // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
639
0
  static constexpr uint8_t Bsr2Log10[] = {
640
0
      20, 20, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25,
641
0
      25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29,
642
0
      30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 34, 34, 34,
643
0
      35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39};
644
0
  auto C = WasmEdge::clz(High);
645
0
  auto T = Bsr2Log10[C ^ 63];
646
0
  static constexpr const uint128_t PowersOf10[] = {
647
0
      0,
648
0
      (uint128_t(5ULL) << 64) | uint128_t(7766279631452241920ULL),
649
0
      (uint128_t(54ULL) << 64) | uint128_t(3875820019684212736ULL),
650
0
      (uint128_t(542ULL) << 64) | uint128_t(1864712049423024128ULL),
651
0
      (uint128_t(5421ULL) << 64) | uint128_t(200376420520689664ULL),
652
0
      (uint128_t(54210ULL) << 64) | uint128_t(2003764205206896640ULL),
653
0
      (uint128_t(542101ULL) << 64) | uint128_t(1590897978359414784ULL),
654
0
      (uint128_t(5421010ULL) << 64) | uint128_t(15908979783594147840ULL),
655
0
      (uint128_t(54210108ULL) << 64) | uint128_t(11515845246265065472ULL),
656
0
      (uint128_t(542101086ULL) << 64) | uint128_t(4477988020393345024ULL),
657
0
      (uint128_t(5421010862ULL) << 64) | uint128_t(7886392056514347008ULL),
658
0
      (uint128_t(54210108624ULL) << 64) | uint128_t(5076944270305263616ULL),
659
0
      (uint128_t(542101086242ULL) << 64) | uint128_t(13875954555633532928ULL),
660
0
      (uint128_t(5421010862427ULL) << 64) | uint128_t(9632337040368467968ULL),
661
0
      (uint128_t(54210108624275ULL) << 64) | uint128_t(4089650035136921600ULL),
662
0
      (uint128_t(542101086242752ULL) << 64) | uint128_t(4003012203950112768ULL),
663
0
      (uint128_t(5421010862427522ULL) << 64) |
664
0
          uint128_t(3136633892082024448ULL),
665
0
      (uint128_t(54210108624275221ULL) << 64) |
666
0
          uint128_t(12919594847110692864ULL),
667
0
      (uint128_t(542101086242752217ULL) << 64) |
668
0
          uint128_t(68739955140067328ULL),
669
0
      (uint128_t(5421010862427522170ULL) << 64) |
670
0
          uint128_t(687399551400673280ULL),
671
0
  };
672
0
  return T - (N < PowersOf10[T - 20]);
673
0
}
674
675
0
FMT_CONSTEXPR20 inline int count_digits(detail::uint128_fallback N) {
676
0
  if (!is_constant_evaluated()) {
677
0
    return do_count_digits(N);
678
0
  }
679
0
  return count_digits_fallback(N);
680
0
}
681
682
} // namespace detail
683
#endif
684
685
#if FMT_VERSION >= 80000
686
template <typename Char> struct formatter<WasmEdge::uint128, Char> {
687
private:
688
  detail::dynamic_format_specs<Char> Specs;
689
690
public:
691
0
  template <typename ParseContext> constexpr auto parse(ParseContext &Ctx) {
692
0
#if FMT_VERSION >= 100000
693
0
    return parse_format_specs(Ctx.begin(), Ctx.end(), Specs, Ctx,
694
0
                              detail::type::uint_type);
695
#else
696
    using HandlerType = detail::dynamic_specs_handler<ParseContext>;
697
    detail::specs_checker<HandlerType> Handler(HandlerType(Specs, Ctx),
698
                                               detail::type::uint_type);
699
    return parse_format_specs(Ctx.begin(), Ctx.end(), Handler);
700
#endif
701
0
  }
702
703
  template <typename FormatContext>
704
0
  auto format(WasmEdge::uint128 V, FormatContext &Ctx) const {
705
0
    auto Out = Ctx.out();
706
0
    auto S = Specs;
707
0
#if FMT_VERSION >= 110100
708
0
    detail::handle_dynamic_spec(S.dynamic_width(), S.width, S.width_ref, Ctx);
709
0
    detail::handle_dynamic_spec(S.dynamic_precision(), S.precision,
710
0
                                S.precision_ref, Ctx);
711
#else
712
    detail::handle_dynamic_spec<detail::width_checker>(S.width, S.width_ref,
713
                                                       Ctx);
714
    detail::handle_dynamic_spec<detail::precision_checker>(
715
        S.precision, S.precision_ref, Ctx);
716
#endif
717
718
0
    const detail::uint128_t U =
719
0
        (detail::uint128_t{static_cast<uint64_t>(V >> 64)} << 64) |
720
0
        detail::uint128_t{static_cast<uint64_t>(V)};
721
0
#if FMT_VERSION >= 110100
722
0
    return detail::write_int<Char>(Out, detail::make_write_int_arg(U, S.sign()),
723
0
                                   S);
724
#else
725
    return detail::write_int<Char>(Out, detail::make_write_int_arg(U, S.sign),
726
                                   S, Ctx.locale());
727
#endif
728
0
  }
729
};
730
#else
731
template <typename Char> struct formatter<WasmEdge::uint128, Char> {
732
private:
733
  Char Fill = static_cast<Char>(' ');
734
  char Align = '\0';
735
  bool Alt = false;
736
  bool ZeroPad = false;
737
  unsigned int Width = 0U;
738
  char Type = '\0';
739
740
public:
741
  template <typename ParseContext>
742
  constexpr auto parse(ParseContext &Ctx) -> decltype(Ctx.begin()) {
743
    auto It = Ctx.begin();
744
    const auto End = Ctx.end();
745
    if (It == End || *It == static_cast<Char>('}')) {
746
      return It;
747
    }
748
    const auto IsAlign = [](Char C) {
749
      return C == static_cast<Char>('<') || C == static_cast<Char>('>') ||
750
             C == static_cast<Char>('^');
751
    };
752
    auto Next = It;
753
    ++Next;
754
    if (Next != End && IsAlign(*Next)) {
755
      Fill = *It;
756
      Align = static_cast<char>(*Next);
757
      It = Next;
758
      ++It;
759
    } else if (IsAlign(*It)) {
760
      Align = static_cast<char>(*It);
761
      ++It;
762
    }
763
    if (It != End && *It == static_cast<Char>('#')) {
764
      Alt = true;
765
      ++It;
766
    }
767
    if (It != End && *It == static_cast<Char>('0')) {
768
      ZeroPad = true;
769
      ++It;
770
    }
771
    while (It != End && *It >= static_cast<Char>('0') &&
772
           *It <= static_cast<Char>('9')) {
773
      Width =
774
          Width * 10U + static_cast<unsigned int>(*It - static_cast<Char>('0'));
775
      ++It;
776
    }
777
    if (It != End && *It != static_cast<Char>('}')) {
778
      Type = static_cast<char>(*It);
779
      ++It;
780
    }
781
    return It;
782
  }
783
784
  template <typename FormatContext>
785
  auto format(WasmEdge::uint128 V, FormatContext &Ctx) -> decltype(Ctx.out()) {
786
    const bool IsZeroValue = (V == WasmEdge::uint128(0U));
787
    unsigned int Base = 10U;
788
    const char *DigitChars = "0123456789abcdef";
789
    char Prefix[2] = {'\0', '\0'};
790
    switch (Type) {
791
    case 'X':
792
      DigitChars = "0123456789ABCDEF";
793
      [[fallthrough]];
794
    case 'x':
795
      Base = 16U;
796
      if (Alt) {
797
        Prefix[0] = '0';
798
        Prefix[1] = (Type == 'X') ? 'X' : 'x';
799
      }
800
      break;
801
    case 'B':
802
    case 'b':
803
      Base = 2U;
804
      if (Alt) {
805
        Prefix[0] = '0';
806
        Prefix[1] = (Type == 'B') ? 'B' : 'b';
807
      }
808
      break;
809
    case 'o':
810
      Base = 8U;
811
      if (Alt && !IsZeroValue) {
812
        Prefix[0] = '0';
813
      }
814
      break;
815
    default:
816
      break;
817
    }
818
819
    char Buf[130];
820
    char *Pos = Buf + sizeof(Buf);
821
    const WasmEdge::uint128 BaseV(Base);
822
    do {
823
      *--Pos = DigitChars[static_cast<unsigned int>((V % BaseV).low())];
824
      V /= BaseV;
825
    } while (V != WasmEdge::uint128(0U));
826
827
    const unsigned int NumDigits =
828
        static_cast<unsigned int>(Buf + sizeof(Buf) - Pos);
829
    const unsigned int PrefixLen =
830
        (Prefix[0] != '\0') ? (Prefix[1] != '\0' ? 2U : 1U) : 0U;
831
    const unsigned int CoreLen = PrefixLen + NumDigits;
832
833
    auto Out = Ctx.out();
834
    const auto WritePrefix = [&]() {
835
      for (unsigned int I = 0U; I < PrefixLen; ++I) {
836
        *Out++ = Prefix[I];
837
      }
838
    };
839
    const auto WriteDigits = [&]() {
840
      for (const char *It = Pos; It != Buf + sizeof(Buf); ++It) {
841
        *Out++ = *It;
842
      }
843
    };
844
    const auto WriteFill = [&](unsigned int Count) {
845
      for (unsigned int I = 0U; I < Count; ++I) {
846
        *Out++ = Fill;
847
      }
848
    };
849
850
    if (Width <= CoreLen) {
851
      WritePrefix();
852
      WriteDigits();
853
      return Out;
854
    }
855
856
    const unsigned int Pad = Width - CoreLen;
857
    if (ZeroPad && Align == '\0') {
858
      WritePrefix();
859
      for (unsigned int I = 0U; I < Pad; ++I) {
860
        *Out++ = '0';
861
      }
862
      WriteDigits();
863
      return Out;
864
    }
865
866
    const char Alignment = (Align == '\0') ? '>' : Align;
867
    if (Alignment == '<') {
868
      WritePrefix();
869
      WriteDigits();
870
      WriteFill(Pad);
871
    } else if (Alignment == '^') {
872
      const unsigned int Left = Pad / 2U;
873
      WriteFill(Left);
874
      WritePrefix();
875
      WriteDigits();
876
      WriteFill(Pad - Left);
877
    } else {
878
      WriteFill(Pad);
879
      WritePrefix();
880
      WriteDigits();
881
    }
882
    return Out;
883
  }
884
};
885
#endif
886
FMT_END_NAMESPACE