This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Implement builtin folding for SPARC


 Hi,

  This patch implements builtin folding for some SPARC VIS builtins that seem
to have no dependencies on the status register.  I didn't implement
fmul8sux16, fmul8ulx16, fmuld8sux16, or fmuld8ulx16 as the definitions for
those builtins may not be correct.  This is PR20666.

  Bootstrapped and regtested on sparc-linux, ok for mainline?

-- 
Thanks,
Jim

http://www.student.cs.uwaterloo.ca/~ja2morri/
http://phython.blogspot.com
http://open.nit.ca/wiki/?page=jim

2005-04-04  James A. Morrison  <phython@gcc.gnu.org>

	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.

Index: config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.358
diff -u -p -r1.358 sparc.c
--- config/sparc/sparc.c	31 Mar 2005 14:59:55 -0000	1.358
+++ config/sparc/sparc.c	4 Apr 2005 12:11:53 -0000
@@ -340,6 +340,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,
@@ -433,6 +436,8 @@ enum processor_type sparc_cpu;
 
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN sparc_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN sparc_fold_builtin
 
 #ifdef HAVE_AS_TLS
 #undef TARGET_HAVE_TLS
@@ -8637,6 +8642,192 @@ sparc_expand_builtin (tree exp, rtx targ
 
   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 instrinsics.  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))
+	    {
+	      short 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)
+	{
+	  long long accum = TREE_INT_CST_LOW (arg2);
+	  tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+	  tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+
+	  accum |= ((long long)TREE_INT_CST_HIGH (arg2)) << 32;
+
+	  for (; elts0 && elts1;
+	       elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+	    {
+	      int low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0));
+	      int low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+	      accum += abs (low0 - low1);
+	    }
+
+	  return build_int_cst_wide (rtype, accum & 0xffffffff,
+				     (accum >> 32) && 0xffffffff);
+	}
+
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
 
 int
 sparc_extra_constraint_check (rtx op, int c, int strict)
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
/* { 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%" } } */
/* { 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" } } */
/* { 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);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]