This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC, patch] implement __builtin_bswap
- From: Eric Christopher <echristo at apple dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 10 Jul 2006 18:52:00 -0700
- Subject: [RFC, patch] implement __builtin_bswap
This patch appears to implement all of builtin_bswap for SI and DImodes.
I've tested it with mipsisa64-elf, mips-elf, x86-darwin, x86-linux
without regressions. A good chunk of my testing was making sure that the
hardware implementation for x86 matched the software implementation in
libgcc. Any review of the SI and DImode routines in there would be
appreciated.
The current testcases check that the instructions or libgcc routines are
generated and work forward and backward.
A scanning routine to generate this automagically would be good, but I
haven't done it yet.
Thoughts? OK for 4.3? Other feedback?
-eric
2006-07-10 Eric Christopher <echristo@apple.com>
* optabs.c (init_optabs): Add bswap_optab.
(init_integral_libfuncs): Ditto.
* optabs.h (optab_index): Add OTI_bswap.
(bswap_optab): New.
* genopinit.c (optabs): Add handler for bswap_optab.
* builtins.c (expand_builtin): Add BUILT_IN_BSWAP.
* builtins.def (BUILT_IN_BSWAP): New.
(BUILT_IN_BSWAPL): Ditto.
(BUILT_IN_BSWAPLL): Ditto.
* rtl.def: Add bswap.
* libgcc2.c (bswapSI2): New.
(bswapDI2): Ditto.
* libgcc2.h (bswapSI2): Declare.
(bswapDI2): Ditto.
* mklibgcc.in (lib2funcs): Add __bswapsi2 and __bswapdi2.
* libgcc-std.ver (GCC_4.2.0): Add __bswapsi2 and __bswapdi2.
* config/i386/i386.h (x86_bswap): New.
(TARGET_BSWAP): Ditto.
* config/i386/i386.c (x86_bswap): New.
* config/i386/i386.md (bswapsi2): New.
(bswapdi2): Ditto.
2006-07-10 Eric Christopher <echristo@apple.com>
* gcc.target/i386/builtin-bswap-1.c: New.
* gcc.dg/builtin-bswap-1.c: Ditto.
* gcc.dg/builtin-bswap-2.c: Ditto.
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c (revision 115311)
+++ gcc/optabs.c (working copy)
@@ -5244,6 +5244,7 @@ init_optabs (void)
absv_optab = init_optabv (ABS);
addcc_optab = init_optab (UNKNOWN);
one_cmpl_optab = init_optab (NOT);
+ bswap_optab = init_optab (BSWAP);
ffs_optab = init_optab (FFS);
clz_optab = init_optab (CLZ);
ctz_optab = init_optab (CTZ);
@@ -5394,6 +5395,7 @@ init_optabs (void)
init_integral_libfuncs (negv_optab, "negv", '2');
init_floating_libfuncs (negv_optab, "neg", '2');
init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
+ init_integral_libfuncs (bswap_optab, "bswap", '2');
init_integral_libfuncs (ffs_optab, "ffs", '2');
init_integral_libfuncs (clz_optab, "clz", '2');
init_integral_libfuncs (ctz_optab, "ctz", '2');
Index: gcc/optabs.h
===================================================================
--- gcc/optabs.h (revision 115311)
+++ gcc/optabs.h (working copy)
@@ -146,6 +146,8 @@ enum optab_index
/* Abs value */
OTI_abs,
OTI_absv,
+ /* Byteswap */
+ OTI_bswap,
/* Bitwise not */
OTI_one_cmpl,
/* Bit scanning and counting */
@@ -315,6 +317,7 @@ extern GTY(()) optab optab_table[OTI_MAX
#define abs_optab (optab_table[OTI_abs])
#define absv_optab (optab_table[OTI_absv])
#define one_cmpl_optab (optab_table[OTI_one_cmpl])
+#define bswap_optab (optab_table[OTI_bswap])
#define ffs_optab (optab_table[OTI_ffs])
#define clz_optab (optab_table[OTI_clz])
#define ctz_optab (optab_table[OTI_ctz])
Index: gcc/genopinit.c
===================================================================
--- gcc/genopinit.c (revision 115311)
+++ gcc/genopinit.c (working copy)
@@ -148,6 +148,7 @@ static const char * const optabs[] =
"atan_optab->handlers[$A].insn_code = CODE_FOR_$(atan$a2$)",
"strlen_optab->handlers[$A].insn_code = CODE_FOR_$(strlen$a$)",
"one_cmpl_optab->handlers[$A].insn_code = CODE_FOR_$(one_cmpl$a2$)",
+ "bswap_optab->handlers[$A].insn_code = CODE_FOR_$(bswap$a2$)",
"ffs_optab->handlers[$A].insn_code = CODE_FOR_$(ffs$a2$)",
"clz_optab->handlers[$A].insn_code = CODE_FOR_$(clz$a2$)",
"ctz_optab->handlers[$A].insn_code = CODE_FOR_$(ctz$a2$)",
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c (revision 115311)
+++ gcc/builtins.c (working copy)
@@ -5825,6 +5825,13 @@ expand_builtin (tree exp, rtx target, rt
expand_stack_restore (TREE_VALUE (arglist));
return const0_rtx;
+ CASE_INT_FN (BUILT_IN_BSWAP):
+ target = expand_builtin_unop (target_mode, arglist, target,
+ subtarget, bswap_optab);
+ if (target)
+ return target;
+ break;
+
CASE_INT_FN (BUILT_IN_FFS):
case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def (revision 115311)
+++ gcc/builtins.def (working copy)
@@ -594,6 +594,9 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_ALLOCA,
DEF_GCC_BUILTIN (BUILT_IN_APPLY, "apply", BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_ARGS_INFO, "args_info", BT_FN_INT_INT, ATTR_NULL)
+DEF_GCC_BUILTIN (BUILT_IN_BSWAP, "bswap", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_BSWAPL, "bswapl", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_BSWAPLL, "bswapll", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLASSIFY_TYPE, "classify_type", BT_FN_INT_VAR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LIST)
Index: gcc/rtl.def
===================================================================
--- gcc/rtl.def (revision 115311)
+++ gcc/rtl.def (working copy)
@@ -567,6 +567,9 @@ DEF_RTL_EXPR(ABS, "abs", "e", RTX_UNARY)
/* Square root */
DEF_RTL_EXPR(SQRT, "sqrt", "e", RTX_UNARY)
+/* Swap bytes. */
+DEF_RTL_EXPR(BSWAP, "bswap", "e", RTX_UNARY)
+
/* Find first bit that is set.
Value is 1 + number of trailing zeros in the arg.,
or 0 if arg is 0. */
Index: gcc/libgcc2.c
===================================================================
--- gcc/libgcc2.c (revision 115311)
+++ gcc/libgcc2.c (working copy)
@@ -492,6 +492,24 @@ __ashrdi3 (DWtype u, word_type b)
}
#endif
+#ifdef L_bswapsi2
+Wtype
+__bswapSI2 (Wtype u)
+{
+ return ((((u) & 0xff000000) >> 24) | (((u) & 0x00ff0000) >> 8) |
+ (((u) & 0x0000ff00) << 8) | (((u) & 0x000000ff) << 24));
+}
+#endif
+#ifdef L_bswapdi2
+DWtype
+__bswapDI2 (DWtype u)
+{
+ return ((((u) & 0xff00000000000000ull) >> 56) | (((u) & 0x00ff000000000000ull) >> 40) |
+ (((u) & 0x0000ff0000000000ull) >> 24) | (((u) & 0x000000ff00000000ull) >> 8) |
+ (((u) & 0x00000000ff000000ull) << 8) | (((u) & 0x0000000000ff0000ull) << 24) |
+ (((u) & 0x000000000000ff00ull) << 40) | (((u) & 0x00000000000000ffull) << 56));
+}
+#endif
#ifdef L_ffssi2
#undef int
int
Index: gcc/libgcc2.h
===================================================================
--- gcc/libgcc2.h (revision 115311)
+++ gcc/libgcc2.h (working copy)
@@ -304,11 +304,14 @@ typedef int word_type __attribute__ ((mo
#define __ctzSI2 __NW(ctz,2)
#define __popcountSI2 __NW(popcount,2)
#define __paritySI2 __NW(parity,2)
+#define __bswapSI2 __NW(bswap,2)
#define __ffsDI2 __NDW(ffs,2)
#define __clzDI2 __NDW(clz,2)
#define __ctzDI2 __NDW(ctz,2)
#define __popcountDI2 __NDW(popcount,2)
#define __parityDI2 __NDW(parity,2)
+#define __bswapDI2 __NDW(bswap,2)
+
extern DWtype __muldi3 (DWtype, DWtype);
extern DWtype __divdi3 (DWtype, DWtype);
@@ -345,11 +348,13 @@ extern Wtype __addvSI3 (Wtype, Wtype);
extern Wtype __subvSI3 (Wtype, Wtype);
extern Wtype __mulvSI3 (Wtype, Wtype);
extern Wtype __negvSI2 (Wtype);
+extern Wtype __bswapSI2 (Wtype);
extern DWtype __absvDI2 (DWtype);
extern DWtype __addvDI3 (DWtype, DWtype);
extern DWtype __subvDI3 (DWtype, DWtype);
extern DWtype __mulvDI3 (DWtype, DWtype);
extern DWtype __negvDI2 (DWtype);
+extern DWtype __bswapDI2 (DWtype);
#ifdef COMPAT_SIMODE_TRAPPING_ARITHMETIC
extern SItype __absvsi2 (SItype);
Index: gcc/mklibgcc.in
===================================================================
--- gcc/mklibgcc.in (revision 115311)
+++ gcc/mklibgcc.in (working copy)
@@ -91,7 +91,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ash
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
- _divxc3 _divtc3'
+ _divxc3 _divtc3 _bswapsi2 _bswapdi2'
if [ "$LIB2_SIDITI_CONV_FUNCS" ]; then
for func in $swfloatfuncs; do
Index: gcc/config/i386/i386.h
===================================================================
--- gcc/config/i386/i386.h (revision 115311)
+++ gcc/config/i386/i386.h (working copy)
@@ -164,6 +164,7 @@ extern const int x86_use_bt;
extern const int x86_cmpxchg, x86_cmpxchg8b, x86_cmpxchg16b, x86_xadd;
extern const int x86_use_incdec;
extern const int x86_pad_returns;
+extern const int x86_bswap;
extern int x86_prefetch_sse;
#define TARGET_USE_LEAVE (x86_use_leave & TUNEMASK)
@@ -236,6 +237,7 @@ extern int x86_prefetch_sse;
#define TARGET_CMPXCHG8B (x86_cmpxchg8b & (1 << ix86_arch))
#define TARGET_CMPXCHG16B (x86_cmpxchg16b & (1 << ix86_arch))
#define TARGET_XADD (x86_xadd & (1 << ix86_arch))
+#define TARGET_BSWAP (x86_bswap & (1 << ix86_arch))
#ifndef TARGET_64BIT_DEFAULT
#define TARGET_64BIT_DEFAULT 0
Index: gcc/config/i386/i386.md
===================================================================
--- gcc/config/i386/i386.md (revision 115311)
+++ gcc/config/i386/i386.md (working copy)
@@ -14142,6 +14142,22 @@
"bsr{q}\t{%1, %0|%0, %1}"
[(set_attr "prefix_0f" "1")])
+(define_insn "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (bswap:SI (match_operand:SI 1 "register_operand" "0")))
+ (clobber (reg:CC FLAGS_REG))]
+ "!TARGET_64BIT && TARGET_BSWAP"
+ "bswap\t%1"
+ [(set_attr "prefix_0f" "1")])
+
+(define_insn "bswapdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (bswap:DI (match_operand:DI 1 "register_operand" "0")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT && TARGET_BSWAP"
+ "bswap\t%1"
+ [(set_attr "prefix_0f" "1")])
+
;; Thread-local storage patterns for ELF.
;;
;; Note that these code sequences must appear exactly as shown
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c (revision 115311)
+++ gcc/config/i386/i386.c (working copy)
@@ -829,6 +829,8 @@ const int x86_cmpxchg8b = ~(m_386 | m_48
const int x86_cmpxchg16b = m_NOCONA;
/* Exchange and add was added for 80486. */
const int x86_xadd = ~m_386;
+/* Byteswap was added for 80486. */
+const int x86_bswap = ~m_386;
const int x86_pad_returns = m_ATHLON_K8 | m_GENERIC;
/* In case the average insn count for single function invocation is
Index: gcc/libgcc-std.ver
===================================================================
--- gcc/libgcc-std.ver (revision 115311)
+++ gcc/libgcc-std.ver (working copy)
@@ -273,4 +273,6 @@ GCC_4.2.0 {
__floatuntixf
__floatuntitf
_Unwind_GetIPInfo
+ __bswapsi2
+ __bswapdi2
}
Index: gcc/testsuite/gcc.target/i386/builtin-bswap-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/builtin-bswap-1.c (revision 0)
+++ gcc/testsuite/gcc.target/i386/builtin-bswap-1.c (revision 0)
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=i486" } */
+/* { dg-final { scan-assembler "bswap" } } */
+
+int foo (int a)
+{
+ int b;
+
+ b = __builtin_bswap (a);
+
+ return b;
+}
Index: gcc/testsuite/gcc.dg/builtin-bswap-1.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-bswap-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/builtin-bswap-1.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-final { scan-assembler-not "__builtin_" } } */
+
+extern void abort (void);
+
+int foo (int a)
+{
+ int b;
+
+ b = __builtin_bswap (a);
+
+ return b;
+}
Index: gcc/testsuite/gcc.dg/builtin-bswap-2.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-bswap-2.c (revision 0)
+++ gcc/testsuite/gcc.dg/builtin-bswap-2.c (revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+extern void abort (void);
+
+int main (void)
+{
+ int a = 4;
+ int b;
+
+ b = __builtin_bswap (a);
+ a = __builtin_bswap (b);
+
+ if (a != 4)
+ abort ();
+
+ return 0;
+}