File indexing completed on 2026-05-10 08:44:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_SUPPORT_MATHEXTRAS_H
0014 #define LLVM_SUPPORT_MATHEXTRAS_H
0015
0016 #include "llvm/ADT/bit.h"
0017 #include "llvm/Support/Compiler.h"
0018 #include <cassert>
0019 #include <climits>
0020 #include <cstdint>
0021 #include <cstring>
0022 #include <limits>
0023 #include <type_traits>
0024
0025 namespace llvm {
0026
0027
0028
0029
0030
0031 template <typename T, typename U>
0032 using enableif_int =
0033 std::enable_if_t<std::is_integral_v<T> && std::is_integral_v<U>>;
0034
0035
0036 template <typename T, typename U, typename = enableif_int<T, U>>
0037 using common_uint =
0038 std::common_type_t<std::make_unsigned_t<T>, std::make_unsigned_t<U>>;
0039 template <typename T, typename U, typename = enableif_int<T, U>>
0040 using common_sint =
0041 std::common_type_t<std::make_signed_t<T>, std::make_signed_t<U>>;
0042
0043
0044 namespace numbers {
0045
0046
0047 constexpr double e = 0x1.5bf0a8b145769P+1,
0048 egamma = 0x1.2788cfc6fb619P-1,
0049 ln2 = 0x1.62e42fefa39efP-1,
0050 ln10 = 0x1.26bb1bbb55516P+1,
0051 log2e = 0x1.71547652b82feP+0,
0052 log10e = 0x1.bcb7b1526e50eP-2,
0053 pi = 0x1.921fb54442d18P+1,
0054 inv_pi = 0x1.45f306dc9c883P-2,
0055 sqrtpi = 0x1.c5bf891b4ef6bP+0,
0056 inv_sqrtpi = 0x1.20dd750429b6dP-1,
0057 sqrt2 = 0x1.6a09e667f3bcdP+0,
0058 inv_sqrt2 = 0x1.6a09e667f3bcdP-1,
0059 sqrt3 = 0x1.bb67ae8584caaP+0,
0060 inv_sqrt3 = 0x1.279a74590331cP-1,
0061 phi = 0x1.9e3779b97f4a8P+0;
0062 constexpr float ef = 0x1.5bf0a8P+1F,
0063 egammaf = 0x1.2788d0P-1F,
0064 ln2f = 0x1.62e430P-1F,
0065 ln10f = 0x1.26bb1cP+1F,
0066 log2ef = 0x1.715476P+0F,
0067 log10ef = 0x1.bcb7b2P-2F,
0068 pif = 0x1.921fb6P+1F,
0069 inv_pif = 0x1.45f306P-2F,
0070 sqrtpif = 0x1.c5bf8aP+0F,
0071 inv_sqrtpif = 0x1.20dd76P-1F,
0072 sqrt2f = 0x1.6a09e6P+0F,
0073 inv_sqrt2f = 0x1.6a09e6P-1F,
0074 sqrt3f = 0x1.bb67aeP+0F,
0075 inv_sqrt3f = 0x1.279a74P-1F,
0076 phif = 0x1.9e377aP+0F;
0077
0078 }
0079
0080
0081
0082 template <typename T> T maskTrailingOnes(unsigned N) {
0083 static_assert(std::is_unsigned_v<T>, "Invalid type!");
0084 const unsigned Bits = CHAR_BIT * sizeof(T);
0085 assert(N <= Bits && "Invalid bit index");
0086 if (N == 0)
0087 return 0;
0088 return T(-1) >> (Bits - N);
0089 }
0090
0091
0092
0093 template <typename T> T maskLeadingOnes(unsigned N) {
0094 return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
0095 }
0096
0097
0098
0099 template <typename T> T maskTrailingZeros(unsigned N) {
0100 return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
0101 }
0102
0103
0104
0105 template <typename T> T maskLeadingZeros(unsigned N) {
0106 return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
0107 }
0108
0109
0110
0111
0112 static const unsigned char BitReverseTable256[256] = {
0113 #define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
0114 #define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
0115 #define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
0116 R6(0), R6(2), R6(1), R6(3)
0117 #undef R2
0118 #undef R4
0119 #undef R6
0120 };
0121
0122
0123 template <typename T> T reverseBits(T Val) {
0124 #if __has_builtin(__builtin_bitreverse8)
0125 if constexpr (std::is_same_v<T, uint8_t>)
0126 return __builtin_bitreverse8(Val);
0127 #endif
0128 #if __has_builtin(__builtin_bitreverse16)
0129 if constexpr (std::is_same_v<T, uint16_t>)
0130 return __builtin_bitreverse16(Val);
0131 #endif
0132 #if __has_builtin(__builtin_bitreverse32)
0133 if constexpr (std::is_same_v<T, uint32_t>)
0134 return __builtin_bitreverse32(Val);
0135 #endif
0136 #if __has_builtin(__builtin_bitreverse64)
0137 if constexpr (std::is_same_v<T, uint64_t>)
0138 return __builtin_bitreverse64(Val);
0139 #endif
0140
0141 unsigned char in[sizeof(Val)];
0142 unsigned char out[sizeof(Val)];
0143 std::memcpy(in, &Val, sizeof(Val));
0144 for (unsigned i = 0; i < sizeof(Val); ++i)
0145 out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
0146 std::memcpy(&Val, out, sizeof(Val));
0147 return Val;
0148 }
0149
0150
0151
0152
0153
0154
0155 constexpr uint32_t Hi_32(uint64_t Value) {
0156 return static_cast<uint32_t>(Value >> 32);
0157 }
0158
0159
0160 constexpr uint32_t Lo_32(uint64_t Value) {
0161 return static_cast<uint32_t>(Value);
0162 }
0163
0164
0165 constexpr uint64_t Make_64(uint32_t High, uint32_t Low) {
0166 return ((uint64_t)High << 32) | (uint64_t)Low;
0167 }
0168
0169
0170 template <unsigned N> constexpr bool isInt(int64_t x) {
0171 if constexpr (N == 0)
0172 return 0 == x;
0173 if constexpr (N == 8)
0174 return static_cast<int8_t>(x) == x;
0175 if constexpr (N == 16)
0176 return static_cast<int16_t>(x) == x;
0177 if constexpr (N == 32)
0178 return static_cast<int32_t>(x) == x;
0179 if constexpr (N < 64)
0180 return -(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1));
0181 (void)x;
0182 return true;
0183 }
0184
0185
0186 template <unsigned N, unsigned S>
0187 constexpr bool isShiftedInt(int64_t x) {
0188 static_assert(S < 64, "isShiftedInt<N, S> with S >= 64 is too much.");
0189 static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
0190 return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
0191 }
0192
0193
0194 template <unsigned N> constexpr bool isUInt(uint64_t x) {
0195 if constexpr (N == 0)
0196 return 0 == x;
0197 if constexpr (N == 8)
0198 return static_cast<uint8_t>(x) == x;
0199 if constexpr (N == 16)
0200 return static_cast<uint16_t>(x) == x;
0201 if constexpr (N == 32)
0202 return static_cast<uint32_t>(x) == x;
0203 if constexpr (N < 64)
0204 return x < (UINT64_C(1) << (N));
0205 (void)x;
0206 return true;
0207 }
0208
0209
0210 template <unsigned N, unsigned S>
0211 constexpr bool isShiftedUInt(uint64_t x) {
0212 static_assert(S < 64, "isShiftedUInt<N, S> with S >= 64 is too much.");
0213 static_assert(N + S <= 64,
0214 "isShiftedUInt<N, S> with N + S > 64 is too wide.");
0215
0216 return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
0217 }
0218
0219
0220 inline uint64_t maxUIntN(uint64_t N) {
0221 assert(N <= 64 && "integer width out of range");
0222
0223
0224
0225
0226
0227
0228
0229
0230 if (N == 0)
0231 return 0;
0232 return UINT64_MAX >> (64 - N);
0233 }
0234
0235
0236 inline int64_t minIntN(int64_t N) {
0237 assert(N <= 64 && "integer width out of range");
0238
0239 if (N == 0)
0240 return 0;
0241 return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
0242 }
0243
0244
0245 inline int64_t maxIntN(int64_t N) {
0246 assert(N <= 64 && "integer width out of range");
0247
0248
0249
0250 if (N == 0)
0251 return 0;
0252 return (UINT64_C(1) << (N - 1)) - 1;
0253 }
0254
0255
0256 inline bool isUIntN(unsigned N, uint64_t x) {
0257 return N >= 64 || x <= maxUIntN(N);
0258 }
0259
0260
0261 inline bool isIntN(unsigned N, int64_t x) {
0262 return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
0263 }
0264
0265
0266
0267
0268 constexpr bool isMask_32(uint32_t Value) {
0269 return Value && ((Value + 1) & Value) == 0;
0270 }
0271
0272
0273
0274 constexpr bool isMask_64(uint64_t Value) {
0275 return Value && ((Value + 1) & Value) == 0;
0276 }
0277
0278
0279
0280 constexpr bool isShiftedMask_32(uint32_t Value) {
0281 return Value && isMask_32((Value - 1) | Value);
0282 }
0283
0284
0285
0286 constexpr bool isShiftedMask_64(uint64_t Value) {
0287 return Value && isMask_64((Value - 1) | Value);
0288 }
0289
0290
0291
0292 constexpr bool isPowerOf2_32(uint32_t Value) {
0293 return llvm::has_single_bit(Value);
0294 }
0295
0296
0297 constexpr bool isPowerOf2_64(uint64_t Value) {
0298 return llvm::has_single_bit(Value);
0299 }
0300
0301
0302
0303
0304
0305
0306 inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
0307 unsigned &MaskLen) {
0308 if (!isShiftedMask_32(Value))
0309 return false;
0310 MaskIdx = llvm::countr_zero(Value);
0311 MaskLen = llvm::popcount(Value);
0312 return true;
0313 }
0314
0315
0316
0317
0318
0319 inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
0320 unsigned &MaskLen) {
0321 if (!isShiftedMask_64(Value))
0322 return false;
0323 MaskIdx = llvm::countr_zero(Value);
0324 MaskLen = llvm::popcount(Value);
0325 return true;
0326 }
0327
0328
0329
0330 template <size_t kValue> constexpr size_t CTLog2() {
0331 static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue),
0332 "Value is not a valid power of 2");
0333 return 1 + CTLog2<kValue / 2>();
0334 }
0335
0336 template <> constexpr size_t CTLog2<1>() { return 0; }
0337
0338
0339
0340
0341 inline unsigned Log2_32(uint32_t Value) {
0342 return 31 - llvm::countl_zero(Value);
0343 }
0344
0345
0346
0347 inline unsigned Log2_64(uint64_t Value) {
0348 return 63 - llvm::countl_zero(Value);
0349 }
0350
0351
0352
0353
0354 inline unsigned Log2_32_Ceil(uint32_t Value) {
0355 return 32 - llvm::countl_zero(Value - 1);
0356 }
0357
0358
0359
0360 inline unsigned Log2_64_Ceil(uint64_t Value) {
0361 return 64 - llvm::countl_zero(Value - 1);
0362 }
0363
0364
0365
0366 template <typename U, typename V, typename T = common_uint<U, V>>
0367 constexpr T MinAlign(U A, V B) {
0368
0369
0370
0371
0372
0373 return (A | B) & (1 + ~(A | B));
0374 }
0375
0376
0377 constexpr uint64_t MinAlign(uint64_t A, uint64_t B) {
0378 return (A | B) & (1 + ~(A | B));
0379 }
0380
0381
0382
0383 constexpr uint64_t NextPowerOf2(uint64_t A) {
0384 A |= (A >> 1);
0385 A |= (A >> 2);
0386 A |= (A >> 4);
0387 A |= (A >> 8);
0388 A |= (A >> 16);
0389 A |= (A >> 32);
0390 return A + 1;
0391 }
0392
0393
0394
0395 inline uint64_t PowerOf2Ceil(uint64_t A) {
0396 if (!A || A > UINT64_MAX / 2)
0397 return 0;
0398 return UINT64_C(1) << Log2_64_Ceil(A);
0399 }
0400
0401
0402
0403 template <typename U, typename V, typename T = common_uint<U, V>>
0404 constexpr T divideCeil(U Numerator, V Denominator) {
0405 assert(Denominator && "Division by zero");
0406 T Bias = (Numerator != 0);
0407 return (Numerator - Bias) / Denominator + Bias;
0408 }
0409
0410
0411 constexpr uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
0412 assert(Denominator && "Division by zero");
0413 uint64_t Bias = (Numerator != 0);
0414 return (Numerator - Bias) / Denominator + Bias;
0415 }
0416
0417
0418
0419 template <typename U, typename V>
0420 constexpr bool divideSignedWouldOverflow(U Numerator, V Denominator) {
0421 return Numerator == std::numeric_limits<U>::min() && Denominator == -1;
0422 }
0423
0424
0425
0426 template <typename U, typename V, typename T = common_sint<U, V>>
0427 constexpr T divideCeilSigned(U Numerator, V Denominator) {
0428 assert(Denominator && "Division by zero");
0429 assert(!divideSignedWouldOverflow(Numerator, Denominator) &&
0430 "Divide would overflow");
0431 if (!Numerator)
0432 return 0;
0433
0434 T Bias = Denominator >= 0 ? 1 : -1;
0435 bool SameSign = (Numerator >= 0) == (Denominator >= 0);
0436 return SameSign ? (Numerator - Bias) / Denominator + 1
0437 : Numerator / Denominator;
0438 }
0439
0440
0441
0442 template <typename U, typename V, typename T = common_sint<U, V>>
0443 constexpr T divideFloorSigned(U Numerator, V Denominator) {
0444 assert(Denominator && "Division by zero");
0445 assert(!divideSignedWouldOverflow(Numerator, Denominator) &&
0446 "Divide would overflow");
0447 if (!Numerator)
0448 return 0;
0449
0450 T Bias = Denominator >= 0 ? -1 : 1;
0451 bool SameSign = (Numerator >= 0) == (Denominator >= 0);
0452 return SameSign ? Numerator / Denominator
0453 : (Numerator - Bias) / Denominator - 1;
0454 }
0455
0456
0457
0458 template <typename U, typename V, typename T = common_sint<U, V>>
0459 constexpr T mod(U Numerator, V Denominator) {
0460 assert(Denominator >= 1 && "Mod by non-positive number");
0461 T Mod = Numerator % Denominator;
0462 return Mod < 0 ? Mod + Denominator : Mod;
0463 }
0464
0465
0466
0467 template <typename U, typename V, typename T = common_uint<U, V>>
0468 constexpr T divideNearest(U Numerator, V Denominator) {
0469 assert(Denominator && "Division by zero");
0470 T Mod = Numerator % Denominator;
0471 return (Numerator / Denominator) +
0472 (Mod > (static_cast<T>(Denominator) - 1) / 2);
0473 }
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487 template <typename U, typename V, typename T = common_uint<U, V>>
0488 constexpr T alignTo(U Value, V Align) {
0489 assert(Align != 0u && "Align can't be 0.");
0490 T CeilDiv = divideCeil(Value, Align);
0491 return CeilDiv * Align;
0492 }
0493
0494
0495 constexpr uint64_t alignTo(uint64_t Value, uint64_t Align) {
0496 assert(Align != 0u && "Align can't be 0.");
0497 uint64_t CeilDiv = divideCeil(Value, Align);
0498 return CeilDiv * Align;
0499 }
0500
0501
0502 template <typename U, typename V, typename T = common_uint<U, V>>
0503 constexpr T alignToPowerOf2(U Value, V Align) {
0504 assert(Align != 0 && (Align & (Align - 1)) == 0 &&
0505 "Align must be a power of 2");
0506 T NegAlign = static_cast<T>(0) - Align;
0507 return (Value + (Align - 1)) & NegAlign;
0508 }
0509
0510
0511 constexpr uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
0512 assert(Align != 0 && (Align & (Align - 1)) == 0 &&
0513 "Align must be a power of 2");
0514 uint64_t NegAlign = 0 - Align;
0515 return (Value + (Align - 1)) & NegAlign;
0516 }
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532 template <typename U, typename V, typename W,
0533 typename T = common_uint<common_uint<U, V>, W>>
0534 constexpr T alignTo(U Value, V Align, W Skew) {
0535 assert(Align != 0u && "Align can't be 0.");
0536 Skew %= Align;
0537 return alignTo(Value - Skew, Align) + Skew;
0538 }
0539
0540
0541
0542
0543
0544 template <auto Align, typename V, typename T = common_uint<decltype(Align), V>>
0545 constexpr T alignTo(V Value) {
0546 static_assert(Align != 0u, "Align must be non-zero");
0547 T CeilDiv = divideCeil(Value, Align);
0548 return CeilDiv * Align;
0549 }
0550
0551
0552
0553
0554 template <typename U, typename V, typename W = uint8_t,
0555 typename T = common_uint<common_uint<U, V>, W>>
0556 constexpr T alignDown(U Value, V Align, W Skew = 0) {
0557 assert(Align != 0u && "Align can't be 0.");
0558 Skew %= Align;
0559 return (Value - Skew) / Align * Align + Skew;
0560 }
0561
0562
0563
0564 template <unsigned B> constexpr int32_t SignExtend32(uint32_t X) {
0565 static_assert(B <= 32, "Bit width out of range.");
0566 if constexpr (B == 0)
0567 return 0;
0568 return int32_t(X << (32 - B)) >> (32 - B);
0569 }
0570
0571
0572
0573 inline int32_t SignExtend32(uint32_t X, unsigned B) {
0574 assert(B <= 32 && "Bit width out of range.");
0575 if (B == 0)
0576 return 0;
0577 return int32_t(X << (32 - B)) >> (32 - B);
0578 }
0579
0580
0581
0582 template <unsigned B> constexpr int64_t SignExtend64(uint64_t x) {
0583 static_assert(B <= 64, "Bit width out of range.");
0584 if constexpr (B == 0)
0585 return 0;
0586 return int64_t(x << (64 - B)) >> (64 - B);
0587 }
0588
0589
0590
0591 inline int64_t SignExtend64(uint64_t X, unsigned B) {
0592 assert(B <= 64 && "Bit width out of range.");
0593 if (B == 0)
0594 return 0;
0595 return int64_t(X << (64 - B)) >> (64 - B);
0596 }
0597
0598
0599
0600 template <typename U, typename V, typename T = common_uint<U, V>>
0601 constexpr T AbsoluteDifference(U X, V Y) {
0602 return X > Y ? (X - Y) : (Y - X);
0603 }
0604
0605
0606
0607
0608 template <typename T>
0609 std::enable_if_t<std::is_unsigned_v<T>, T>
0610 SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
0611 bool Dummy;
0612 bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
0613
0614 T Z = X + Y;
0615 Overflowed = (Z < X || Z < Y);
0616 if (Overflowed)
0617 return std::numeric_limits<T>::max();
0618 else
0619 return Z;
0620 }
0621
0622
0623
0624 template <class T, class... Ts>
0625 std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
0626 Ts... Args) {
0627 bool Overflowed = false;
0628 T XY = SaturatingAdd(X, Y, &Overflowed);
0629 if (Overflowed)
0630 return SaturatingAdd(std::numeric_limits<T>::max(), T(1), Args...);
0631 return SaturatingAdd(XY, Z, Args...);
0632 }
0633
0634
0635
0636
0637 template <typename T>
0638 std::enable_if_t<std::is_unsigned_v<T>, T>
0639 SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
0640 bool Dummy;
0641 bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
0642
0643
0644
0645
0646
0647
0648 Overflowed = false;
0649
0650
0651
0652
0653 int Log2Z = Log2_64(X) + Log2_64(Y);
0654 const T Max = std::numeric_limits<T>::max();
0655 int Log2Max = Log2_64(Max);
0656 if (Log2Z < Log2Max) {
0657 return X * Y;
0658 }
0659 if (Log2Z > Log2Max) {
0660 Overflowed = true;
0661 return Max;
0662 }
0663
0664
0665
0666
0667 T Z = (X >> 1) * Y;
0668 if (Z & ~(Max >> 1)) {
0669 Overflowed = true;
0670 return Max;
0671 }
0672 Z <<= 1;
0673 if (X & 1)
0674 return SaturatingAdd(Z, Y, ResultOverflowed);
0675
0676 return Z;
0677 }
0678
0679
0680
0681
0682
0683 template <typename T>
0684 std::enable_if_t<std::is_unsigned_v<T>, T>
0685 SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
0686 bool Dummy;
0687 bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
0688
0689 T Product = SaturatingMultiply(X, Y, &Overflowed);
0690 if (Overflowed)
0691 return Product;
0692
0693 return SaturatingAdd(A, Product, &Overflowed);
0694 }
0695
0696
0697 extern const float huge_valf;
0698
0699
0700
0701 template <typename T>
0702 std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y, T &Result) {
0703 #if __has_builtin(__builtin_add_overflow)
0704 return __builtin_add_overflow(X, Y, &Result);
0705 #else
0706
0707 using U = std::make_unsigned_t<T>;
0708 const U UX = static_cast<U>(X);
0709 const U UY = static_cast<U>(Y);
0710 const U UResult = UX + UY;
0711
0712
0713 Result = static_cast<T>(UResult);
0714
0715
0716 if (X > 0 && Y > 0)
0717 return Result <= 0;
0718
0719 if (X < 0 && Y < 0)
0720 return Result >= 0;
0721 return false;
0722 #endif
0723 }
0724
0725
0726
0727 template <typename T>
0728 std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y, T &Result) {
0729 #if __has_builtin(__builtin_sub_overflow)
0730 return __builtin_sub_overflow(X, Y, &Result);
0731 #else
0732
0733 using U = std::make_unsigned_t<T>;
0734 const U UX = static_cast<U>(X);
0735 const U UY = static_cast<U>(Y);
0736 const U UResult = UX - UY;
0737
0738
0739 Result = static_cast<T>(UResult);
0740
0741
0742 if (X <= 0 && Y > 0)
0743 return Result >= 0;
0744
0745 if (X >= 0 && Y < 0)
0746 return Result <= 0;
0747 return false;
0748 #endif
0749 }
0750
0751
0752
0753 template <typename T>
0754 std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
0755 #if __has_builtin(__builtin_mul_overflow)
0756 return __builtin_mul_overflow(X, Y, &Result);
0757 #else
0758
0759 using U = std::make_unsigned_t<T>;
0760 const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
0761 const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
0762 const U UResult = UX * UY;
0763
0764
0765 const bool IsNegative = (X < 0) ^ (Y < 0);
0766 Result = IsNegative ? (0 - UResult) : UResult;
0767
0768
0769 if (UX == 0 || UY == 0)
0770 return false;
0771
0772
0773
0774
0775 if (IsNegative)
0776 return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY;
0777 else
0778 return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY;
0779 #endif
0780 }
0781
0782
0783
0784 #if defined(__i386__) || defined(_M_IX86)
0785 using stack_float_t = volatile float;
0786 #else
0787 using stack_float_t = float;
0788 #endif
0789
0790 }
0791
0792 #endif