Coverage Report

Created: 2026-06-30 06:10

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 defined(_MSC_VER) && !defined(__clang__)
33
0
  if (V) {
34
0
    unsigned long LeadingZero = 0;
35
0
    _BitScanReverse(&LeadingZero, V);
36
0
    return 31 ^ static_cast<int>(LeadingZero);
37
0
  }
38
0
  return 32;
39
0
#else
40
0
  return __builtin_clz(V);
41
0
#endif
42
0
}
43
44
0
inline constexpr int clz(uint64_t V) noexcept {
45
0
#if defined(_MSC_VER) && !defined(__clang__)
46
0
  if (V) {
47
0
    unsigned long LeadingZero = 0;
48
0
    _BitScanReverse64(&LeadingZero, V);
49
0
    return 63 ^ static_cast<int>(LeadingZero);
50
0
  }
51
0
  return 64;
52
0
#else
53
0
  return __builtin_clzll(V);
54
0
#endif
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
    return uint128(Value.Low << (Shift - 64), 0);
325
0
  }
326
  friend constexpr uint128 operator>>(uint128 Value,
327
0
                                      unsigned int Shift) noexcept {
328
0
    if (Shift < 64) {
329
0
      if (Shift != 0) {
330
0
        return uint128((Value.High >> Shift),
331
0
                       Value.Low >> Shift | (Value.High << (64 - Shift)));
332
0
      }
333
0
      return Value;
334
0
    }
335
0
    return uint128(0, Value.High >> (Shift - 64));
336
0
  }
337
0
  friend constexpr uint128 operator<<(uint128 Value, int Shift) noexcept {
338
0
    return Value << static_cast<unsigned int>(Shift);
339
0
  }
340
0
  friend constexpr uint128 operator>>(uint128 Value, int Shift) noexcept {
341
0
    return Value >> static_cast<unsigned int>(Shift);
342
0
  }
343
  friend constexpr uint128 operator<<(uint128 Value,
344
0
                                      unsigned long long Shift) noexcept {
345
0
    return Value << static_cast<unsigned int>(Shift);
346
0
  }
347
  friend constexpr uint128 operator>>(uint128 Value,
348
0
                                      unsigned long long Shift) noexcept {
349
0
    return Value >> static_cast<unsigned int>(Shift);
350
0
  }
351
352
0
  static constexpr uint128 numericMin() noexcept {
353
0
    return uint128(std::numeric_limits<uint64_t>::min(),
354
0
                   std::numeric_limits<uint64_t>::min());
355
0
  }
356
0
  static constexpr uint128 numericMax() noexcept {
357
0
    return uint128(std::numeric_limits<uint64_t>::max(),
358
0
                   std::numeric_limits<uint64_t>::max());
359
0
  }
360
361
0
  constexpr uint64_t low() const noexcept { return Low; }
362
0
  constexpr uint64_t high() const noexcept { return High; }
363
0
  constexpr unsigned int clz() const noexcept {
364
0
    if (High) {
365
0
      return static_cast<unsigned int>(WasmEdge::clz(High));
366
0
    }
367
0
    if (Low) {
368
0
      return static_cast<unsigned int>(WasmEdge::clz(Low)) + 64U;
369
0
    }
370
0
    return 128U;
371
0
  }
372
373
private:
374
  uint64_t Low;
375
  uint64_t High;
376
};
377
378
class int128 {
379
public:
380
  int128() noexcept = default;
381
  constexpr int128(const int128 &) noexcept = default;
382
  constexpr int128(int128 &&) noexcept = default;
383
  constexpr int128 &operator=(const int128 &V) noexcept = default;
384
  constexpr int128 &operator=(int128 &&V) noexcept = default;
385
386
  constexpr int128(int V) noexcept
387
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
388
  constexpr int128(long V) noexcept
389
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
390
  constexpr int128(long long V) noexcept
391
0
      : Low(static_cast<uint64_t>(V)), High(V < 0 ? INT64_C(-1) : INT64_C(0)) {}
392
0
  constexpr int128(unsigned int V) noexcept : Low(V), High(INT64_C(0)) {}
393
0
  constexpr int128(unsigned long V) noexcept : Low(V), High(INT64_C(0)) {}
394
0
  constexpr int128(unsigned long long V) noexcept : Low(V), High(INT64_C(0)) {}
395
  constexpr int128(uint128 V) noexcept;
396
0
  constexpr int128(int64_t H, uint64_t L) noexcept : Low(L), High(H) {}
397
#if defined(__x86_64__) || defined(__aarch64__) ||                             \
398
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
399
  constexpr int128(__int128 V) noexcept
400
0
      : Low(static_cast<uint64_t>(V)), High(V >> 64) {}
401
#endif
402
403
0
  constexpr int128 &operator=(int V) noexcept { return *this = int128(V); }
404
0
  constexpr int128 &operator=(long V) noexcept { return *this = int128(V); }
405
0
  constexpr int128 &operator=(long long V) noexcept {
406
0
    return *this = int128(V);
407
0
  }
408
0
  constexpr int128 &operator=(unsigned int V) noexcept {
409
0
    return *this = int128(V);
410
0
  }
411
0
  constexpr int128 &operator=(unsigned long V) noexcept {
412
0
    return *this = int128(V);
413
0
  }
414
0
  constexpr int128 &operator=(unsigned long long V) noexcept {
415
0
    return *this = int128(V);
416
0
  }
417
418
  constexpr int128 &operator=(uint128 V) noexcept;
419
420
0
  static constexpr int128 numericMin() noexcept {
421
0
    return int128(std::numeric_limits<int64_t>::min(), 0);
422
0
  }
423
0
  static constexpr int128 numericMax() noexcept {
424
0
    return int128(std::numeric_limits<int64_t>::max(),
425
0
                  std::numeric_limits<uint64_t>::max());
426
0
  }
427
428
0
  constexpr uint64_t low() const noexcept { return Low; }
429
0
  constexpr int64_t high() const noexcept { return High; }
430
431
private:
432
  uint64_t Low;
433
  int64_t High;
434
};
435
436
inline constexpr uint128::uint128(int128 V) noexcept
437
    : Low(V.low()), High(static_cast<uint64_t>(V.high())) {}
438
439
0
inline constexpr uint128 &uint128::operator=(int128 V) noexcept {
440
0
  return *this = uint128(V);
441
0
}
442
443
inline constexpr int128::int128(uint128 V) noexcept
444
    : Low(V.low()), High(static_cast<int64_t>(V.high())) {}
445
446
0
inline constexpr int128 &int128::operator=(uint128 V) noexcept {
447
0
  return *this = int128(V);
448
0
}
449
450
} // namespace WasmEdge
451
452
namespace std {
453
template <> class numeric_limits<WasmEdge::uint128> {
454
public:
455
  static constexpr bool is_specialized = true;
456
  static constexpr bool is_signed = false;
457
  static constexpr bool is_integer = true;
458
  static constexpr bool is_exact = true;
459
  static constexpr bool has_infinity = false;
460
  static constexpr bool has_quiet_NaN = false;
461
  static constexpr bool has_signaling_NaN = false;
462
  static constexpr float_denorm_style has_denorm = denorm_absent;
463
  static constexpr bool has_denorm_loss = false;
464
  static constexpr float_round_style round_style = round_toward_zero;
465
  static constexpr bool is_iec559 = false;
466
  static constexpr bool is_bounded = true;
467
  static constexpr bool is_modulo = false;
468
  static constexpr int digits = 127;
469
  static constexpr int digits10 = 38;
470
  static constexpr int max_digits10 = 0;
471
  static constexpr int radix = 2;
472
  static constexpr int min_exponent = 0;
473
  static constexpr int min_exponent10 = 0;
474
  static constexpr int max_exponent = 0;
475
  static constexpr int max_exponent10 = 0;
476
  static constexpr bool traps = numeric_limits<uint64_t>::traps;
477
  static constexpr bool tinyness_before = false;
478
479
0
  static constexpr WasmEdge::uint128 min() {
480
0
    return WasmEdge::uint128::numericMin();
481
0
  }
482
0
  static constexpr WasmEdge::uint128 lowest() {
483
0
    return WasmEdge::uint128::numericMin();
484
0
  }
485
0
  static constexpr WasmEdge::uint128 max() {
486
0
    return WasmEdge::uint128::numericMax();
487
0
  }
488
0
  static constexpr WasmEdge::uint128 epsilon() { return 0U; }
489
0
  static constexpr WasmEdge::uint128 round_error() { return 0U; }
490
0
  static constexpr WasmEdge::uint128 infinity() { return 0U; }
491
0
  static constexpr WasmEdge::uint128 quiet_NaN() { return 0U; }
492
0
  static constexpr WasmEdge::uint128 signaling_NaN() { return 0U; }
493
0
  static constexpr WasmEdge::uint128 denorm_min() { return 0U; }
494
};
495
template <> class numeric_limits<WasmEdge::int128> {
496
public:
497
  static constexpr bool is_specialized = true;
498
  static constexpr bool is_signed = true;
499
  static constexpr bool is_integer = true;
500
  static constexpr bool is_exact = true;
501
  static constexpr bool has_infinity = false;
502
  static constexpr bool has_quiet_NaN = false;
503
  static constexpr bool has_signaling_NaN = false;
504
  static constexpr float_denorm_style has_denorm = denorm_absent;
505
  static constexpr bool has_denorm_loss = false;
506
  static constexpr float_round_style round_style = round_toward_zero;
507
  static constexpr bool is_iec559 = false;
508
  static constexpr bool is_bounded = true;
509
  static constexpr bool is_modulo = false;
510
  static constexpr int digits = 127;
511
  static constexpr int digits10 = 38;
512
  static constexpr int max_digits10 = 0;
513
  static constexpr int radix = 2;
514
  static constexpr int min_exponent = 0;
515
  static constexpr int min_exponent10 = 0;
516
  static constexpr int max_exponent = 0;
517
  static constexpr int max_exponent10 = 0;
518
  static constexpr bool traps = numeric_limits<uint64_t>::traps;
519
  static constexpr bool tinyness_before = false;
520
521
0
  static constexpr WasmEdge::int128 min() {
522
0
    return WasmEdge::int128::numericMin();
523
0
  }
524
0
  static constexpr WasmEdge::int128 lowest() {
525
0
    return WasmEdge::int128::numericMin();
526
0
  }
527
0
  static constexpr WasmEdge::int128 max() {
528
0
    return WasmEdge::int128::numericMax();
529
0
  }
530
0
  static constexpr WasmEdge::int128 epsilon() { return 0; }
531
0
  static constexpr WasmEdge::int128 round_error() { return 0; }
532
0
  static constexpr WasmEdge::int128 infinity() { return 0; }
533
0
  static constexpr WasmEdge::int128 quiet_NaN() { return 0; }
534
0
  static constexpr WasmEdge::int128 signaling_NaN() { return 0; }
535
0
  static constexpr WasmEdge::int128 denorm_min() { return 0; }
536
};
537
} // namespace std
538
539
namespace WasmEdge {
540
// If there is a built-in type __int128, then use it directly
541
#if defined(__x86_64__) || defined(__aarch64__) ||                             \
542
    (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__)
543
using int128_t = __int128;
544
using uint128_t = unsigned __int128;
545
#else
546
using int128_t = int128;
547
using uint128_t = uint128;
548
#endif
549
} // namespace WasmEdge
550
551
#include <fmt/format.h>
552
553
FMT_BEGIN_NAMESPACE
554
#if FMT_VERSION >= 90000
555
namespace detail {
556
#if FMT_VERSION >= 120200
557
using uint128_fallback = uint128;
558
#endif
559
inline constexpr bool operator>=(detail::uint128_fallback LHS,
560
0
                                 unsigned int RHS) {
561
0
  return LHS.high() != 0 || LHS.low() >= static_cast<uint64_t>(RHS);
562
0
}
563
564
inline constexpr bool operator<(detail::uint128_fallback LHS,
565
0
                                unsigned int RHS) {
566
0
  return LHS.high() == 0 && LHS.low() < static_cast<uint64_t>(RHS);
567
0
}
568
569
inline constexpr bool operator<(detail::uint128_fallback LHS,
570
0
                                detail::uint128_fallback RHS) {
571
0
  return LHS.high() < RHS.high() ||
572
0
         (LHS.high() == RHS.high() && LHS.low() < RHS.low());
573
0
}
574
575
inline constexpr detail::uint128_fallback
576
0
operator+(detail::uint128_fallback LHS, unsigned int RHS) {
577
0
  uint64_t NewLow = LHS.low() + RHS;
578
0
  uint64_t NewHigh = LHS.high() + (NewLow < LHS.low());
579
0
  return {NewHigh, NewLow};
580
0
}
581
582
inline constexpr detail::uint128_fallback
583
0
operator-(unsigned int LHS, detail::uint128_fallback RHS) {
584
0
  detail::uint128_fallback Negated = {~RHS.high(), ~RHS.low()};
585
0
  return Negated + 1 + LHS;
586
0
}
587
588
inline constexpr detail::uint128_fallback &
589
0
operator/=(detail::uint128_fallback &LHS, unsigned int RHSi) {
590
0
  const uint64_t RHS = static_cast<uint64_t>(RHSi);
591
0
  if (LHS.high() == 0 && LHS.low() < RHS) {
592
0
    LHS = 0;
593
0
    return LHS;
594
0
  }
595
0
  if (LHS.high() < RHS) {
596
0
    uint64_t Rem = 0;
597
0
    uint64_t QLo = WasmEdge::udiv128by64to64(LHS.high(), LHS.low(), RHS, Rem);
598
0
    LHS = QLo;
599
0
    return LHS;
600
0
  }
601
0
  uint64_t QHi = LHS.high() / RHS;
602
0
  uint64_t Rem = 0;
603
0
  uint64_t QLo =
604
0
      WasmEdge::udiv128by64to64(LHS.high() % RHS, LHS.low(), RHS, Rem);
605
0
  LHS = (detail::uint128_t{QHi} << 64u) | QLo;
606
0
  return LHS;
607
0
}
608
609
inline constexpr detail::uint128_fallback
610
0
operator%(detail::uint128_fallback LHS, unsigned int RHSi) {
611
0
  const uint64_t RHS = static_cast<uint64_t>(RHSi);
612
0
  if (LHS.high() == 0 && LHS.low() < RHS) {
613
0
    return LHS;
614
0
  }
615
0
  uint64_t Rem = 0;
616
0
  WasmEdge::udiv128by64to64(LHS.high() % RHS, LHS.low(), RHS, Rem);
617
0
  return Rem;
618
0
}
619
620
0
inline int do_count_digits(detail::uint128_fallback N) {
621
0
  const uint64_t Low = static_cast<uint64_t>(N);
622
0
  const uint64_t High = static_cast<uint64_t>(N >> 64);
623
0
  if (High == 0) {
624
0
    return detail::count_digits(Low);
625
0
  }
626
0
  // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
627
0
  static constexpr uint8_t Bsr2Log10[] = {
628
0
      20, 20, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25,
629
0
      25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29,
630
0
      30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 34, 34, 34,
631
0
      35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39};
632
0
  auto C = WasmEdge::clz(High);
633
0
  auto T = Bsr2Log10[C ^ 63];
634
0
  static constexpr const uint128_t PowersOf10[] = {
635
0
      0,
636
0
      (uint128_t(5ULL) << 64) | uint128_t(7766279631452241920ULL),
637
0
      (uint128_t(54ULL) << 64) | uint128_t(3875820019684212736ULL),
638
0
      (uint128_t(542ULL) << 64) | uint128_t(1864712049423024128ULL),
639
0
      (uint128_t(5421ULL) << 64) | uint128_t(200376420520689664ULL),
640
0
      (uint128_t(54210ULL) << 64) | uint128_t(2003764205206896640ULL),
641
0
      (uint128_t(542101ULL) << 64) | uint128_t(1590897978359414784ULL),
642
0
      (uint128_t(5421010ULL) << 64) | uint128_t(15908979783594147840ULL),
643
0
      (uint128_t(54210108ULL) << 64) | uint128_t(11515845246265065472ULL),
644
0
      (uint128_t(542101086ULL) << 64) | uint128_t(4477988020393345024ULL),
645
0
      (uint128_t(5421010862ULL) << 64) | uint128_t(7886392056514347008ULL),
646
0
      (uint128_t(54210108624ULL) << 64) | uint128_t(5076944270305263616ULL),
647
0
      (uint128_t(542101086242ULL) << 64) | uint128_t(13875954555633532928ULL),
648
0
      (uint128_t(5421010862427ULL) << 64) | uint128_t(9632337040368467968ULL),
649
0
      (uint128_t(54210108624275ULL) << 64) | uint128_t(4089650035136921600ULL),
650
0
      (uint128_t(542101086242752ULL) << 64) | uint128_t(4003012203950112768ULL),
651
0
      (uint128_t(5421010862427522ULL) << 64) |
652
0
          uint128_t(3136633892082024448ULL),
653
0
      (uint128_t(54210108624275221ULL) << 64) |
654
0
          uint128_t(12919594847110692864ULL),
655
0
      (uint128_t(542101086242752217ULL) << 64) |
656
0
          uint128_t(68739955140067328ULL),
657
0
      (uint128_t(5421010862427522170ULL) << 64) |
658
0
          uint128_t(687399551400673280ULL),
659
0
  };
660
0
  return T - (N < PowersOf10[T - 20]);
661
0
}
662
663
0
FMT_CONSTEXPR20 inline int count_digits(detail::uint128_fallback N) {
664
0
  if (!is_constant_evaluated()) {
665
0
    return do_count_digits(N);
666
0
  }
667
0
  return count_digits_fallback(N);
668
0
}
669
670
} // namespace detail
671
#endif
672
673
#if FMT_VERSION >= 80000
674
template <typename Char> struct formatter<WasmEdge::uint128, Char> {
675
private:
676
  detail::dynamic_format_specs<Char> Specs;
677
678
public:
679
0
  template <typename ParseContext> constexpr auto parse(ParseContext &Ctx) {
680
0
#if FMT_VERSION >= 100000
681
0
    return parse_format_specs(Ctx.begin(), Ctx.end(), Specs, Ctx,
682
0
                              detail::type::uint_type);
683
#else
684
    using HandlerType = detail::dynamic_specs_handler<ParseContext>;
685
    detail::specs_checker<HandlerType> Handler(HandlerType(Specs, Ctx),
686
                                               detail::type::uint_type);
687
    return parse_format_specs(Ctx.begin(), Ctx.end(), Handler);
688
#endif
689
0
  }
690
691
  template <typename FormatContext>
692
0
  auto format(WasmEdge::uint128 V, FormatContext &Ctx) const {
693
0
    auto Out = Ctx.out();
694
0
    auto S = Specs;
695
#if FMT_VERSION >= 110100
696
    detail::handle_dynamic_spec(S.dynamic_width(), S.width, S.width_ref, Ctx);
697
    detail::handle_dynamic_spec(S.dynamic_precision(), S.precision,
698
                                S.precision_ref, Ctx);
699
#else
700
0
    detail::handle_dynamic_spec<detail::width_checker>(S.width, S.width_ref,
701
0
                                                       Ctx);
702
0
    detail::handle_dynamic_spec<detail::precision_checker>(
703
0
        S.precision, S.precision_ref, Ctx);
704
0
#endif
705
706
0
    const detail::uint128_t U =
707
0
        (detail::uint128_t{static_cast<uint64_t>(V >> 64)} << 64) |
708
0
        detail::uint128_t{static_cast<uint64_t>(V)};
709
#if FMT_VERSION >= 110100
710
    return detail::write_int<Char>(Out, detail::make_write_int_arg(U, S.sign()),
711
                                   S);
712
#else
713
0
    return detail::write_int<Char>(Out, detail::make_write_int_arg(U, S.sign),
714
0
                                   S, Ctx.locale());
715
0
#endif
716
0
  }
717
};
718
#else
719
template <typename Char> struct formatter<WasmEdge::uint128, Char> {
720
private:
721
  Char Fill = static_cast<Char>(' ');
722
  char Align = '\0';
723
  bool Alt = false;
724
  bool ZeroPad = false;
725
  unsigned int Width = 0U;
726
  char Type = '\0';
727
728
public:
729
  template <typename ParseContext>
730
  constexpr auto parse(ParseContext &Ctx) -> decltype(Ctx.begin()) {
731
    auto It = Ctx.begin();
732
    const auto End = Ctx.end();
733
    if (It == End || *It == static_cast<Char>('}')) {
734
      return It;
735
    }
736
    const auto IsAlign = [](Char C) {
737
      return C == static_cast<Char>('<') || C == static_cast<Char>('>') ||
738
             C == static_cast<Char>('^');
739
    };
740
    auto Next = It;
741
    ++Next;
742
    if (Next != End && IsAlign(*Next)) {
743
      Fill = *It;
744
      Align = static_cast<char>(*Next);
745
      It = Next;
746
      ++It;
747
    } else if (IsAlign(*It)) {
748
      Align = static_cast<char>(*It);
749
      ++It;
750
    }
751
    if (It != End && *It == static_cast<Char>('#')) {
752
      Alt = true;
753
      ++It;
754
    }
755
    if (It != End && *It == static_cast<Char>('0')) {
756
      ZeroPad = true;
757
      ++It;
758
    }
759
    while (It != End && *It >= static_cast<Char>('0') &&
760
           *It <= static_cast<Char>('9')) {
761
      Width =
762
          Width * 10U + static_cast<unsigned int>(*It - static_cast<Char>('0'));
763
      ++It;
764
    }
765
    if (It != End && *It != static_cast<Char>('}')) {
766
      Type = static_cast<char>(*It);
767
      ++It;
768
    }
769
    return It;
770
  }
771
772
  template <typename FormatContext>
773
  auto format(WasmEdge::uint128 V, FormatContext &Ctx) -> decltype(Ctx.out()) {
774
    const bool IsZeroValue = (V == WasmEdge::uint128(0U));
775
    unsigned int Base = 10U;
776
    const char *DigitChars = "0123456789abcdef";
777
    char Prefix[2] = {'\0', '\0'};
778
    switch (Type) {
779
    case 'X':
780
      DigitChars = "0123456789ABCDEF";
781
      [[fallthrough]];
782
    case 'x':
783
      Base = 16U;
784
      if (Alt) {
785
        Prefix[0] = '0';
786
        Prefix[1] = (Type == 'X') ? 'X' : 'x';
787
      }
788
      break;
789
    case 'B':
790
    case 'b':
791
      Base = 2U;
792
      if (Alt) {
793
        Prefix[0] = '0';
794
        Prefix[1] = (Type == 'B') ? 'B' : 'b';
795
      }
796
      break;
797
    case 'o':
798
      Base = 8U;
799
      if (Alt && !IsZeroValue) {
800
        Prefix[0] = '0';
801
      }
802
      break;
803
    default:
804
      break;
805
    }
806
807
    char Buf[130];
808
    char *Pos = Buf + sizeof(Buf);
809
    const WasmEdge::uint128 BaseV(Base);
810
    do {
811
      *--Pos = DigitChars[static_cast<unsigned int>((V % BaseV).low())];
812
      V /= BaseV;
813
    } while (V != WasmEdge::uint128(0U));
814
815
    const unsigned int NumDigits =
816
        static_cast<unsigned int>(Buf + sizeof(Buf) - Pos);
817
    const unsigned int PrefixLen =
818
        (Prefix[0] != '\0') ? (Prefix[1] != '\0' ? 2U : 1U) : 0U;
819
    const unsigned int CoreLen = PrefixLen + NumDigits;
820
821
    auto Out = Ctx.out();
822
    const auto WritePrefix = [&]() {
823
      for (unsigned int I = 0U; I < PrefixLen; ++I) {
824
        *Out++ = Prefix[I];
825
      }
826
    };
827
    const auto WriteDigits = [&]() {
828
      for (const char *It = Pos; It != Buf + sizeof(Buf); ++It) {
829
        *Out++ = *It;
830
      }
831
    };
832
    const auto WriteFill = [&](unsigned int Count) {
833
      for (unsigned int I = 0U; I < Count; ++I) {
834
        *Out++ = Fill;
835
      }
836
    };
837
838
    if (Width <= CoreLen) {
839
      WritePrefix();
840
      WriteDigits();
841
      return Out;
842
    }
843
844
    const unsigned int Pad = Width - CoreLen;
845
    if (ZeroPad && Align == '\0') {
846
      WritePrefix();
847
      for (unsigned int I = 0U; I < Pad; ++I) {
848
        *Out++ = '0';
849
      }
850
      WriteDigits();
851
      return Out;
852
    }
853
854
    const char Alignment = (Align == '\0') ? '>' : Align;
855
    if (Alignment == '<') {
856
      WritePrefix();
857
      WriteDigits();
858
      WriteFill(Pad);
859
    } else if (Alignment == '^') {
860
      const unsigned int Left = Pad / 2U;
861
      WriteFill(Left);
862
      WritePrefix();
863
      WriteDigits();
864
      WriteFill(Pad - Left);
865
    } else {
866
      WriteFill(Pad);
867
      WritePrefix();
868
      WriteDigits();
869
    }
870
    return Out;
871
  }
872
};
873
#endif
874
FMT_END_NAMESPACE