This patch adds support for the signed and unsigned int versions of the...
authorBill Seurer <seurer@linux.vnet.ibm.com>
Fri, 20 May 2016 15:25:04 +0000 (15:25 +0000)
committerBill Seurer <seurer@gcc.gnu.org>
Fri, 20 May 2016 15:25:04 +0000 (15:25 +0000)
This patch adds support for the signed and unsigned int versions of the
vec_addec altivec builtins from the Power Architecture 64-Bit ELF V2 ABI
OpenPOWER ABI for Linux Supplement (16 July 2015 Version 1.1). There are
many of the builtins that are missing and this is part of a series
of patches to add them.

There aren't instructions for the int versions of vec_addec so the
output code is built from other built-ins that do have instructions
which in this case is the following.

vec_addec (va, vb, carryv) == vec_or (vec_addc (va, vb),
vec_addc(vec_add(va, vb),
 vec_and (carryv, 0x1)))

The new test cases are executable tests which verify that the generated
code produces expected values. C macros were used so that the same
test case could be used for both the signed and unsigned versions. An
extra executable test case is also included to ensure that the modified
support for the __int128 versions of vec_addec is not broken. The same
test case could not be used for both int and __int128 because of some
differences in loading and storing the vectors.

Bootstrapped and tested on powerpc64le-unknown-linux-gnu and
powerpc64-unknown-linux-gnu with no regressions. Is this ok for trunk?

[gcc]

2016-05-20  Bill Seurer  <seurer@linux.vnet.ibm.com>

* config/rs6000/rs6000-builtin.def (vec_addec): Change vec_addec to a
special case builtin.
* config/rs6000/rs6000-c.c (altivec_resolve_overloaded_builtin): Add
support for ALTIVEC_BUILTIN_VEC_ADDEC.
* config/rs6000/rs6000.c (altivec_init_builtins): Add definition
for __builtin_vec_addec.

[gcc/testsuite]

2016-05-20  Bill Seurer  <seurer@linux.vnet.ibm.com>

* gcc.target/powerpc/vec-addec.c: New test.
* gcc.target/powerpc/vec-addec-int128.c: New test.

From-SVN: r236515

ChangeLog
gcc/config/rs6000/rs6000-builtin.def
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/vec-addec-int128.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/vec-addec.c [new file with mode: 0644]

index 8698133a08d680b9712f55f17ac64f617ea6ce88..f640bb740496f1994ba3aba7b3b8d559559169c4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-05-20  Bill Seurer  <seurer@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000-builtin.def (vec_addec): Change vec_addec to a
+       special case builtin.
+       * config/rs6000/rs6000-c.c (altivec_resolve_overloaded_builtin): Add
+       support for ALTIVEC_BUILTIN_VEC_ADDEC.
+       * config/rs6000/rs6000.c (altivec_init_builtins): Add definition
+       for __builtin_vec_addec.
+
 2016-05-16  Jakub Sejdak  <jakub.sejdak@phoesys.com>
 
        * config.guess: Import version 2016-04-02 (newest).
index 190df93bfdcca0a3ace0c48804f1ff7f3f702036..399d9f695142cbdd782c122873b4ffca5782eb26 100644 (file)
@@ -991,7 +991,6 @@ BU_ALTIVEC_X (VEC_EXT_V4SF, "vec_ext_v4sf",     CONST)
    before we get to the point about classifying the builtin type.  */
 
 /* 3 argument Altivec overloaded builtins.  */
-BU_ALTIVEC_OVERLOAD_3 (ADDEC,     "addec")
 BU_ALTIVEC_OVERLOAD_3 (MADD,       "madd")
 BU_ALTIVEC_OVERLOAD_3 (MADDS,      "madds")
 BU_ALTIVEC_OVERLOAD_3 (MLADD,      "mladd")
@@ -1177,6 +1176,7 @@ BU_ALTIVEC_OVERLOAD_P (VCMPGE_P,   "vcmpge_p")
 
 /* Overloaded Altivec builtins that are handled as special cases.  */
 BU_ALTIVEC_OVERLOAD_X (ADDE,      "adde")
+BU_ALTIVEC_OVERLOAD_X (ADDEC,     "addec")
 BU_ALTIVEC_OVERLOAD_X (CTF,       "ctf")
 BU_ALTIVEC_OVERLOAD_X (CTS,       "cts")
 BU_ALTIVEC_OVERLOAD_X (CTU,       "ctu")
index c69c93c5bd2866427a7b17fc4f6b336199669ac5..d22f6bd2095d79533c92ab29817146de8589c63c 100644 (file)
@@ -4661,6 +4661,86 @@ assignment for unaligned loads and stores");
        }
     }
 
+  if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC)
+    {
+      /* vec_addec needs to be special cased because there is no instruction
+       for the {un}signed int version.  */
+      if (nargs != 3)
+       {
+         error ("vec_addec only accepts 3 arguments");
+         return error_mark_node;
+       }
+
+      tree arg0 = (*arglist)[0];
+      tree arg0_type = TREE_TYPE (arg0);
+      tree arg1 = (*arglist)[1];
+      tree arg1_type = TREE_TYPE (arg1);
+      tree arg2 = (*arglist)[2];
+      tree arg2_type = TREE_TYPE (arg2);
+
+      /* All 3 arguments must be vectors of (signed or unsigned) (int or
+       __int128) and the types must match.  */
+      if (arg0_type != arg1_type || arg1_type != arg2_type)
+       goto bad;
+      if (TREE_CODE (arg0_type) != VECTOR_TYPE)
+       goto bad;
+
+      switch (TYPE_MODE (TREE_TYPE (arg0_type)))
+       {
+         /* For {un}signed ints,
+             vec_addec (va, vb, carryv) ==
+                               vec_or (vec_addc (va, vb),
+                                       vec_addc (vec_add (va, vb),
+                                                 vec_and (carryv, 0x1))).  */
+         case SImode:
+           {
+           /* Use save_expr to ensure that operands used more than once
+               that may have side effects (like calls) are only evaluated
+               once.  */
+           arg0 = save_expr (arg0);
+           arg1 = save_expr (arg1);
+           vec<tree, va_gc> *params = make_tree_vector ();
+           vec_safe_push (params, arg0);
+           vec_safe_push (params, arg1);
+           tree addc_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADDC];
+           tree call1 = altivec_resolve_overloaded_builtin (loc, addc_builtin,
+                                                            params);
+           params = make_tree_vector ();
+           vec_safe_push (params, arg0);
+           vec_safe_push (params, arg1);
+           tree add_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADD];
+           tree call2 = altivec_resolve_overloaded_builtin (loc, add_builtin,
+                                                            params);
+           tree const1 = build_int_cstu (TREE_TYPE (arg0_type), 1);
+           tree ones_vector = build_vector_from_val (arg0_type, const1);
+           tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, arg0_type,
+                                            arg2, ones_vector);
+           params = make_tree_vector ();
+           vec_safe_push (params, call2);
+           vec_safe_push (params, and_expr);
+           call2 = altivec_resolve_overloaded_builtin (loc, addc_builtin,
+                                                       params);
+           params = make_tree_vector ();
+           vec_safe_push (params, call1);
+           vec_safe_push (params, call2);
+           tree or_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_OR];
+           return altivec_resolve_overloaded_builtin (loc, or_builtin,
+                                                      params);
+           }
+         /* For {un}signed __int128s use the vaddecuq instruction.  */
+         case TImode:
+           {
+           tree VADDECUQ_bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VADDECUQ];
+           return altivec_resolve_overloaded_builtin (loc, VADDECUQ_bii,
+                                                      arglist);
+           }
+         /* Types other than {un}signed int and {un}signed __int128
+               are errors.  */
+         default:
+           goto bad;
+       }
+    }
+
   /* For now treat vec_splats and vec_promote as the same.  */
   if (fcode == ALTIVEC_BUILTIN_VEC_SPLATS
       || fcode == ALTIVEC_BUILTIN_VEC_PROMOTE)
index 092867520d3504fcc843e9693061f91220c1ccc9..0488db563e66e94784ab28a984d23f7c769dc765 100644 (file)
@@ -16557,6 +16557,8 @@ altivec_init_builtins (void)
 
   def_builtin ("__builtin_vec_adde", opaque_ftype_opaque_opaque_opaque,
                ALTIVEC_BUILTIN_VEC_ADDE);
+  def_builtin ("__builtin_vec_addec", opaque_ftype_opaque_opaque_opaque,
+               ALTIVEC_BUILTIN_VEC_ADDEC);
 
   /* Cell builtins.  */
   def_builtin ("__builtin_altivec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLX);
index d5739cbd22f98cce23e89d3898b6b5552b3ad80c..323e69f514cb4a7c0caf40347d3a4f9abe16e294 100644 (file)
@@ -1,3 +1,8 @@
+2016-05-20  Bill Seurer  <seurer@linux.vnet.ibm.com>
+
+       * gcc.target/powerpc/vec-addec.c: New test.
+       * gcc.target/powerpc/vec-addec-int128.c: New test.
+
 2016-05-20  David Malcolm  <dmalcolm@redhat.com>
 
        * gcc.dg/plugin/must-tail-call-1.c: New test case.
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-addec-int128.c b/gcc/testsuite/gcc.target/powerpc/vec-addec-int128.c
new file mode 100644 (file)
index 0000000..f95143a
--- /dev/null
@@ -0,0 +1,123 @@
+/* { dg-do run { target { powerpc64*-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3" } */
+
+/* Test that the vec_addec builtin works as expected.  */
+
+#include "altivec.h"
+
+#define N 4096
+
+void abort ();
+
+#define define_test_functions(STYPE, NAMESUFFIX) \
+\
+STYPE result_##NAMESUFFIX[N]; \
+STYPE addend1_##NAMESUFFIX[N]; \
+STYPE addend2_##NAMESUFFIX[N]; \
+STYPE carry_##NAMESUFFIX[N]; \
+STYPE expected_##NAMESUFFIX[N]; \
+\
+__attribute__((noinline)) void vector_tests_##NAMESUFFIX () \
+{ \
+  vector STYPE v1, v2, v3, tmp; \
+  int i; \
+  for (i = 0; i < N; i+=16/sizeof (STYPE)) \
+    { \
+      /* result=carry of addend1+addend2+(carry & 0x1).  */ \
+      v1 = (vector STYPE) { addend1_##NAMESUFFIX[i] }; \
+      v2 = (vector STYPE) { addend2_##NAMESUFFIX[i] }; \
+      v3 = (vector STYPE) { carry_##NAMESUFFIX[i] }; \
+\
+      tmp = vec_addec (v1, v2, v3); \
+      result_##NAMESUFFIX[i] = tmp[0]; \
+    } \
+} \
+\
+__attribute__((noinline)) void init_##NAMESUFFIX () \
+{ \
+  int i; \
+  for (i = 0; i < N; ++i) \
+    { \
+      result_##NAMESUFFIX[i] = 0; \
+      if (i%6 == 0) \
+       { \
+         addend1_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64); \
+         addend2_##NAMESUFFIX[i] =  0xfffffffffffffffe; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 0; \
+       } \
+      else if (i%6 == 1) \
+       { \
+         addend1_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64) + \
+                                   0xffffffffffffffff; \
+         addend2_##NAMESUFFIX[i] = 1; \
+         carry_##NAMESUFFIX[i] = 0; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 2) \
+       { \
+         addend1_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64) + \
+                                   0xffffffffffffffff; \
+         addend2_##NAMESUFFIX[i] = 0; \
+         carry_##NAMESUFFIX[i] = 3; /* 3 should work like 1 here.  */ \
+         expected_##NAMESUFFIX[i] = 1; \
+       }  \
+      else if (i%6 == 3) \
+       { \
+         addend1_##NAMESUFFIX[i] = 1; \
+         addend2_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64) + \
+                                   0xffffffffffffffff; \
+         carry_##NAMESUFFIX[i] = 2; /* 2 should work like 0 here.  */ \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 4) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0; \
+         addend2_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64) + \
+                                   0xffffffffffffffff; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 5) \
+       { \
+         addend1_##NAMESUFFIX[i] = ((__int128)0xffffffffffffffff << 64); \
+         addend2_##NAMESUFFIX[i] = 0xffffffffffffffff; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+    } \
+} \
+\
+__attribute__((noinline)) void verify_results_##NAMESUFFIX () \
+{ \
+  int i; \
+  for (i = 0; i < N; ++i) \
+    { \
+      if (result_##NAMESUFFIX[i] != expected_##NAMESUFFIX[i]) \
+       abort (); \
+    } \
+}
+
+
+#define execute_test_functions(STYPE, NAMESUFFIX) \
+{ \
+  init_##NAMESUFFIX (); \
+  vector_tests_##NAMESUFFIX (); \
+  verify_results_##NAMESUFFIX (); \
+}
+
+
+define_test_functions (signed __int128, si128);
+define_test_functions (unsigned __int128, ui128);
+
+int main ()
+{
+  execute_test_functions (signed __int128, si128);
+  execute_test_functions (unsigned __int128, ui128);
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/gcc.target/powerpc/vec-addec.c b/gcc/testsuite/gcc.target/powerpc/vec-addec.c
new file mode 100644 (file)
index 0000000..53bd41f
--- /dev/null
@@ -0,0 +1,119 @@
+/* { dg-do run { target { powerpc64*-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3" } */
+
+/* Test that the vec_addec builtin works as expected.  */
+
+#include "altivec.h"
+
+#define N 4096
+
+void abort ();
+
+#define define_test_functions(STYPE, NAMESUFFIX) \
+\
+STYPE result_##NAMESUFFIX[N]; \
+STYPE addend1_##NAMESUFFIX[N]; \
+STYPE addend2_##NAMESUFFIX[N]; \
+STYPE carry_##NAMESUFFIX[N]; \
+STYPE expected_##NAMESUFFIX[N]; \
+\
+__attribute__((noinline)) void vector_tests_##NAMESUFFIX () \
+{ \
+  vector STYPE v1, v2, v3, tmp; \
+  int i; \
+  for (i = 0; i < N; i+=16/sizeof (STYPE)) \
+    { \
+      /* result=carry of addend1+addend2+(carry & 0x1).  */ \
+      v1 = vec_vsx_ld (0, &addend1_##NAMESUFFIX[i]); \
+      v2 = vec_vsx_ld (0, &addend2_##NAMESUFFIX[i]); \
+      v3 = vec_vsx_ld (0, &carry_##NAMESUFFIX[i]); \
+\
+      tmp = vec_addec (v1, v2, v3); \
+      vec_vsx_st (tmp, 0, &result_##NAMESUFFIX[i]); \
+    } \
+} \
+\
+__attribute__((noinline)) void init_##NAMESUFFIX () \
+{ \
+  int i; \
+  for (i = 0; i < N; ++i) \
+    { \
+      result_##NAMESUFFIX[i] = 0; \
+      if (i%6 == 0) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0xfffffffd; \
+         addend2_##NAMESUFFIX[i] =  1; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 0; \
+       } \
+      else if (i%6 == 1) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0xffffffff; \
+         addend2_##NAMESUFFIX[i] = 1; \
+         carry_##NAMESUFFIX[i] = 0; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 2) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0xffffffff; \
+         addend2_##NAMESUFFIX[i] = 0; \
+         carry_##NAMESUFFIX[i] = 3; /* 3 should work like 1 here.  */ \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 3) \
+       { \
+         addend1_##NAMESUFFIX[i] = 1; \
+         addend2_##NAMESUFFIX[i] = 0xffffffff; \
+         carry_##NAMESUFFIX[i] = 2; /* 2 should work like 0 here.  */ \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 4) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0; \
+         addend2_##NAMESUFFIX[i] = 0xffffffff; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+      else if (i%6 == 5) \
+       { \
+         addend1_##NAMESUFFIX[i] = 0xffff0000; \
+         addend2_##NAMESUFFIX[i] = 0x0000ffff; \
+         carry_##NAMESUFFIX[i] = 1; \
+         expected_##NAMESUFFIX[i] = 1; \
+       } \
+    } \
+} \
+\
+__attribute__((noinline)) void verify_results_##NAMESUFFIX () \
+{ \
+  int i; \
+  for (i = 0; i < N; ++i) \
+    { \
+      if (result_##NAMESUFFIX[i] != expected_##NAMESUFFIX[i]) \
+       abort (); \
+    } \
+}
+
+
+#define execute_test_functions(STYPE, NAMESUFFIX) \
+{ \
+  init_##NAMESUFFIX (); \
+  vector_tests_##NAMESUFFIX (); \
+  verify_results_##NAMESUFFIX (); \
+}
+
+
+define_test_functions (signed int, si);
+define_test_functions (unsigned int, ui);
+
+int main ()
+{
+  execute_test_functions (signed int, si);
+  execute_test_functions (unsigned int, ui);
+
+  return 0;
+}
+
+