Add support for __builtin_bswap128
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 27 May 2020 22:31:15 +0000 (00:31 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Wed, 27 May 2020 22:33:04 +0000 (00:33 +0200)
This patch introduces a new builtin named __builtin_bswap128 on targets
where TImode is supported, i.e. 64-bit targets only in practice.  The
implementation simply reuses the existing double word path in optab, so
no routine is added to libgcc (which means that you get two calls to
_bswapdi2 in the worst case).

gcc/ChangeLog:

* builtin-types.def (BT_UINT128): New primitive type.
(BT_FN_UINT128_UINT128): New function type.
* builtins.def (BUILT_IN_BSWAP128): New GCC builtin.
* doc/extend.texi (__builtin_bswap128): Document it.
* builtins.c (expand_builtin): Deal with BUILT_IN_BSWAP128.
(is_inexpensive_builtin): Likewise.
* fold-const-call.c (fold_const_call_ss): Likewise.
* fold-const.c (tree_call_nonnegative_warnv_p): Likewise.
* tree-ssa-ccp.c (evaluate_stmt): Likewise.
* tree-vect-stmts.c (vect_get_data_ptr_increment): Likewise.
(vectorizable_call): Likewise.
* optabs.c (expand_unop): Always use the double word path for it.
* tree-core.h (enum tree_index): Add TI_UINT128_TYPE.
* tree.h (uint128_type_node): New global type.
* tree.c (build_common_tree_nodes): Build it if TImode is supported.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-bswap-10.c: New test.
* gcc.dg/builtin-bswap-11.c: Likewise.
* gcc.dg/builtin-bswap-12.c: Likewise.
* gcc.target/i386/builtin-bswap-5.c: Likewise.

16 files changed:
gcc/builtin-types.def
gcc/builtins.c
gcc/builtins.def
gcc/doc/extend.texi
gcc/fold-const-call.c
gcc/fold-const.c
gcc/optabs.c
gcc/testsuite/gcc.dg/builtin-bswap-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-bswap-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-bswap-12.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/builtin-bswap-5.c [new file with mode: 0644]
gcc/tree-core.h
gcc/tree-ssa-ccp.c
gcc/tree-vect-stmts.c
gcc/tree.c
gcc/tree.h

index c7aa691..c46b1bc 100644 (file)
@@ -73,6 +73,9 @@ DEF_PRIMITIVE_TYPE (BT_UINT8, unsigned_char_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT16, uint16_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT32, uint32_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT64, uint64_type_node)
+DEF_PRIMITIVE_TYPE (BT_UINT128, uint128_type_node
+                               ? uint128_type_node
+                               : error_mark_node)
 DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
 DEF_PRIMITIVE_TYPE (BT_UNWINDWORD, (*lang_hooks.types.type_for_mode)
                                    (targetm.unwind_word_mode (), 1))
@@ -300,6 +303,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_UINT8_FLOAT, BT_UINT8, BT_FLOAT)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT128_UINT128, BT_UINT128, BT_UINT128)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_FLOAT, BT_UINT64, BT_FLOAT)
 DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT)
 DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_PTR, BT_BOOL, BT_PTR)
index 53bae59..f7bb87e 100644 (file)
@@ -7988,6 +7988,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
     case BUILT_IN_BSWAP16:
     case BUILT_IN_BSWAP32:
     case BUILT_IN_BSWAP64:
+    case BUILT_IN_BSWAP128:
       target = expand_builtin_bswap (target_mode, exp, target, subtarget);
       if (target)
        return target;
@@ -11704,6 +11705,7 @@ is_inexpensive_builtin (tree decl)
       case BUILT_IN_BSWAP16:
       case BUILT_IN_BSWAP32:
       case BUILT_IN_BSWAP64:
+      case BUILT_IN_BSWAP128:
       case BUILT_IN_CLZ:
       case BUILT_IN_CLZIMAX:
       case BUILT_IN_CLZL:
index fa8b064..ee67ac1 100644 (file)
@@ -834,6 +834,8 @@ DEF_GCC_BUILTIN        (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_L
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP16, "bswap16", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAP128, "bswap128", BT_FN_UINT128_UINT128, ATTR_CONST_NOTHROW_LEAF_LIST)
+
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
 /* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed.  */
 DEF_LIB_BUILTIN        (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_WARN_UNUSED_RESULT_SIZE_1_2_NOTHROW_LEAF_LIST)
index a2ebef8..cced19d 100644 (file)
@@ -13784,14 +13784,20 @@ exactly 8 bits.
 
 @deftypefn {Built-in Function} uint32_t __builtin_bswap32 (uint32_t x)
 Similar to @code{__builtin_bswap16}, except the argument and return types
-are 32 bit.
+are 32-bit.
 @end deftypefn
 
 @deftypefn {Built-in Function} uint64_t __builtin_bswap64 (uint64_t x)
 Similar to @code{__builtin_bswap32}, except the argument and return types
-are 64 bit.
+are 64-bit.
 @end deftypefn
 
+@deftypefn {Built-in Function} uint128_t __builtin_bswap128 (uint128_t x)
+Similar to @code{__builtin_bswap64}, except the argument and return types
+are 128-bit.  Only supported on targets when 128-bit types are supported.
+@end deftypefn
+
+
 @deftypefn {Built-in Function} Pmode __builtin_extend_pointer (void * x)
 On targets where the user visible pointer size is smaller than the size
 of an actual hardware address this function returns the extended user
index 29dab0f..c9e368d 100644 (file)
@@ -1033,6 +1033,7 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg,
     case CFN_BUILT_IN_BSWAP16:
     case CFN_BUILT_IN_BSWAP32:
     case CFN_BUILT_IN_BSWAP64:
+    case CFN_BUILT_IN_BSWAP128:
       *result = wide_int::from (arg, precision, TYPE_SIGN (arg_type)).bswap ();
       return true;
 
index f054871..212d0ba 100644 (file)
@@ -13794,8 +13794,10 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1,
     CASE_CFN_POPCOUNT:
     CASE_CFN_CLZ:
     CASE_CFN_CLRSB:
+    case CFN_BUILT_IN_BSWAP16:
     case CFN_BUILT_IN_BSWAP32:
     case CFN_BUILT_IN_BSWAP64:
+    case CFN_BUILT_IN_BSWAP128:
       /* Always true.  */
       return true;
 
index d85ce47..7a4ec1e 100644 (file)
@@ -2889,8 +2889,11 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target,
          if (temp)
            return temp;
 
+         /* We do not provide a 128-bit bswap in libgcc so force the use of
+            a double bswap for 64-bit targets.  */
          if (GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
-             && optab_handler (unoptab, word_mode) != CODE_FOR_nothing)
+             && (UNITS_PER_WORD == 64
+                 || optab_handler (unoptab, word_mode) != CODE_FOR_nothing))
            {
              temp = expand_doubleword_bswap (mode, op0, target);
              if (temp)
diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-10.c b/gcc/testsuite/gcc.dg/builtin-bswap-10.c
new file mode 100644 (file)
index 0000000..6c8a39f
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile { target { ilp32 } } } */
+/* { dg-options "" } */
+/* { dg-final { scan-assembler "__builtin_" } } */
+
+int foo (int x)
+{
+  return __builtin_bswap128 (x); /* { dg-warning "implicit declaration" } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-11.c b/gcc/testsuite/gcc.dg/builtin-bswap-11.c
new file mode 100644 (file)
index 0000000..3fedcf1
--- /dev/null
@@ -0,0 +1,51 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-Wall" } */
+
+#include <stdint.h>
+
+#define MAKE_FUN(suffix, type)                                         \
+  type my_bswap##suffix(type x) {                                      \
+    type result = 0;                                                   \
+    int shift;                                                         \
+    for (shift = 0; shift < 8 * sizeof (type); shift += 8)     \
+      {                                                                        \
+       result <<= 8;                                                   \
+       result |= (x >> shift) & 0xff;                                  \
+      }                                                                        \
+    return result;                                                     \
+  }                                                                    \
+
+MAKE_FUN(128, __uint128_t);
+
+extern void abort (void);
+
+typedef union
+{
+  struct { uint64_t lo; uint64_t hi; } s;
+  __uint128_t n;
+} u;
+
+#define NUMS128                                                        \
+  {                                                            \
+    { .s = { 0x0000000000000000ULL, 0x1122334455667788ULL } },         \
+    { .s = { 0x1122334455667788ULL, 0xffffffffffffffffULL } }, \
+    { .s = { 0xffffffffffffffffULL, 0x0000000000000000ULL } }  \
+  }
+
+u uint128_ts[] = NUMS128;
+
+#define N(table) (sizeof (table) / sizeof (table[0]))
+
+int
+main (void)
+{
+  int i;
+
+  for (i = 0; i < N(uint128_ts); i++)
+    if (__builtin_bswap128 (uint128_ts[i].n) != my_bswap128 (uint128_ts[i].n))
+      abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-bswap-12.c b/gcc/testsuite/gcc.dg/builtin-bswap-12.c
new file mode 100644 (file)
index 0000000..8ff65d8
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target stdint_types } */
+/* { dg-options "-O" } */
+
+#include <stdint.h>
+
+typedef union
+{
+  struct { uint64_t lo; uint64_t hi; } s;
+  __uint128_t n;
+} u;
+
+int
+main (void)
+{
+  /* Test constant folding.  */
+  extern void link_error (void);
+
+  const u U1 = { .s = { 0x1122334455667788ULL, 0xffffffffffffffffULL } };
+  const u U2 = { .s = { 0xffffffffffffffffULL, 0x8877665544332211ULL } };
+
+  if (__builtin_bswap128 (U1.n) != U2.n)
+    link_error ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-bswap-5.c b/gcc/testsuite/gcc.target/i386/builtin-bswap-5.c
new file mode 100644 (file)
index 0000000..a73a870
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-final { scan-assembler-not "call" } } */
+
+__uint128_t foo (__uint128_t x)
+{
+  return __builtin_bswap128 (x);
+}
index 0309148..8c5a2e3 100644 (file)
@@ -600,6 +600,7 @@ enum tree_index {
   TI_UINT16_TYPE,
   TI_UINT32_TYPE,
   TI_UINT64_TYPE,
+  TI_UINT128_TYPE,
 
   TI_VOID,
 
index be6647d..e9d2f4b 100644 (file)
@@ -2002,6 +2002,7 @@ evaluate_stmt (gimple *stmt)
            case BUILT_IN_BSWAP16:
            case BUILT_IN_BSWAP32:
            case BUILT_IN_BSWAP64:
+           case BUILT_IN_BSWAP128:
              val = get_value_for_expr (gimple_call_arg (stmt, 0), true);
              if (val.lattice_val == UNDEFINED)
                break;
index 35043ec..2f92bb5 100644 (file)
@@ -3003,7 +3003,7 @@ vect_get_data_ptr_increment (vec_info *vinfo,
   return iv_step;
 }
 
-/* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64}.  */
+/* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}.  */
 
 static bool
 vectorizable_bswap (vec_info *vinfo,
@@ -3385,7 +3385,8 @@ vectorizable_call (vec_info *vinfo,
       else if (modifier == NONE
               && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
                   || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
-                  || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)))
+                  || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
+                  || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
        return vectorizable_bswap (vinfo, stmt_info, gsi, vec_stmt, slp_node,
                                   slp_op, vectype_in, cost_vec);
       else
index ea66924..2cc9e4f 100644 (file)
@@ -10350,6 +10350,8 @@ build_common_tree_nodes (bool signed_char)
   uint16_type_node = make_or_reuse_type (16, 1);
   uint32_type_node = make_or_reuse_type (32, 1);
   uint64_type_node = make_or_reuse_type (64, 1);
+  if (targetm.scalar_mode_supported_p (TImode))
+    uint128_type_node = make_or_reuse_type (128, 1);
 
   /* Decimal float types. */
   if (targetm.decimal_float_supported_p ())
index 0c8585f..21a96b2 100644 (file)
@@ -4037,6 +4037,7 @@ tree_strip_any_location_wrapper (tree exp)
 #define uint16_type_node               global_trees[TI_UINT16_TYPE]
 #define uint32_type_node               global_trees[TI_UINT32_TYPE]
 #define uint64_type_node               global_trees[TI_UINT64_TYPE]
+#define uint128_type_node              global_trees[TI_UINT128_TYPE]
 
 #define void_node                      global_trees[TI_VOID]