This patch solves a problem with VIEW_CONVERT_EXPR folding for fixed_cst and that use fixed-value.c:fixed_from_double_int.
The patch sign/zero extends the double_int input according to the requested fixed-point mode. The patch bootstraps on x86-linux-gnu and passes testsuite on avr-unknown one. Without this patch, the new test case fails because when a SAmode is constructed in fold-const.c:native_interpret_fixed(), the MSBs are not set according to the sign of the value. However, functions dealing with fixed-point constants use all bits of the underlying double_int, not only those covered by the mode mask. Moreover, some sanity checking is added for to the incoming machine mode. Ok for trunk? gcc/ PR tree-optimization/56064 * fixed-value.c (fixed_from_double_int): Sign/zero extend payload bits according to mode. * fixed-value.h (fixed_from_double_int) (const_fixed_from_double_int): Adjust comments. gcc/testsuite/ PR tree-optimization/56064 * gcc.dg/fixed-point/view-convert-2.c: New test.
Index: fixed-value.c =================================================================== --- fixed-value.c (revision 195736) +++ fixed-value.c (working copy) @@ -83,7 +83,7 @@ check_real_for_fixed_mode (REAL_VALUE_TY /* Construct a CONST_FIXED from a bit payload and machine mode MODE. - The bits in PAYLOAD are used verbatim. */ + The bits in PAYLOAD are sign-extended/zero-extended according to MODE. */ FIXED_VALUE_TYPE fixed_from_double_int (double_int payload, enum machine_mode mode) @@ -92,7 +92,13 @@ fixed_from_double_int (double_int payloa gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT); - value.data = payload; + if (SIGNED_SCALAR_FIXED_POINT_MODE_P (mode)) + value.data = payload.sext (1 + GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode)); + else if (UNSIGNED_SCALAR_FIXED_POINT_MODE_P (mode)) + value.data = payload.zext (GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode)); + else + gcc_unreachable(); + value.mode = mode; return value; Index: fixed-value.h =================================================================== --- fixed-value.h (revision 195736) +++ fixed-value.h (working copy) @@ -50,12 +50,12 @@ extern FIXED_VALUE_TYPE fconst1[MAX_FCON extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode); /* Construct a FIXED_VALUE from a bit payload and machine mode MODE. - The bits in PAYLOAD are used verbatim. */ + The bits in PAYLOAD are sign-extended/zero-extended according to MODE. */ extern FIXED_VALUE_TYPE fixed_from_double_int (double_int, enum machine_mode); /* Return a CONST_FIXED from a bit payload and machine mode MODE. - The bits in PAYLOAD are used verbatim. */ + The bits in PAYLOAD are sign-extended/zero-extended according to MODE. */ static inline rtx const_fixed_from_double_int (double_int payload, enum machine_mode mode) Index: testsuite/gcc.dg/fixed-point/view-convert-2.c =================================================================== --- testsuite/gcc.dg/fixed-point/view-convert-2.c (revision 0) +++ testsuite/gcc.dg/fixed-point/view-convert-2.c (revision 0) @@ -0,0 +1,139 @@ +/* PR tree-optimization/56064 */ +/* { dg-do run } */ +/* { dg-options "-std=gnu99 -O2" } */ + +extern void abort (void); +extern void exit (int); + +void test_k (void) +{ + _Accum a; + __INT32_TYPE__ i = -__INT32_MAX__; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&a, &i, sizeof (a)); + + if (a >= 0k) + abort(); +} + +void test_0k (void) +{ + _Accum a; + __INT32_TYPE__ i = 0; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&a, &i, sizeof (a)); + + if (a != 0k) + abort(); +} + + +void test_hr (void) +{ + short _Fract a; + __INT8_TYPE__ i = -__INT8_MAX__; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&a, &i, sizeof (a)); + + if (a >= 0hr) + abort(); +} + +void test_0hr (void) +{ + short _Fract a; + __INT8_TYPE__ i = 0; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&a, &i, sizeof (a)); + + if (a != 0hr) + abort(); +} + + +void test_si (void) +{ + _Accum a = __ACCUM_MIN__; + __INT32_TYPE__ i; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&i, &a, sizeof (i)); + + if (i >= 0) + abort(); +} + +void test_0si (void) +{ + _Accum a = 0; + __INT32_TYPE__ i; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&i, &a, sizeof (i)); + + if (i != 0) + abort(); +} + + +void test_qi (void) +{ + short _Fract a = __SFRACT_MIN__; + __INT8_TYPE__ i; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&i, &a, sizeof (i)); + + if (i >= 0) + abort(); +} + +void test_0qi (void) +{ + short _Fract a = 0hr; + __INT8_TYPE__ i; + + if (sizeof (a) != sizeof (i)) + return; + + __builtin_memcpy (&i, &a, sizeof (i)); + + if (i != 0) + abort(); +} + + +int main (void) +{ + test_hr(); + test_k(); + test_qi(); + test_si(); + + test_0hr(); + test_0k(); + test_0qi(); + test_0si(); + + exit (0); + + return 0; +}