1 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s 2 // expected-no-diagnostics 3 4 #include <limits.h> 5 #include <stdint.h> 6 7 int a() { 8 const int x = 3; 9 static int z; 10 constexpr int *y = &z; 11 return []() { return __builtin_sub_overflow((int)x, (int)x, (int *)y); }(); 12 } 13 int a2() { 14 const int x = 3; 15 static int z; 16 constexpr int *y = &z; 17 return []() { return __builtin_sub_overflow(x, x, y); }(); 18 } 19 20 template<typename T> 21 struct Result { 22 bool B; 23 T Value; 24 constexpr bool operator==(const Result<T> &Other) { 25 return B == Other.B && Value == Other.Value; 26 } 27 }; 28 29 30 template <typename RET, typename LHS, typename RHS> 31 constexpr Result<RET> add(LHS &&lhs, RHS &&rhs) { 32 RET sum{}; 33 return {__builtin_add_overflow(lhs, rhs, &sum), sum}; 34 } 35 36 static_assert(add<short>(static_cast<char>(120), static_cast<char>(10)) == Result<short>{false, 130}); 37 static_assert(add<char>(static_cast<short>(120), static_cast<short>(10)) == Result<char>{true, -126}); 38 static_assert(add<unsigned int>(INT_MAX, INT_MAX) == Result<unsigned int>{false, static_cast<unsigned int>(INT_MAX) * 2u}); 39 static_assert(add<int>(static_cast<unsigned int>(INT_MAX), 1u) == Result<int>{true, INT_MIN}); 40 41 static_assert(add<int>(17, 22) == Result<int>{false, 39}); 42 static_assert(add<int>(INT_MAX - 22, 24) == Result<int>{true, INT_MIN + 1}); 43 static_assert(add<int>(INT_MIN + 22, -23) == Result<int>{true, INT_MAX}); 44 45 template <typename RET, typename LHS, typename RHS> 46 constexpr Result<RET> sub(LHS &&lhs, RHS &&rhs) { 47 RET sum{}; 48 return {__builtin_sub_overflow(lhs, rhs, &sum), sum}; 49 } 50 51 static_assert(sub<unsigned char>(static_cast<char>(0),static_cast<char>(1)) == Result<unsigned char>{true, UCHAR_MAX}); 52 static_assert(sub<char>(static_cast<unsigned char>(0),static_cast<unsigned char>(1)) == Result<char>{false, -1}); 53 static_assert(sub<unsigned short>(static_cast<short>(0),static_cast<short>(1)) == Result<unsigned short>{true, USHRT_MAX}); 54 static_assert(sub<uint8_t>(static_cast<uint8_t>(255),static_cast<int>(100)) == Result<uint8_t>{false, 155}); 55 56 static_assert(sub<int>(17,22) == Result<int>{false, -5}); 57 static_assert(sub<int>(INT_MAX - 22, -23) == Result<int>{true, INT_MIN}); 58 static_assert(sub<int>(INT_MIN + 22, 23) == Result<int>{true, INT_MAX}); 59 60 template <typename RET, typename LHS, typename RHS> 61 constexpr Result<RET> mul(LHS &&lhs, RHS &&rhs) { 62 RET sum{}; 63 return {__builtin_mul_overflow(lhs, rhs, &sum), sum}; 64 } 65 66 static_assert(mul<int>(17,22) == Result<int>{false, 374}); 67 static_assert(mul<int>(INT_MAX / 22, 23) == Result<int>{true, -2049870757}); 68 static_assert(mul<int>(INT_MIN / 22, -23) == Result<int>{true, -2049870757}); 69 70 constexpr Result<int> sadd(int lhs, int rhs) { 71 int sum{}; 72 return {__builtin_sadd_overflow(lhs, rhs, &sum), sum}; 73 } 74 75 static_assert(sadd(17,22) == Result<int>{false, 39}); 76 static_assert(sadd(INT_MAX - 22, 23) == Result<int>{true, INT_MIN}); 77 static_assert(sadd(INT_MIN + 22, -23) == Result<int>{true, INT_MAX}); 78 79 constexpr Result<int> ssub(int lhs, int rhs) { 80 int sum{}; 81 return {__builtin_ssub_overflow(lhs, rhs, &sum), sum}; 82 } 83 84 static_assert(ssub(17,22) == Result<int>{false, -5}); 85 static_assert(ssub(INT_MAX - 22, -23) == Result<int>{true, INT_MIN}); 86 static_assert(ssub(INT_MIN + 22, 23) == Result<int>{true, INT_MAX}); 87 88 constexpr Result<int> smul(int lhs, int rhs) { 89 int sum{}; 90 return {__builtin_smul_overflow(lhs, rhs, &sum), sum}; 91 } 92 93 static_assert(smul(17,22) == Result<int>{false, 374}); 94 static_assert(smul(INT_MAX / 22, 23) == Result<int>{true, -2049870757}); 95 static_assert(smul(INT_MIN / 22, -23) == Result<int>{true, -2049870757}); 96 97 template<typename T> 98 struct CarryResult { 99 T CarryOut; 100 T Value; 101 constexpr bool operator==(const CarryResult<T> &Other) { 102 return CarryOut == Other.CarryOut && Value == Other.Value; 103 } 104 }; 105 106 constexpr CarryResult<unsigned char> addcb(unsigned char lhs, unsigned char rhs, unsigned char carry) { 107 unsigned char carry_out{}; 108 unsigned char sum{}; 109 sum = __builtin_addcb(lhs, rhs, carry, &carry_out); 110 return {carry_out, sum}; 111 } 112 113 static_assert(addcb(120, 10, 0) == CarryResult<unsigned char>{0, 130}); 114 static_assert(addcb(250, 10, 0) == CarryResult<unsigned char>{1, 4}); 115 static_assert(addcb(255, 255, 0) == CarryResult<unsigned char>{1, 254}); 116 static_assert(addcb(255, 255, 1) == CarryResult<unsigned char>{1, 255}); 117 static_assert(addcb(255, 0, 1) == CarryResult<unsigned char>{1, 0}); 118 static_assert(addcb(255, 1, 0) == CarryResult<unsigned char>{1, 0}); 119 static_assert(addcb(255, 1, 1) == CarryResult<unsigned char>{1, 1}); 120 // This is currently supported with the carry still producing a value of 1. 121 // If support for carry outside of 0-1 is removed, change this test to check 122 // that it is not supported. 123 static_assert(addcb(255, 255, 2) == CarryResult<unsigned char>{1, 0}); 124 125 constexpr CarryResult<unsigned char> subcb(unsigned char lhs, unsigned char rhs, unsigned char carry) { 126 unsigned char carry_out{}; 127 unsigned char sum{}; 128 sum = __builtin_subcb(lhs, rhs, carry, &carry_out); 129 return {carry_out, sum}; 130 } 131 132 static_assert(subcb(20, 10, 0) == CarryResult<unsigned char>{0, 10}); 133 static_assert(subcb(10, 10, 0) == CarryResult<unsigned char>{0, 0}); 134 static_assert(subcb(10, 15, 0) == CarryResult<unsigned char>{1, 251}); 135 // The carry is subtracted from the result 136 static_assert(subcb(10, 15, 1) == CarryResult<unsigned char>{1, 250}); 137 static_assert(subcb(0, 0, 1) == CarryResult<unsigned char>{1, 255}); 138 static_assert(subcb(0, 1, 0) == CarryResult<unsigned char>{1, 255}); 139 static_assert(subcb(0, 1, 1) == CarryResult<unsigned char>{1, 254}); 140 static_assert(subcb(0, 255, 0) == CarryResult<unsigned char>{1, 1}); 141 static_assert(subcb(0, 255, 1) == CarryResult<unsigned char>{1, 0}); 142 // This is currently supported with the carry still producing a value of 1. 143 // If support for carry outside of 0-1 is removed, change this test to check 144 // that it is not supported. 145 static_assert(subcb(0, 255, 2) == CarryResult<unsigned char>{1, 255}); 146