From 8b0096b486441c247c10cc46b4265e01ac32f9c5 Mon Sep 17 00:00:00 2001 From: "James A. Morrison" Date: Wed, 8 Jun 2005 16:03:31 +0000 Subject: [PATCH] re PR target/20666 (SPARC builtins should be folded if possible) 2005-06-08 James A. Morrison PR target/20666 * config/sparc/sparc.c (sparc_fold_builtin): New function (sparc_vis_mul8x16): New function. (sparc_handle_vis_mul8x16): New function. (TARGET_FOLD_BUILTIN): Define to sparc_fold_builtin. From-SVN: r100762 --- gcc/ChangeLog | 8 + gcc/config/sparc/sparc.c | 203 +++++++++++++++++++++ gcc/testsuite/ChangeLog | 10 + gcc/testsuite/gcc.target/sparc/fexpand-2.c | 11 ++ gcc/testsuite/gcc.target/sparc/fpmerge-2.c | 15 ++ gcc/testsuite/gcc.target/sparc/fpmul-2.c | 47 +++++ gcc/testsuite/gcc.target/sparc/noresult.c | 10 + gcc/testsuite/gcc.target/sparc/pdist-2.c | 18 ++ gcc/testsuite/gcc.target/sparc/pdist-3.c | 36 ++++ 9 files changed, 358 insertions(+) create mode 100644 gcc/testsuite/gcc.target/sparc/fexpand-2.c create mode 100644 gcc/testsuite/gcc.target/sparc/fpmerge-2.c create mode 100644 gcc/testsuite/gcc.target/sparc/fpmul-2.c create mode 100644 gcc/testsuite/gcc.target/sparc/noresult.c create mode 100644 gcc/testsuite/gcc.target/sparc/pdist-2.c create mode 100644 gcc/testsuite/gcc.target/sparc/pdist-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 44fbfdb568c..d0c33050430 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2005-06-08 James A. Morrison + + PR target/20666 + * config/sparc/sparc.c (sparc_fold_builtin): New function + (sparc_vis_mul8x16): New function. + (sparc_handle_vis_mul8x16): New function. + (TARGET_FOLD_BUILTIN): Define to sparc_fold_builtin. + 2005-06-08 David Edelsohn * config/rs6000/rs6000.md (call_indirect_nonlocal_aix32): Prefer diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 314895536db..6b46165c9c9 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -341,6 +341,9 @@ static void sparc_init_libfuncs (void); static void sparc_init_builtins (void); static void sparc_vis_init_builtins (void); static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +static tree sparc_fold_builtin (tree, tree, bool); +static int sparc_vis_mul8x16 (int, int); +static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree); static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static bool sparc_can_output_mi_thunk (tree, HOST_WIDE_INT, @@ -437,6 +440,8 @@ static bool fpu_option_set = false; #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN sparc_expand_builtin +#undef TARGET_FOLD_BUILTIN +#define TARGET_FOLD_BUILTIN sparc_fold_builtin #if TARGET_TLS #undef TARGET_HAVE_TLS @@ -7904,6 +7909,204 @@ sparc_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, return op[0]; } + +static int +sparc_vis_mul8x16 (int e8, int e16) +{ + return (e8 * e16 + 128) / 256; +} + +/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified + by FNCODE. All of the elements in ELTS0 and ELTS1 lists must be integer + constants. A tree list with the results of the multiplications is returned, + and each element in the list is of INNER_TYPE. */ + +static tree +sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1) +{ + tree n_elts = NULL_TREE; + int scale; + + switch (fncode) + { + case CODE_FOR_fmul8x16_vis: + for (; elts0 && elts1; + elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) + { + int val + = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), + TREE_INT_CST_LOW (TREE_VALUE (elts1))); + n_elts = tree_cons (NULL_TREE, + build_int_cst (inner_type, val), + n_elts); + } + break; + + case CODE_FOR_fmul8x16au_vis: + scale = TREE_INT_CST_LOW (TREE_VALUE (elts1)); + + for (; elts0; elts0 = TREE_CHAIN (elts0)) + { + int val + = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), + scale); + n_elts = tree_cons (NULL_TREE, + build_int_cst (inner_type, val), + n_elts); + } + break; + + case CODE_FOR_fmul8x16al_vis: + scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1))); + + for (; elts0; elts0 = TREE_CHAIN (elts0)) + { + int val + = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)), + scale); + n_elts = tree_cons (NULL_TREE, + build_int_cst (inner_type, val), + n_elts); + } + break; + + default: + gcc_unreachable (); + } + + return nreverse (n_elts); + +} +/* Handle TARGET_FOLD_BUILTIN target hook. + Fold builtin functions for SPARC intrinsics. If INGNORE is true the + result of the function call is ignored. NULL_TREE is returned if the + function could not be folded. */ + +static tree +sparc_fold_builtin (tree fndecl, tree arglist, bool ignore) +{ + tree arg0, arg1, arg2; + tree rtype = TREE_TYPE (TREE_TYPE (fndecl)); + + + if (ignore && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis + && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis) + return build_int_cst (rtype, 0); + + switch (DECL_FUNCTION_CODE (fndecl)) + { + case CODE_FOR_fexpand_vis: + arg0 = TREE_VALUE (arglist); + STRIP_NOPS (arg0); + + if (TREE_CODE (arg0) == VECTOR_CST) + { + tree inner_type = TREE_TYPE (rtype); + tree elts = TREE_VECTOR_CST_ELTS (arg0); + tree n_elts = NULL_TREE; + + for (; elts; elts = TREE_CHAIN (elts)) + { + unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4; + n_elts = tree_cons (NULL_TREE, + build_int_cst (inner_type, val), + n_elts); + } + return build_vector (rtype, nreverse (n_elts)); + } + break; + + case CODE_FOR_fmul8x16_vis: + case CODE_FOR_fmul8x16au_vis: + case CODE_FOR_fmul8x16al_vis: + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST) + { + tree inner_type = TREE_TYPE (rtype); + tree elts0 = TREE_VECTOR_CST_ELTS (arg0); + tree elts1 = TREE_VECTOR_CST_ELTS (arg1); + tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl), + inner_type, elts0, elts1); + + return build_vector (rtype, n_elts); + } + break; + + case CODE_FOR_fpmerge_vis: + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST) + { + tree elts0 = TREE_VECTOR_CST_ELTS (arg0); + tree elts1 = TREE_VECTOR_CST_ELTS (arg1); + tree n_elts = NULL_TREE; + + for (; elts0 && elts1; + elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) + { + n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts); + n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts); + } + + return build_vector (rtype, nreverse (n_elts)); + } + break; + + case CODE_FOR_pdist_vis: + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + + if (TREE_CODE (arg0) == VECTOR_CST + && TREE_CODE (arg1) == VECTOR_CST + && TREE_CODE (arg2) == INTEGER_CST) + { + int overflow = 0; + unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2); + HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2); + tree elts0 = TREE_VECTOR_CST_ELTS (arg0); + tree elts1 = TREE_VECTOR_CST_ELTS (arg1); + + for (; elts0 && elts1; + elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1)) + { + unsigned HOST_WIDE_INT + low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)), + low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1)); + HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0)); + HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1)); + + unsigned HOST_WIDE_INT l; + HOST_WIDE_INT h; + + overflow |= neg_double (low1, high1, &l, &h); + overflow |= add_double (low0, high0, l, h, &l, &h); + if (h < 0) + overflow |= neg_double (l, h, &l, &h); + + overflow |= add_double (low, high, l, h, &low, &high); + } + + gcc_assert (overflow == 0); + + return build_int_cst_wide (rtype, low, high); + } + + default: + break; + } + return NULL_TREE; +} int sparc_extra_constraint_check (rtx op, int c, int strict) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 62fd7fc20c7..c3bdb1b54f9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2005-06-08 James A. Morrison + + PR target/20666 + * gcc.target/sparc/fexpand-2.c: New. + * gcc.target/sparc/fpmerge-2.c: New. + * gcc.target/sparc/fpmul-2.c: New. + * gcc.target/sparc/noresult.c: New. + * gcc.target/sparc/pdist-2.c: New. + * gcc.target/sparc/pdist-3.c: New. + 2005-06-08 Alex V. Breger PR testsuite/21702 diff --git a/gcc/testsuite/gcc.target/sparc/fexpand-2.c b/gcc/testsuite/gcc.target/sparc/fexpand-2.c new file mode 100644 index 00000000000..38b4e72fa09 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/fexpand-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-final_cleanup -mcpu=ultrasparc -mvis" } */ +typedef short vec16 __attribute__((vector_size(8))); +typedef unsigned char vec8 __attribute__((vector_size(4))); + +vec16 foo () { + vec8 a = {(unsigned char)1,(unsigned char)2,(unsigned char)4,(unsigned char)8}; + return __builtin_vis_fexpand (a); +} + +/* { dg-final { scan-tree-dump "{ 16, 32, 64, 128 }" "final_cleanup" } } */ diff --git a/gcc/testsuite/gcc.target/sparc/fpmerge-2.c b/gcc/testsuite/gcc.target/sparc/fpmerge-2.c new file mode 100644 index 00000000000..ad66c199e44 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/fpmerge-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=ultrasparc -mvis -O1 -fdump-tree-final_cleanup" } */ +typedef unsigned char pixel __attribute__((vector_size(8))); +typedef unsigned char vec8 __attribute__((vector_size(4))); + +#define _(ARG) (unsigned char)ARG + +pixel foo () { + vec8 a = { _(1), _(3), _(5), _(7) }; + vec8 b = { _(2), _(4), _(6), _(8) }; + return __builtin_vis_fpmerge (a, b); +} + +/* { dg-final { scan-assembler-not "fpmerge\t%" } } */ +/* { dg-final { scan-tree-dump "{ 1, 2, 3, 4, 5, 6, 7, 8 }" "final_cleanup" } } */ diff --git a/gcc/testsuite/gcc.target/sparc/fpmul-2.c b/gcc/testsuite/gcc.target/sparc/fpmul-2.c new file mode 100644 index 00000000000..32170bda4e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/fpmul-2.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=ultrasparc -mvis -O1 -fdump-tree-final_cleanup" } */ + +typedef int vec32 __attribute__((vector_size(8))); +typedef short vec16 __attribute__((vector_size(8))); +typedef unsigned char vec8 __attribute__((vector_size(8))); + +typedef unsigned char pixel __attribute__((vector_size(4))); +typedef short pixel16 __attribute__((vector_size(4))); + +vec16 foo1 () { + pixel a = { (unsigned char)1, (unsigned char)2, (unsigned char)3, (unsigned char)4 }; + vec16 b = { (short)1, (short)2, (short)3, (short)4 }; + return __builtin_vis_fmul8x16 (a, b); +} + +vec16 foo1_1 () { + pixel a = { (unsigned char)1, (unsigned char)1, (unsigned char)1, (unsigned char)1 }; + vec16 b = { (short)256, (short)512, (short)1024, (short)2048 }; + return __builtin_vis_fmul8x16 (a, b); +} + +vec16 foo1_2 () { + pixel a = { (unsigned char)255, (unsigned char)255, (unsigned char)255, (unsigned char)255 }; + vec16 b = { (short)256, (short)512, (short)1024, (short)32767 }; + return __builtin_vis_fmul8x16 (a, b); +} +/* { dg-final { scan-assembler-not "fmul8x16\t%" } } */ +/* { dg-final { scan-tree-dump "{ 0, 0, 0, 0 }" "final_cleanup" } } */ +/* { dg-final { scan-tree-dump "{ 1, 2, 4, 8 }" "final_cleanup" } } */ +/* { dg-final { scan-tree-dump "{ 255, 510, 1020, 32639 }" "final_cleanup" } } */ + +vec16 foo2 () { + pixel a = { 1, 2, 3, 4 }; + pixel16 b = { 256, 512 }; + return __builtin_vis_fmul8x16au (a, b); +} +/* { dg-final { scan-assembler-not "fmul8x16au\t%" } } */ +/* { dg-final { scan-tree-dump "{ 1, 2, 3, 4 }" "final_cleanup" } } */ + +vec16 foo3 () { + pixel a = { 1, 2, 3, 4 }; + pixel16 b = { 256, 512 }; + return __builtin_vis_fmul8x16al (a, b); +} +/* { dg-final { scan-assembler-not "fmul8x16al\t%" } } */ +/* { dg-final { scan-tree-dump "{ 2, 4, 6, 8 }" "final_cleanup" } } */ diff --git a/gcc/testsuite/gcc.target/sparc/noresult.c b/gcc/testsuite/gcc.target/sparc/noresult.c new file mode 100644 index 00000000000..f32805d3547 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/noresult.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=ultrasparc -mvis" } */ +typedef short vec16 __attribute__((vector_size(8))); +typedef char vec8 __attribute__((vector_size(4))); + +void foo (vec16 a) { + __builtin_vis_fpack16 (a); +} + +/* { dg-final { scan-assembler-not "fpack16\t%" } } */ diff --git a/gcc/testsuite/gcc.target/sparc/pdist-2.c b/gcc/testsuite/gcc.target/sparc/pdist-2.c new file mode 100644 index 00000000000..0095d0e02f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/pdist-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=ultrasparc -mvis -O1 -fdump-tree-final_cleanup" } */ + +typedef long long int64_t; +typedef unsigned char vec8 __attribute__((vector_size(8))); + +#define _(A) (unsigned char)A + +int64_t foo () { + int64_t d = 2; + vec8 a = { _(1), _(2), _(3), _(4), _(5), _(6), _(7), _(255) }; + vec8 b = { _(2), _(4), _(8), _(16), _(32), _(64), _(128), _(8) }; + d = __builtin_vis_pdist (a, b, d); + return d; +} + +/* { dg-final { scan-assembler-not "pdist\t%" } } */ +/* { dg-final { scan-tree-dump "return 475" "final_cleanup" } } */ diff --git a/gcc/testsuite/gcc.target/sparc/pdist-3.c b/gcc/testsuite/gcc.target/sparc/pdist-3.c new file mode 100644 index 00000000000..e4d6cb53ed0 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/pdist-3.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-mcpu=ultrasparc -mvis -O1" } */ + +typedef long long int64_t; +typedef unsigned char vec8 __attribute__((vector_size(8))); + +extern void abort (); +extern void exit (int); + +#define _(A) (unsigned char)A + +int64_t foo (vec8 a, vec8 b) { + int64_t d = 2; + d = __builtin_vis_pdist (a, b, d); + return d; +} + +int64_t bar () { + int64_t d = 2; + vec8 a = { _(1), _(2), _(3), _(4), _(5), _(6), _(7), _(255) }; + vec8 b = { _(2), _(4), _(8), _(16), _(32), _(64), _(128), _(8) }; + d = __builtin_vis_pdist (a, b, d); + return d; +} + + +static vec8 a = { 1, 2, 3, 4, 5, 6, 7, 255 }; +static vec8 b = { 2, 4, 8, 16, 32, 64, 128, 8 }; + +int main (int argc, char *argv[]) { + + if (foo (a, b) != bar ()) + abort (); + + exit (0); +}