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.
This commit is contained in:
Eric Botcazou 2020-05-28 00:31:15 +02:00
parent bbaec68c86
commit fe7ebef7fe
16 changed files with 125 additions and 5 deletions

View 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)

View 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:

View 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)

View 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

View 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;

View 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;

View 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)

View File

@ -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" } */
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -600,6 +600,7 @@ enum tree_index {
TI_UINT16_TYPE,
TI_UINT32_TYPE,
TI_UINT64_TYPE,
TI_UINT128_TYPE,
TI_VOID,

View 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;

View 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

View 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 ())

View 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]