HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
int_overflow.hpp
1// Copyright Take Vos 2019, 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../utility/utility.hpp"
8#include "../macros.hpp"
9
10#include <type_traits>
11#include <cmath>
12
13#if HI_PROCESSOR == HI_CPU_X64
14#include <immintrin.h>
15#endif
16
17#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
18#include <intrin.h>
19#pragma intrinsic(_mul128)
20#endif
21
22hi_warning_push();
23// C4702 unreachable code: Suppressed due intrinsics and std::is_constant_evaluated()
24hi_warning_ignore_msvc(4702);
25
26namespace hi::inline v1 {
27
28template<typename T, typename U>
29inline bool convert_overflow(T x, U *r)
30{
31 static_assert(std::is_integral_v<U>, "convert_overflow() requires integral return type.");
32 static_assert(
33 std::is_integral_v<T> || std::is_floating_point_v<T>, "convert_overflow() requires float or integral argument type.");
34
35 if constexpr (std::is_integral_v<T>) {
36 // Optimized away when is_same_v<T,U>
37 *r = static_cast<U>(x);
38 return *r != x;
39 } else {
40 *r = static_cast<U>(std::llround(x));
42 }
43}
44
45template<typename T>
46inline bool add_overflow(T lhs, T rhs, T *r)
47{
48 static_assert(std::is_integral_v<T>, "add_overflow() requires integral arguments.");
49
50#if HI_COMPILER == HI_CC_GCC or HI_COMPILER == HI_CC_CLANG
51 // ADD, JO
52 return __builtin_add_overflow(lhs, rhs, r);
53#endif
54
55 if constexpr (std::is_unsigned_v<T>) {
56 // LEA, CMP, JB
57 *r = lhs + rhs;
58 return *r < lhs;
59
60 } else {
61 // LEA,XOR,XOR,TEST,JS
62 hilet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
63 hilet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
64 hilet r_ = lhs_ + rhs_;
65 *r = static_cast<T>(r_);
66 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
67 }
68}
69
70template<typename T>
71inline bool sub_overflow(T lhs, T rhs, T *r)
72{
73 static_assert(std::is_integral_v<T>, "sub_overflow() requires integral arguments.");
74
75#if HI_COMPILER == HI_CC_GCC or HI_COMPILER == HI_CC_CLANG
76 // SUB, JB
77 return __builtin_sub_overflow(lhs, rhs, r);
78#endif
79
80 if constexpr (std::is_unsigned_v<T>) {
81 // MOV, SUB, CMP, JA
82 *r = lhs - rhs;
83 return *r > lhs;
84
85 } else {
86 // SUB, NOT, XOR, XOR, TEST, JL
87 hilet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
88 hilet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
89 hilet r_ = lhs_ - rhs_;
90 *r = static_cast<T>(r_);
91 return ((lhs ^ rhs) & (~rhs ^ *r)) < 0;
92 }
93}
94
98template<typename T>
99inline bool mul_overflow(T lhs, T rhs, T *r) noexcept
100{
101 static_assert(std::is_integral_v<T>, "mul_overflow() requires integral arguments.");
102
103#if HI_COMPILER == HI_CC_GCC or HI_COMPILER == HI_CC_CLANG
104 return __builtin_mul_overflow(lhs, rhs, r);
105
106#elif HI_COMPILER == HI_CC_MSVC
107 if constexpr (std::is_signed_v<T> and sizeof(T) == sizeof(long long)) {
108 // IMUL, SAR, XOR, JNE
109 long long hi = 0;
110 *r = _mul128(lhs, rhs, &hi);
111
112 // Sign bit in *r should match all bits in hi.
113 return (hi ^ (*r >> 63)) != 0;
114
115 } else if constexpr (std::is_unsigned_v<T> and sizeof(T) == sizeof(unsigned long long)) {
116 unsigned long long hi = 0;
117 *r = _umul128(lhs, rhs, &hi);
118 return hi > 0;
119 }
120#endif
121
122 if constexpr (sizeof(T) <= (sizeof(make_intmax_t<T>) / 2)) {
123 // MOVSX, MOVSX, IMUL, MOVSX, CMP, JNE
124 hilet lhs_ = static_cast<make_intmax_t<T>>(lhs);
125 hilet rhs_ = static_cast<make_intmax_t<T>>(rhs);
126 hilet r_ = lhs_ * rhs_;
127 *r = static_cast<T>(r_);
128 return *r != r_;
129
130 } else {
131 hi_not_implemented();
132 }
133}
134
135} // namespace hi::inline v1
136
137hi_warning_pop();
DOXYGEN BUG.
Definition algorithm.hpp:16
bool mul_overflow(T lhs, T rhs, T *r) noexcept
Multiply with overflow detection.
Definition int_overflow.hpp:99
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
T llround(T... args)