HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
int_overflow.hpp
1// Copyright Take Vos 2019-2020.
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 "required.hpp"
8#include "os_detect.hpp"
9#include "type_traits.hpp"
10#include "assert.hpp"
11
12#include <type_traits>
13#include <cmath>
14
15#if TT_PROCESSOR == TT_CPU_X64
16#include <immintrin.h>
17#endif
18
19#if TT_OPERATING_SYSTEM == TT_OS_WINDOWS
20#include <intrin.h>
21#pragma intrinsic(_mul128)
22#endif
23
24namespace tt {
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(std::is_integral_v<T> || std::is_floating_point_v<T>, "convert_overflow() requires float or integral argument type.");
31
32 if constexpr (std::is_integral_v<T>) {
33 // Optimized away when is_same_v<T,U>
34 *r = static_cast<U>(x);
35 return *r != x;
36 } else {
37 *r = static_cast<U>(std::llround(x));
38 return x < std::numeric_limits<U>::min() || x > std::numeric_limits<U>::max();
39 }
40}
41
42template<typename T>
43inline bool add_overflow(T lhs, T rhs, T *r)
44{
45 static_assert(std::is_integral_v<T>, "add_overflow() requires integral arguments.");
46
47 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
48 // ADD, JO
49 return __builtin_add_overflow(lhs, rhs, r);
50
51 } else if constexpr (std::is_unsigned_v<T>) {
52 // LEA, CMP, JB
53 *r = lhs + rhs;
54 return *r < lhs;
55
56 } else {
57 // LEA,XOR,XOR,TEST,JS
58 ttlet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
59 ttlet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
60 ttlet r_ = lhs_ + rhs_;
61 *r = static_cast<T>(r_);
62 return ((lhs ^ *r) & (rhs ^ *r)) < 0;
63 }
64}
65
66template<typename T>
67inline bool sub_overflow(T lhs, T rhs, T *r)
68{
69 static_assert(std::is_integral_v<T>, "sub_overflow() requires integral arguments.");
70
71 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
72 // SUB, JB
73 return __builtin_sub_overflow(lhs, rhs, r);
74
75 } else if constexpr (std::is_unsigned_v<T>) {
76 // MOV, SUB, CMP, JA
77 *r = lhs - rhs;
78 return *r > lhs;
79
80 } else {
81 // SUB, NOT, XOR, XOR, TEST, JL
82 ttlet lhs_ = static_cast<std::make_unsigned_t<T>>(lhs);
83 ttlet rhs_ = static_cast<std::make_unsigned_t<T>>(rhs);
84 ttlet r_ = lhs_ - rhs_;
85 *r = static_cast<T>(r_);
86 return ((lhs ^ rhs) & (~rhs ^ *r)) < 0;
87 }
88}
89
93template<typename T>
94inline bool mul_overflow(T lhs, T rhs, T *r)
95{
96 static_assert(std::is_integral_v<T>, "mul_overflow() requires integral arguments.");
97
98 if constexpr (Compiler::current == Compiler::gcc || Compiler::current == Compiler::clang) {
99 return __builtin_mul_overflow(lhs, rhs, r);
100
101 } else if constexpr (std::is_signed_v<T> && Compiler::current == Compiler::MSVC && sizeof(T) == sizeof(long long)) {
102 // IMUL, SAR, XOR, JNE
103 long long hi = 0;
104 *r = _mul128(lhs, rhs, &hi);
105
106 // Sign bit in *r should match all bits in hi.
107 return (hi ^ (*r >> 63)) != 0;
108
109 } else if constexpr (std::is_unsigned_v<T> && Compiler::current == Compiler::MSVC && sizeof(T) == sizeof(unsigned long long)) {
110 unsigned long long hi = 0;
111 *r = _umul128(lhs, rhs, &hi);
112 return hi > 0;
113
114 } else if constexpr (sizeof(T) <= (sizeof(make_intmax_t<T>)/2)) {
115 // MOVSX, MOVSX, IMUL, MOVSX, CMP, JNE
116 ttlet lhs_ = static_cast<make_intmax_t<T>>(lhs);
117 ttlet rhs_ = static_cast<make_intmax_t<T>>(rhs);
118 ttlet r_ = lhs_ * rhs_;
119 *r = static_cast<T>(r_);
120 return *r != r_;
121
122 } else {
123 tt_not_implemented();
124 }
125}
126
127}
T llround(T... args)