From: Florian K. <fk...@so...> - 2025-07-16 11:52:07
|
https://sourceware.org/cgit/valgrind/commit/?id=21bc095a32ad715a5857d11111703a34eca62b79 commit 21bc095a32ad715a5857d11111703a34eca62b79 Author: Florian Krohm <fl...@ei...> Date: Wed Jul 16 11:51:15 2025 +0000 iropt-test: Also test with random inputs; reorg the code a bit New utility functions: get_random_value and get_selected_values Add command line option -rNUM to specify the number of random tests per operator. Diff: --- none/tests/iropt-test/binary.c | 116 +++++++++++++++++--------------- none/tests/iropt-test/iropt-test.vgtest | 3 +- none/tests/iropt-test/main.c | 9 ++- none/tests/iropt-test/unary.c | 74 ++++++++++---------- none/tests/iropt-test/util.c | 55 +++++++++++++++ none/tests/iropt-test/vtest.h | 3 + 6 files changed, 163 insertions(+), 97 deletions(-) diff --git a/none/tests/iropt-test/binary.c b/none/tests/iropt-test/binary.c index c3f36c1884..ec4fa21d1c 100644 --- a/none/tests/iropt-test/binary.c +++ b/none/tests/iropt-test/binary.c @@ -27,90 +27,96 @@ #include "vtest.h" static void check_result(const irop_t *, const test_data_t *); -static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *, - unsigned, uint64_t *); +static void run_tests(const irop_t *, test_data_t *); +static void run_shift_tests(const irop_t *, test_data_t *); static int is_shift_op(IROp); void test_binary_op(const irop_t *op, test_data_t *data) { - opnd_t *opnd_l = &data->opnds[0]; - - switch (opnd_l->type) { - case Ity_I1: { - uint64_t values[] = { 0, 1 }; - - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } + if (is_shift_op(op->op)) + run_shift_tests(op, data); + else + run_tests(op, data); +} - case Ity_I8: { - uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; - uint64_t shifts[] = { 0, 1, 2, 6, 7 }; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } +static void +run_selected_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd_l = &data->opnds[0]; + opnd_t *opnd_r = &data->opnds[1]; + unsigned num_val_l, num_val_r; + const uint64_t *values_l = get_selected_values(opnd_l->type, &num_val_l); + const uint64_t *values_r = get_selected_values(opnd_r->type, &num_val_r); - case Ity_I16: { - uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX }; - uint64_t shifts[] = { 0, 1, 2, 14, 15 }; + for (unsigned i = 0; i < num_val_l; ++i) { + opnd_l->value = values_l[i]; + for (unsigned j = 0; j < num_val_r; ++j) { + opnd_r->value = values_r[j]; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; + valgrind_execute_test(op, data); + check_result(op, data); + } } +} - case Ity_I32: { - uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX }; - uint64_t shifts[] = { 0, 1, 2, 30, 31 }; - - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } - case Ity_I64: { - uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX }; - uint64_t shifts[] = { 0, 1, 2, 62, 63 }; +/* Test with pseudo-random numbers */ +static void +run_random_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd_l = &data->opnds[0]; + opnd_t *opnd_r = &data->opnds[1]; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd_l->value = get_random_value(opnd_l->type); + opnd_r->value = get_random_value(opnd_r->type); - default: - panic(__func__); + valgrind_execute_test(op, data); + check_result(op, data); } } +/* OP is a shift operator. */ static void -run_tests(const irop_t *op, test_data_t *data, unsigned num_val_l, - uint64_t *values_l, unsigned num_val_r, uint64_t *values_r) +run_shift_tests(const irop_t *op, test_data_t *data) { opnd_t *opnd_l = &data->opnds[0]; opnd_t *opnd_r = &data->opnds[1]; + unsigned num_shiftee; + const uint64_t *shiftee = get_selected_values(opnd_l->type, &num_shiftee); + unsigned max_shift_amount = bitsof_irtype(opnd_r->type) - 1; - for (unsigned i = 0; i < num_val_l; ++i) { - opnd_l->value = values_l[i]; - for (unsigned j = 0; j < num_val_r; ++j) { - opnd_r->value = values_r[j]; + /* Shift selected values with all possible shift amounts */ + for (unsigned i = 0; i < num_shiftee; ++i) { + opnd_l->value = shiftee[i]; + for (unsigned j = 0; j < max_shift_amount; ++j) { + opnd_r->value = j; valgrind_execute_test(op, data); check_result(op, data); } } + + /* Shift random values with random shift amounts */ + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd_l->value = get_random_value(opnd_l->type); + opnd_r->value = get_random_value(opnd_r->type) & max_shift_amount; + + valgrind_execute_test(op, data); + check_result(op, data); + } +} + + +static void +run_tests(const irop_t *op, test_data_t *data) +{ + run_selected_tests(op, data); + run_random_tests(op, data); } diff --git a/none/tests/iropt-test/iropt-test.vgtest b/none/tests/iropt-test/iropt-test.vgtest index 8becafdf8c..de31de6046 100644 --- a/none/tests/iropt-test/iropt-test.vgtest +++ b/none/tests/iropt-test/iropt-test.vgtest @@ -1,4 +1,5 @@ prog: iropt-test -#args: -v -v +#args: -v -v -r10 +args: -r100 vgopts: -q --vex-guest-chase=no diff --git a/none/tests/iropt-test/main.c b/none/tests/iropt-test/main.c index 28b8d23e4b..2622515e55 100644 --- a/none/tests/iropt-test/main.c +++ b/none/tests/iropt-test/main.c @@ -38,18 +38,23 @@ static void check_irops_table(void); static test_data_t *new_test_data(const irop_t *); int verbose = 0; +unsigned num_random_tests; int main(int argc, char *argv[]) { assert(sizeof(long long) == 8); + assert(RAND_MAX == INT32_MAX); for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-v") == 0) ++verbose; - else if (strcmp(argv[i], "--help") == 0) { + else if (strncmp(argv[i], "-r", 2) == 0) { + num_random_tests = atoi(argv[i] + 2); + } else if (strcmp(argv[i], "--help") == 0) { printf("\niropt-test [ -v | --help ]\n"); + printf("\n\t -rNUM number of random tests per IRop\n"); printf("\n\t -v verbose mode; shows IROps being tested\n"); printf("\n\t -v -v verbose mode, extreme edition\n\n"); return 0; @@ -72,7 +77,7 @@ main(int argc, char *argv[]) const irop_t *op = irops +i; if (verbose) - printf("\nTesting operator %s\n", op->name); + printf("Testing operator %s\n", op->name); test_data_t *data = new_test_data(op); diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 44af3203dd..bb26138487 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -23,11 +23,13 @@ */ #include <stdio.h> // printf +#include <stdlib.h> // rand #include <stdint.h> // UINT64_MAX #include "vtest.h" static void check_result(const irop_t *, const test_data_t *); -static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *); +static void run_selected_tests(const irop_t *, test_data_t *); +static void run_random_tests(const irop_t *, test_data_t *); static uint64_t left(uint64_t, unsigned); static uint32_t popcount(uint64_t); @@ -38,47 +40,25 @@ test_unary_op(const irop_t *op, test_data_t *data) opnd_t *opnd = &data->opnds[0]; switch (opnd->type) { - case Ity_I1: { - uint64_t values[] = { 0, 1 }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - + case Ity_I1: case Ity_I8: { - uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - - case Ity_I16: { - uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX, - /* and for the benefit of Iop_16HIto8: */ - 1 << 8, 2 << 8, UINT8_MAX << 8 - }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - - case Ity_I32: { - uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX, - /* and for the benefit of Iop_32HIto16: */ - 1 << 16, 2 << 16, (uint64_t)UINT16_MAX << 16 - }; - run_tests(op, data, NUM_EL(values), values); + /* Exhaustive */ + unsigned max = (1 << bitsof_irtype(opnd->type)) - 1; + for (unsigned i = 0; i <= max; ++i) { + opnd->value = i; + + valgrind_execute_test(op, data); + check_result(op, data); + } break; } - case Ity_I64: { - uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX, - /* and for the benefit of Iop_64HIto32: */ - (uint64_t)1 << 32, (uint64_t)2 << 32, (uint64_t)UINT32_MAX << 32 - }; - run_tests(op, data, NUM_EL(values), values); + case Ity_I16: + case Ity_I32: + case Ity_I64: + run_selected_tests(op, data); + run_random_tests(op, data); break; - } default: panic(__func__); @@ -87,10 +67,11 @@ test_unary_op(const irop_t *op, test_data_t *data) static void -run_tests(const irop_t *op, test_data_t *data, unsigned num_val, - uint64_t *values) +run_selected_tests(const irop_t *op, test_data_t *data) { opnd_t *opnd = &data->opnds[0]; + unsigned num_val; + const uint64_t *values = get_selected_values(opnd->type, &num_val); for (unsigned i = 0; i < num_val; ++i) { opnd->value = values[i]; @@ -101,6 +82,21 @@ run_tests(const irop_t *op, test_data_t *data, unsigned num_val, } +/* Test with pseudo-random numbers */ +static void +run_random_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd = &data->opnds[0]; + + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd->value = get_random_value(opnd->type); + + valgrind_execute_test(op, data); + check_result(op, data); + } +} + + /* Check the result of a unary operation. */ static void check_result(const irop_t *op, const test_data_t *data) diff --git a/none/tests/iropt-test/util.c b/none/tests/iropt-test/util.c index 80e58570fe..072ff90c36 100644 --- a/none/tests/iropt-test/util.c +++ b/none/tests/iropt-test/util.c @@ -104,3 +104,58 @@ bitsof_irtype(IRType ty) panic(__func__); } } + + +uint64_t +get_random_value(IRType type) +{ + uint64_t val = rand(); + + switch (type) { + case Ity_I1: return val & 0x1; + case Ity_I8: return val & UINT8_MAX; + case Ity_I16: return val & UINT16_MAX; + case Ity_I32: return val & UINT32_MAX; + case Ity_I64: + /* Note, that RAND_MAX == INT32_MAX. Therefore, simply concatenating + two rand() values would never produce a value with MSB == 1 */ + val <<= (32 + 1); + val |= rand() << 1; + val |= rand() & 0x1; + return val; + + default: + panic(__func__); + } +} + + +const uint64_t * +get_selected_values(IRType type, unsigned *num_val) +{ + static const uint64_t values_1bit[] = { 0, 1 }; + static const uint64_t values_8bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX }; + static const uint64_t values_16bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX }; + static const uint64_t values_32bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX, UINT16_MAX + 1, + UINT32_MAX - 1, UINT32_MAX }; + static const uint64_t values_64bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX, UINT16_MAX + 1, + UINT32_MAX - 1, UINT32_MAX, UINT32_MAX + 1, + UINT64_MAX - 1, UINT64_MAX }; + + switch (type) { + case Ity_I1: *num_val = NUM_EL(values_1bit); return values_1bit; + case Ity_I8: *num_val = NUM_EL(values_8bit); return values_8bit; + case Ity_I16: *num_val = NUM_EL(values_16bit); return values_16bit; + case Ity_I32: *num_val = NUM_EL(values_32bit); return values_32bit; + case Ity_I64: *num_val = NUM_EL(values_64bit); return values_64bit; + default: + panic(__func__); + } +} diff --git a/none/tests/iropt-test/vtest.h b/none/tests/iropt-test/vtest.h index d9c1ddaae5..47b397f681 100644 --- a/none/tests/iropt-test/vtest.h +++ b/none/tests/iropt-test/vtest.h @@ -84,8 +84,11 @@ void panic(const char *, ...) __attribute__((noreturn)); void complain(const irop_t *, const test_data_t *, uint64_t expected); unsigned bitsof_irtype(IRType); +uint64_t get_random_value(IRType); +const uint64_t *get_selected_values(IRType, unsigned *); /* Exported variables */ extern int verbose; +extern unsigned num_random_tests; #endif // VTEST_H |