From: Eric Botcazou Date: Wed, 27 May 2020 22:31:15 +0000 (+0200) Subject: Add support for __builtin_bswap128 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fe7ebef7fe4f9acb79658ed9db0749b07efc3105;p=gcc.git Add support for __builtin_bswap128 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. --- diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index c7aa691b243..c46b1bc5cbd 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -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) diff --git a/gcc/builtins.c b/gcc/builtins.c index 53bae599d3e..f7bb87e4690 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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: diff --git a/gcc/builtins.def b/gcc/builtins.def index fa8b0641ab1..ee67ac15d5c 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -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) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a2ebef8cf8c..cced19d2018 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index 29dab0f24f6..c9e368db9d0 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -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; diff --git a/gcc/fold-const.c b/gcc/fold-const.c index f054871746c..212d0ba0aab 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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; diff --git a/gcc/optabs.c b/gcc/optabs.c index d85ce47f762..7a4ec1ec01c 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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 index 00000000000..6c8a39f17d0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-bswap-10.c @@ -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 index 00000000000..3fedcf1bd3c --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-bswap-11.c @@ -0,0 +1,51 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int128 } */ +/* { dg-require-effective-target stdint_types } */ +/* { dg-options "-Wall" } */ + +#include + +#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 index 00000000000..8ff65d85300 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-bswap-12.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int128 } */ +/* { dg-require-effective-target stdint_types } */ +/* { dg-options "-O" } */ + +#include + +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 index 00000000000..a73a870dad2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/builtin-bswap-5.c @@ -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); +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 03091486731..8c5a2e3c404 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -600,6 +600,7 @@ enum tree_index { TI_UINT16_TYPE, TI_UINT32_TYPE, TI_UINT64_TYPE, + TI_UINT128_TYPE, TI_VOID, diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index be6647db894..e9d2f4bc27a 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -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; diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 35043ecd0f9..2f92bb5555e 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -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 diff --git a/gcc/tree.c b/gcc/tree.c index ea6692476e7..2cc9e4f66e3 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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 ()) diff --git a/gcc/tree.h b/gcc/tree.h index 0c8585f6e22..21a96b2b920 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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]