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