summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/builtins.c')
-rw-r--r--contrib/gcc/builtins.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/contrib/gcc/builtins.c b/contrib/gcc/builtins.c
index a65d725..ffae159 100644
--- a/contrib/gcc/builtins.c
+++ b/contrib/gcc/builtins.c
@@ -4589,6 +4589,30 @@ expand_builtin_alloca (tree arglist, rtx target)
return result;
}
+/* Expand a call to a bswap builtin. The arguments are in ARGLIST. MODE
+ is the mode to expand with. */
+
+static rtx
+expand_builtin_bswap (tree arglist, rtx target, rtx subtarget)
+{
+ enum machine_mode mode;
+ tree arg;
+ rtx op0;
+
+ if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ mode = TYPE_MODE (TREE_TYPE (arg));
+ op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+
+ target = expand_unop (mode, bswap_optab, op0, target, 1);
+
+ gcc_assert (target);
+
+ return convert_to_mode (mode, target, 0);
+}
+
/* Expand a call to a unary builtin. The arguments are in ARGLIST.
Return 0 if a normal call should be emitted rather than expanding the
function in-line. If convenient, the result should be placed in TARGET.
@@ -5877,6 +5901,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
expand_stack_restore (TREE_VALUE (arglist));
return const0_rtx;
+ case BUILT_IN_BSWAP32:
+ case BUILT_IN_BSWAP64:
+ target = expand_builtin_bswap (arglist, target, subtarget);
+
+ if (target)
+ return target;
+ break;
+
CASE_INT_FN (BUILT_IN_FFS):
case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
@@ -7539,6 +7571,67 @@ fold_builtin_bitop (tree fndecl, tree arglist)
return NULL_TREE;
}
+/* Fold function call to builtin_bswap and the long and long long
+ variants. Return NULL_TREE if no simplification can be made. */
+static tree
+fold_builtin_bswap (tree fndecl, tree arglist)
+{
+ tree arg;
+
+ if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+
+ /* Optimize constant value. */
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (arg))
+ {
+ HOST_WIDE_INT hi, width, r_hi = 0;
+ unsigned HOST_WIDE_INT lo, r_lo = 0;
+ tree type;
+
+ type = TREE_TYPE (arg);
+ width = TYPE_PRECISION (type);
+ lo = TREE_INT_CST_LOW (arg);
+ hi = TREE_INT_CST_HIGH (arg);
+
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_BSWAP32:
+ case BUILT_IN_BSWAP64:
+ {
+ int s;
+
+ for (s = 0; s < width; s += 8)
+ {
+ int d = width - s - 8;
+ unsigned HOST_WIDE_INT byte;
+
+ if (s < HOST_BITS_PER_WIDE_INT)
+ byte = (lo >> s) & 0xff;
+ else
+ byte = (hi >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
+
+ if (d < HOST_BITS_PER_WIDE_INT)
+ r_lo |= byte << d;
+ else
+ r_hi |= byte << (d - HOST_BITS_PER_WIDE_INT);
+ }
+ }
+
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (width < HOST_BITS_PER_WIDE_INT)
+ return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), r_lo);
+ else
+ return build_int_cst_wide (TREE_TYPE (TREE_TYPE (fndecl)), r_lo, r_hi);
+ }
+
+ return NULL_TREE;
+}
/* Return true if EXPR is the real constant contained in VALUE. */
static bool
@@ -9053,6 +9146,10 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
CASE_FLT_FN (BUILT_IN_LLRINT):
return fold_fixed_mathfn (fndecl, arglist);
+ case BUILT_IN_BSWAP32:
+ case BUILT_IN_BSWAP64:
+ return fold_builtin_bswap (fndecl, arglist);
+
CASE_INT_FN (BUILT_IN_FFS):
CASE_INT_FN (BUILT_IN_CLZ):
CASE_INT_FN (BUILT_IN_CTZ):
OpenPOWER on IntegriCloud