// Copyright (C) 2020-2023 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING3. If not see // . // expensive: * [1-9] * * // timeout-factor: 2 #include "bits/main.h" template void for_constexpr(F&& fun) { if constexpr (Begin <= End) { fun(std::integral_constant()); if constexpr (Begin < End) { for_constexpr(static_cast(fun)); } } } template void test() { using T = typename V::value_type; if constexpr (std::is_integral_v) { constexpr int nbits(sizeof(T) * __CHAR_BIT__); constexpr int n_promo_bits = std::max(nbits, int(sizeof(int) * __CHAR_BIT__)); // complement COMPARE(~V(), V(~T())); COMPARE(~V(~T()), V()); { // modulus V x = make_vec({3, 4}, 2); COMPARE(x % x, V(0)); V y = x - 1; COMPARE(x % y, V(1)); y = x + 1; COMPARE(x % y, x); if (std::is_signed::value) { x = -x; COMPARE(x % y, x); x = -y; COMPARE(x % y, V(0)); x = x - 1; COMPARE(x % y, V(-1)); x %= y; COMPARE(x, V(-1)); } } { // bit_and V x = make_vec({3, 4, 5}, 8); COMPARE(x & x, x); COMPARE(x & ~x, V()); COMPARE(x & V(), V()); COMPARE(V() & x, V()); V y = make_vec({1, 5, 3}, 8); COMPARE(x & y, make_vec({1, 4, 1}, 8)); x &= y; COMPARE(x, make_vec({1, 4, 1}, 8)); } { // bit_or V x = make_vec({3, 4, 5}, 8); COMPARE(x | x, x); COMPARE(x | ~x, ~V()); COMPARE(x | V(), x); COMPARE(V() | x, x); V y = make_vec({1, 5, 3}, 8); COMPARE(x | y, make_vec({3, 5, 7}, 8)); x |= y; COMPARE(x, make_vec({3, 5, 7}, 8)); } { // bit_xor V x = make_vec({3, 4, 5}, 8); COMPARE(x ^ x, V()); COMPARE(x ^ ~x, ~V()); COMPARE(x ^ V(), x); COMPARE(V() ^ x, x); V y = make_vec({1, 5, 3}, 8); COMPARE(x ^ y, make_vec({2, 1, 6}, 0)); x ^= y; COMPARE(x, make_vec({2, 1, 6}, 0)); } { // bit_shift_left // Note: // - negative RHS or RHS >= max(#bits(T), #bits(int)) is UB // - negative LHS is UB // - shifting into (or over) the sign bit is UB // - unsigned LHS overflow is modulo arithmetic COMPARE(V() << 1, V()); for (int i = 0; i < nbits - 1; ++i) { COMPARE(V(1) << i, V(T(1) << i)) << "i: " << i; } for_constexpr( [](auto shift_ic) { constexpr int shift = shift_ic; const V seq = make_value_unknown(V([&](T i) { if constexpr (std::is_signed_v) { const T max = std::__finite_max_v >> shift; return max == 0 ? 1 : (std::abs(max - i) % max) + 1; } else { return ~T() - i; } })); const V ref([&](T i) { return T(seq[i] << shift); }); COMPARE(seq << shift, ref) << "seq: " << seq << ", shift: " << shift; COMPARE(seq << make_value_unknown(shift), ref) << "seq: " << seq << ", shift: " << shift; }); { V seq = make_vec({0, 1}, nbits - 2); seq %= nbits - 1; COMPARE(make_vec({0, 1}, 0) << seq, V([&](auto i) { return T(T(i & 1) << seq[i]); })) << "seq = " << seq; COMPARE(make_vec({1, 0}, 0) << seq, V([&](auto i) { return T(T(~i & 1) << seq[i]); })); COMPARE(V(1) << seq, V([&](auto i) { return T(T(1) << seq[i]); })); } if (std::is_unsigned::value) { constexpr int shift_count = nbits - 1; COMPARE(V(1) << shift_count, V(T(1) << shift_count)); constexpr T max = // avoid overflow warning in the last COMPARE std::is_unsigned::value ? std::__finite_max_v : T(1); COMPARE(V(max) << shift_count, V(max << shift_count)) << "shift_count: " << shift_count; } } { // bit_shift_right // Note: // - negative LHS is implementation defined // - negative RHS or RHS >= #bits is UB // - no other UB COMPARE(V(~T()) >> V(0), V(~T())); COMPARE(V(~T()) >> V(make_value_unknown(0)), V(~T())); for (int s = 1; s < nbits; ++s) { COMPARE(V(~T()) >> V(s), V(T(~T()) >> s)) << "s: " << s; } for (int s = 1; s < nbits; ++s) { COMPARE(V(~T(1)) >> V(s), V(T(~T(1)) >> s)) << "s: " << s; } COMPARE(V(0) >> V(1), V(0)); COMPARE(V(1) >> V(1), V(0)); COMPARE(V(2) >> V(1), V(1)); COMPARE(V(3) >> V(1), V(1)); COMPARE(V(7) >> V(2), V(1)); for (int j = 0; j < 100; ++j) { const V seq([&](auto i) -> T { return (j + i) % n_promo_bits; }); COMPARE(V(1) >> seq, V([&](auto i) { return T(T(1) >> seq[i]); })) << "seq = " << seq; COMPARE(make_value_unknown(V(1)) >> make_value_unknown(seq), V([&](auto i) { return T(T(1) >> seq[i]); })) << "seq = " << seq; } for_constexpr([](auto shift_ic) { constexpr int shift = shift_ic; const V seq = make_value_unknown(V([&](int i) { using U = std::make_unsigned_t; return T(~U() >> (i % 32)); })); const V ref([&](T i) { return T(seq[i] >> shift); }); COMPARE(seq >> shift, ref) << "seq: " << seq << ", shift: " << shift; COMPARE(seq >> make_value_unknown(shift), ref) << "seq: " << seq << ", shift: " << shift; }); } } else { VERIFY((is_substitution_failure>)); VERIFY((is_substitution_failure>)); VERIFY((is_substitution_failure>)); VERIFY((is_substitution_failure>)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); VERIFY((is_substitution_failure)); } }