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