This patch fixes PR target/79004 by eliminating the optimization of avoiding direct move if we are converting an 8/16-bit integer value from memory to IEEE 128-bit floating point.
I opened a new bug (PR target/79038) to address the underlying issue that the IEEE 128-bit floating point integer conversions were written before small integers were allowed in the traditional Altivec registers. This meant that we had to use UNSPEC and explicit temporaries to get the integers into the appropriate registers. I have tested this bug by doing a bootstrap build and make check on a little endian power8 system and using an assembler that knows about ISA 3.0 instructions. I added a new test to verify the results. Can I check this into the trunk? This is not an issue on GCC 6.x. [gcc] 2017-01-09 Michael Meissner <meiss...@linux.vnet.ibm.com> PR target/79004 * config/rs6000/rs6000.md (FP_ISA3): Do not optimize converting char or short to __float128/_Float128 directly. [gcc/testsuite] 2017-01-09 Michael Meissner <meiss...@linux.vnet.ibm.com> PR target/79004 * gcc.target/powerpc/pr79004.c: New test. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 244232) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -521,10 +521,7 @@ (define_mode_iterator SIGNBIT [(KF "FLOA (TF "FLOAT128_VECTOR_P (TFmode)")]) ; Iterator for ISA 3.0 supported floating point types -(define_mode_iterator FP_ISA3 [SF - DF - (KF "FLOAT128_IEEE_P (KFmode)") - (TF "FLOAT128_IEEE_P (TFmode)")]) +(define_mode_iterator FP_ISA3 [SF DF]) ; SF/DF suffix for traditional floating instructions (define_mode_attr Ftrad [(SF "s") (DF "")]) Index: gcc/testsuite/gcc.target/powerpc/pr79004.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr79004.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr79004.c (revision 0) @@ -0,0 +1,118 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-require-effective-target powerpc_float128_hw_ok } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */ +/* { dg-options "-mcpu=power9 -O2" } */ + +#include <math.h> + +#ifndef TYPE +#define TYPE __float128 +#endif + +TYPE from_double (double a) { return (TYPE)a; } +TYPE from_single (float a) { return (TYPE)a; } + +TYPE from_double_load (double *a) { return (TYPE)*a; } +TYPE from_single_load (float *a) { return (TYPE)*a; } + +double to_double (TYPE a) { return (double)a; } +float to_single (TYPE a) { return (float)a; } + +void to_double_store (TYPE a, double *p) { *p = (double)a; } +void to_single_store (TYPE a, float *p) { *p = (float)a; } + +TYPE from_sign_char (signed char a) { return (TYPE)a; } +TYPE from_sign_short (short a) { return (TYPE)a; } +TYPE from_sign_int (int a) { return (TYPE)a; } +TYPE from_sign_long (long a) { return (TYPE)a; } + +TYPE from_sign_char_load (signed char *a) { return (TYPE)*a; } +TYPE from_sign_short_load (short *a) { return (TYPE)*a; } +TYPE from_sign_int_load (int *a) { return (TYPE)*a; } +TYPE from_sign_long_load (long *a) { return (TYPE)*a; } + +TYPE from_sign_char_load_4 (signed char *a) { return (TYPE)a[4]; } +TYPE from_sign_short_load_4 (short *a) { return (TYPE)a[4]; } +TYPE from_sign_int_load_4 (int *a) { return (TYPE)a[4]; } +TYPE from_sign_long_load_4 (long *a) { return (TYPE)a[4]; } + +TYPE from_sign_char_load_n (signed char *a, long n) { return (TYPE)a[n]; } +TYPE from_sign_short_load_n (short *a, long n) { return (TYPE)a[n]; } +TYPE from_sign_int_load_n (int *a, long n) { return (TYPE)a[n]; } +TYPE from_sign_long_load_n (long *a, long n) { return (TYPE)a[n]; } + +signed char to_sign_char (TYPE a) { return (signed char)a; } +short to_sign_short (TYPE a) { return (short)a; } +int to_sign_int (TYPE a) { return (int)a; } +long to_sign_long (TYPE a) { return (long)a; } + +void to_sign_char_store (TYPE a, signed char *p) { *p = (signed char)a; } +void to_sign_short_store (TYPE a, short *p) { *p = (short)a; } +void to_sign_int_store (TYPE a, int *p) { *p = (int)a; } +void to_sign_long_store (TYPE a, long *p) { *p = (long)a; } + +void to_sign_char_store_4 (TYPE a, signed char *p) { p[4] = (signed char)a; } +void to_sign_short_store_4 (TYPE a, short *p) { p[4] = (short)a; } +void to_sign_int_store_4 (TYPE a, int *p) { p[4] = (int)a; } +void to_sign_long_store_4 (TYPE a, long *p) { p[4] = (long)a; } + +void to_sign_char_store_n (TYPE a, signed char *p, long n) { p[n] = (signed char)a; } +void to_sign_short_store_n (TYPE a, short *p, long n) { p[n] = (short)a; } +void to_sign_int_store_n (TYPE a, int *p, long n) { p[n] = (int)a; } +void to_sign_long_store_n (TYPE a, long *p, long n) { p[n] = (long)a; } + +TYPE from_uns_char (unsigned char a) { return (TYPE)a; } +TYPE from_uns_short (unsigned short a) { return (TYPE)a; } +TYPE from_uns_int (unsigned int a) { return (TYPE)a; } +TYPE from_uns_long (unsigned long a) { return (TYPE)a; } + +TYPE from_uns_char_load (unsigned char *a) { return (TYPE)*a; } +TYPE from_uns_short_load (unsigned short *a) { return (TYPE)*a; } +TYPE from_uns_int_load (unsigned int *a) { return (TYPE)*a; } +TYPE from_uns_long_load (unsigned long *a) { return (TYPE)*a; } + +TYPE from_uns_char_load_4 (unsigned char *a) { return (TYPE)a[4]; } +TYPE from_uns_short_load_4 (unsigned short *a) { return (TYPE)a[4]; } +TYPE from_uns_int_load_4 (unsigned int *a) { return (TYPE)a[4]; } +TYPE from_uns_long_load_4 (unsigned long *a) { return (TYPE)a[4]; } + +TYPE from_uns_char_load_n (unsigned char *a, long n) { return (TYPE)a[n]; } +TYPE from_uns_short_load_n (unsigned short *a, long n) { return (TYPE)a[n]; } +TYPE from_uns_int_load_n (unsigned int *a, long n) { return (TYPE)a[n]; } +TYPE from_uns_long_load_n (unsigned long *a, long n) { return (TYPE)a[n]; } + +unsigned char to_uns_char (TYPE a) { return (unsigned char)a; } +unsigned short to_uns_short (TYPE a) { return (unsigned short)a; } +unsigned int to_uns_int (TYPE a) { return (unsigned int)a; } +unsigned long to_uns_long (TYPE a) { return (unsigned long)a; } + +void to_uns_char_store (TYPE a, unsigned char *p) { *p = (unsigned char)a; } +void to_uns_short_store (TYPE a, unsigned short *p) { *p = (unsigned short)a; } +void to_uns_int_store (TYPE a, unsigned int *p) { *p = (unsigned int)a; } +void to_uns_long_store (TYPE a, unsigned long *p) { *p = (unsigned long)a; } + +void to_uns_char_store_4 (TYPE a, unsigned char *p) { p[4] = (unsigned char)a; } +void to_uns_short_store_4 (TYPE a, unsigned short *p) { p[4] = (unsigned short)a; } +void to_uns_int_store_4 (TYPE a, unsigned int *p) { p[4] = (unsigned int)a; } +void to_uns_long_store_4 (TYPE a, unsigned long *p) { p[4] = (unsigned long)a; } + +void to_uns_char_store_n (TYPE a, unsigned char *p, long n) { p[n] = (unsigned char)a; } +void to_uns_short_store_n (TYPE a, unsigned short *p, long n) { p[n] = (unsigned short)a; } +void to_uns_int_store_n (TYPE a, unsigned int *p, long n) { p[n] = (unsigned int)a; } +void to_uns_long_store_n (TYPE a, unsigned long *p, long n) { p[n] = (unsigned long)a; } + +/* { dg-final { scan-assembler-not " bl __" } } */ +/* { dg-final { scan-assembler "xscvdpqp" } } */ +/* { dg-final { scan-assembler "xscvqpdp" } } */ +/* { dg-final { scan-assembler "xscvqpdpo" } } */ +/* { dg-final { scan-assembler "xscvqpsdz" } } */ +/* { dg-final { scan-assembler "xscvqpswz" } } */ +/* { dg-final { scan-assembler "xscvsdqp" } } */ +/* { dg-final { scan-assembler "xscvudqp" } } */ +/* { dg-final { scan-assembler "lxsd" } } */ +/* { dg-final { scan-assembler "lxsiwax" } } */ +/* { dg-final { scan-assembler "lxsiwzx" } } */ +/* { dg-final { scan-assembler "lxssp" } } */ +/* { dg-final { scan-assembler "stxsd" } } */ +/* { dg-final { scan-assembler "stxsiwx" } } */ +/* { dg-final { scan-assembler "stxssp" } } */