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/module.hpp"
8
9#include <type_traits>
10#include <cmath>
11
12#if HI_PROCESSOR == HI_CPU_X64
13#include <immintrin.h>
14#endif
15
16#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
17#include <intrin.h>
18#pragma intrinsic(_mul128)
19#endif
20
21namespace hi::inline v1 {
22
23template<typename T, typename U>
24inline bool convert_overflow(T x, U *r)
25{
26 static_assert(std::is_integral_v<U>, "convert_overflow() requires integral return type.");
27 static_assert(
28 std::is_integral_v<T> || std::is_floating_point_v<T>, "convert_overflow() requires float or integral argument type.");
29
30 if constexpr (std::is_integral_v<T>) {
31 // Optimized away when is_same_v<T,U>
32 *r = static_cast<U>(x);
33 return *r != x;
34 } else {
35 *r = static_cast<U>(std::llround(x));
36 return x < std::numeric_limits<U>::min() || x > std::numeric_limits<U>::max();
37 }
38}
39
40template<typename T>
41inline bool add_overflow(T lhs, T rhs, T *r)
42{
43 static_assert(std::is_integral_v<T>, "add_overflow() requires integral arguments.");
44
45 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
46 // ADD, JO
47 return __builtin_add_overflow(lhs, rhs, r);
48
49 } else if constexpr (std::is_unsigned_v<T>) {
50 // LEA, CMP, JB
51 *r = lhs + rhs;
52 return *r < lhs;
53
54 } else {
55 // LEA,XOR,XOR,TEST,JS
56 hilet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
57 hilet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
58 hilet r_ = lhs_ + rhs_;
59 *r = static_cast<T>(r_);
60 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
61 }
62}
63
64template<typename T>
65inline bool sub_overflow(T lhs, T rhs, T *r)
66{
67 static_assert(std::is_integral_v<T>, "sub_overflow() requires integral arguments.");
68
69 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
70 // SUB, JB
71 return __builtin_sub_overflow(lhs, rhs, r);
72
73 } else if constexpr (std::is_unsigned_v<T>) {
74 // MOV, SUB, CMP, JA
75 *r = lhs - rhs;
76 return *r > lhs;
77
78 } else {
79 // SUB, NOT, XOR, XOR, TEST, JL
80 hilet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
81 hilet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
82 hilet r_ = lhs_ - rhs_;
83 *r = static_cast<T>(r_);
84 return ((lhs ^ rhs) & (~rhs ^ *r)) < 0;
85 }
86}
87
91template<typename T>
92inline bool mul_overflow(T lhs, T rhs, T *r) noexcept
93{
94 static_assert(std::is_integral_v<T>, "mul_overflow() requires integral arguments.");
95
96 if constexpr (compiler::current == compiler::gcc || compiler::current == compiler::clang) {
97 return __builtin_mul_overflow(lhs, rhs, r);
98
99 } else if constexpr (std::is_signed_v<T> && compiler::current == compiler::msvc && sizeof(T) == sizeof(long long)) {
100 // IMUL, SAR, XOR, JNE
101 long long hi = 0;
102 *r = _mul128(lhs, rhs, &hi);
103
104 // Sign bit in *r should match all bits in hi.
105 return (hi ^ (*r >> 63)) != 0;
106
107 } else if constexpr (
108 std::is_unsigned_v<T> && compiler::current == compiler::msvc && sizeof(T) == sizeof(unsigned long long)) {
109 unsigned long long hi = 0;
110 *r = _umul128(lhs, rhs, &hi);
111 return hi > 0;
112
113 } else if constexpr (sizeof(T) <= (sizeof(make_intmax_t<T>) / 2)) {
114 // MOVSX, MOVSX, IMUL, MOVSX, CMP, JNE
115 hilet lhs_ = static_cast<make_intmax_t<T>>(lhs);
116 hilet rhs_ = static_cast<make_intmax_t<T>>(rhs);
117 hilet r_ = lhs_ * rhs_;
118 *r = static_cast<T>(r_);
119 return *r != r_;
120
121 } else {
123 }
124}
125
126} // namespace hi::inline v1
#define hi_not_implemented(...)
This part of the code has not been implemented yet.
Definition assert.hpp:335
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
bool mul_overflow(T lhs, T rhs, T *r) noexcept
Multiply with overflow detection.
Definition int_overflow.hpp:92
geometry/margins.hpp
Definition cache.hpp:11
T llround(T... args)