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 c7aa691b243771c9768d524026600cb484115092..c46b1bc5cbd1fba03b033b8d44ba186570780c3f 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 53bae599d3e2ddfe4c08f5b37dd5c51c245512bf..f7bb87e4690f2f5a76d68c6fa907f958d877c458 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 fa8b0641ab13b36f983c591a7020f6b432e5fb3d..ee67ac15d5cf98797144b9d08a75f4cf7ee5ad33 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 a2ebef8cf8ca30f073e65744632268c6a221178e..cced19d20181a1ca8d3ab88b4cba55762f3ee13f 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 29dab0f24f64ffa720cf5069ca3945ff7f83183a..c9e368db9d01b77a141c29056ed095a329cce7ac 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 f054871746cd79c97a56b99cf36fe988a0738ba0..212d0ba0aab527dfd9338db2277013372eef47dd 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 d85ce47f7624d2e808a77bc9a79bb3b283753144..7a4ec1ec01c6b0ab09ce7390a025ddf6e759f1a9 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 03091486731d5ca28d1e32bda866a8c7d59ecc4b..8c5a2e3c4041248d2928c613cf7062b259abf2a4 100644 (file)
@@ -600,6 +600,7 @@ enum tree_index {
   TI_UINT16_TYPE,
   TI_UINT32_TYPE,
   TI_UINT64_TYPE,
+  TI_UINT128_TYPE,
 
   TI_VOID,
 
index be6647db894d2673bc819fc106e6198e13316be8..e9d2f4bc27ae3dad90b5951eb5dc8db9003260ab 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 35043ecd0f912786b56e413abd9e70b0b4f8c179..2f92bb5555e6590002e2d688bc7276a99a96a624 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 ea6692476e71793e5be2a0d3634c72449d0a1e98..2cc9e4f66e37817b2b8f5711dd92fb49502639dd 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 0c8585f6e22788fd1ebf10fe26d47f41f2efb7b8..21a96b2b920b27eb25d1717ac174630947bf1beb 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]