The following addresses another case where x87 FP loads mangle the bit representation and thus are not suitable for a representative in other types. VN was value-numbering a later integer load of 'x' as the same as a former float load of 'x'.
We can use the new TARGET_MODE_CAN_TRANSFER_BITS hook to identify problematic modes and enforce strict compatibility for those in the reference comparison, improving the handling of modes with padding in visit_reference_op_load. Bootstrapped and tested on x86_64-unknown-linux-gnu. OK? Thanks, Richard. PR tree-optimization/114659 * tree-ssa-sccvn.cc (visit_reference_op_load): Do not prevent punning from modes with padding here, but ... (vn_reference_eq): ... ensure this here, also honoring types with modes that cannot act as bit container. * gcc.target/i386/pr114659.c: New testcase. --- gcc/testsuite/gcc.target/i386/pr114659.c | 62 ++++++++++++++++++++++++ gcc/tree-ssa-sccvn.cc | 11 ++--- 2 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr114659.c diff --git a/gcc/testsuite/gcc.target/i386/pr114659.c b/gcc/testsuite/gcc.target/i386/pr114659.c new file mode 100644 index 00000000000..e1e24d55687 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114659.c @@ -0,0 +1,62 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +int +my_totalorderf (float const *x, float const *y) +{ + int xs = __builtin_signbit (*x); + int ys = __builtin_signbit (*y); + if (!xs != !ys) + return xs; + + int xn = __builtin_isnan (*x); + int yn = __builtin_isnan (*y); + if (!xn != !yn) + return !xn == !xs; + if (!xn) + return *x <= *y; + + unsigned int extended_sign = -!!xs; + union { unsigned int i; float f; } xu = {0}, yu = {0}; + __builtin_memcpy (&xu.f, x, sizeof (float)); + __builtin_memcpy (&yu.f, y, sizeof (float)); + return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign); +} + +static float +positive_NaNf () +{ + float volatile nan = 0.0f / 0.0f; + return (__builtin_signbit (nan) ? - nan : nan); +} + +typedef union { float value; unsigned int word[1]; } memory_float; + +static memory_float +construct_memory_SNaNf (float quiet_value) +{ + memory_float m; + m.value = quiet_value; + m.word[0] ^= (unsigned int) 1 << 22; + m.word[0] |= (unsigned int) 1; + return m; +} + +memory_float x[7] = + { + { 0 }, + { 1e-5 }, + { 1 }, + { 1e37 }, + { 1.0f / 0.0f }, + }; + +int +main () +{ + x[5] = construct_memory_SNaNf (positive_NaNf ()); + x[6] = (memory_float) { positive_NaNf () }; + if (! my_totalorderf (&x[5].value, &x[6].value)) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index dc377fa16ce..0639ba426ff 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -837,6 +837,9 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) TYPE_VECTOR_SUBPARTS (vr2->type))) return false; } + else if (TYPE_MODE (vr1->type) != TYPE_MODE (vr2->type) + && !mode_can_transfer_bits (TYPE_MODE (vr1->type))) + return false; i = 0; j = 0; @@ -5814,13 +5817,7 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt) if (result && !useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (op))) { - /* Avoid the type punning in case the result mode has padding where - the op we lookup has not. */ - if (TYPE_MODE (TREE_TYPE (result)) != BLKmode - && maybe_lt (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (result))), - GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (op))))) - result = NULL_TREE; - else if (CONSTANT_CLASS_P (result)) + if (CONSTANT_CLASS_P (result)) result = const_unop (VIEW_CONVERT_EXPR, TREE_TYPE (op), result); else { -- 2.35.3