Created
July 28, 2020 01:09
-
-
Save tstellar/80dae2ab8a18d810b10b8e42777f4fe4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Test driver for https://reviews.llvm.org/D84405 | |
// | |
// based on similar driver for https://reviews.llvm.org/D41149 | |
#include <cstdint> | |
#include <limits> | |
#include <iostream> | |
#include <vector> | |
// Instructions: | |
// - Compile this program with a baseline compiler and a patched compiler. | |
// - Check that the output of the two executables is the same. | |
// - Flags: -std=c++11 -O3 | |
// Generate interesting test inputs for mul<S, U>(S a, U b). | |
template<typename S, typename U0, typename U1> | |
std::vector<std::pair<U0, U1>> gen() { | |
std::vector<U0> Inputs0; | |
std::vector<U1> Inputs1; | |
// Create some interesting signed and unsigned numbers. | |
for (int i = 0; i < 50; ++i) { | |
Inputs0.push_back(i); | |
Inputs1.push_back(i); | |
} | |
for (int i = 1; i < 50; ++i) { // {MIN, MAX} / 1..49 | |
Inputs0.push_back(std::numeric_limits<U0>::min() / i); | |
Inputs1.push_back(std::numeric_limits<U1>::max() / i); | |
} | |
// Add an edge case where the product is greater than sign max but less than | |
// unsigned max. | |
if (std::numeric_limits<S>::max() < std::numeric_limits<U0>::max()) { | |
U0 SignedMax = std::numeric_limits<S>::max(); | |
U0 SignedMaxNextEven = SignedMax % 2 == 0 ? SignedMax + 2 : SignedMax + 1; | |
U0 Divisor = SignedMaxNextEven / 2; | |
Inputs0.push_back(Divisor); | |
Inputs1.push_back(2); | |
} | |
if (std::numeric_limits<S>::max() < std::numeric_limits<U1>::max()) { | |
U1 SignedMax = std::numeric_limits<S>::max(); | |
U1 SignedMaxNextEven = SignedMax % 2 == 0 ? SignedMax + 2 : SignedMax + 1; | |
U1 Divisor = SignedMaxNextEven / 2; | |
Inputs0.push_back(2); | |
Inputs1.push_back(Divisor); | |
} | |
// Take the cartesian product of the interesting signed and unsigned numbers. | |
std::vector<std::pair<U0, U1>> Inputs; | |
for (U0 i : Inputs0) | |
for (U1 u : Inputs1) | |
Inputs.emplace_back(i, u); | |
return Inputs; | |
} | |
// Multiply a * b. Print out the result if there's no overflow. Return true | |
// iff there's an overflow. | |
template<typename S, typename U0, typename U1> | |
bool mul(U0 a, U1 b) { | |
S res; | |
bool oflow = __builtin_mul_overflow(a, b, &res); | |
std::cout << a << " * " << b << " = " << res << "\toflow: " << oflow << std::endl; | |
return oflow; | |
} | |
// Compute some interesting checked multiplications given the following types: | |
// | |
// S: signed type | |
// U: unsigned type | |
// R: result type | |
// | |
// Print out the number of overflows detected. | |
template<typename S, typename U0, typename U1> | |
void test_mul() { | |
uint64_t NumOverflows = 0; | |
for (auto I : gen<S, U0, U1>()) | |
if (mul<S, U0, U1>(I.first, I.second)) | |
++NumOverflows; | |
std::cout << "# overflows = " << NumOverflows << std::endl; | |
} | |
// Test 6 different result types for each pair of signed & unsigned types. | |
#define R(SignedTy, UnsignedTy) \ | |
test_mul<SignedTy, UnsignedTy, uint16_t>(); \ | |
test_mul<SignedTy, UnsignedTy, uint32_t>(); \ | |
test_mul<SignedTy, UnsignedTy, uint64_t>(); | |
// Test 3 different unsigned types for each signed type. | |
#define U(SignedTy) \ | |
R(SignedTy, uint16_t) \ | |
R(SignedTy, uint32_t) \ | |
R(SignedTy, uint64_t) | |
// Test 3 different signed types. | |
#define S() \ | |
U(int16_t) \ | |
U(int32_t) \ | |
U(int64_t) | |
int main() { | |
// S(); // Test 54 different combinations of signed, unsigned, and result types. | |
// | |
// | |
// clang 10 can only compile these combinations. (The rest generate __muloti4 calls | |
// and cause the test program to fail to link). | |
test_mul<int32_t, uint32_t, uint32_t>(); | |
test_mul<int16_t, uint16_t, uint16_t>(); | |
// clang 11 with this patch can only test the clang 10 combinations plus these: | |
test_mul<int64_t, uint64_t, uint64_t>(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment