This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: Endian swapping with C code on ARM
Richard Earnshaw <rearnsha@gcc.gnu.org> writes:
> Having a builtin is OK, provided there's something to fall back on
> if it doesn't exist for a particular port. I'm not aware of a
> generally available (all OSes) library function that does a byte
> swap.
I've attached my old patch. It uses a libgcc function as fallback. If
it seems OK, I could tie up the loose ends and send it to gcc-patches.
> You also get into issues of word size. Which builtins do you
> provide? 32-bit? 16-bit? 64-bit?
In theory, any attempt to describe a 16-bit bswap should be recognized
as 16 bit rotation. So my patch provides only 32 and 64.
> When is it best to stop trying to inline all this and drop into a
> library call?
This patch never open-codes bswap. I'm not sure if it would be worth
doing, since basically every platform has some trick that would save a
cycle or two over generic inlined code.
--
Falk
diff -x build -Nurp gcc/gcc/builtins.c gcc-3.5-2004.07.09/gcc/builtins.c
--- gcc/gcc/builtins.c 2004-07-09 05:37:13.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/builtins.c 2004-07-09 18:31:11.000000000 +0200
@@ -6015,6 +6015,20 @@ expand_builtin (tree exp, rtx target, rt
return target;
break;
+ case BUILT_IN_BSWAP32:
+ target = expand_builtin_unop (SImode, arglist, target,
+ subtarget, bswap_optab);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_BSWAP64:
+ target = expand_builtin_unop (DImode, arglist, target,
+ subtarget, bswap_optab);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_STRLEN:
target = expand_builtin_strlen (arglist, target, target_mode);
if (target)
diff -x build -Nurp gcc/gcc/builtins.def gcc-3.5-2004.07.09/gcc/builtins.def
--- gcc/gcc/builtins.def 2004-07-01 10:02:31.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/builtins.def 2004-07-09 18:34:15.000000000 +0200
@@ -540,6 +540,8 @@ 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_BSWAP32, "bswap32", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_BSWAP64, "bswap64", 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_INT, ATTR_CONST_NOTHROW_LIST)
diff -x build -Nurp gcc/gcc/config/alpha/alpha.md gcc-3.5-2004.07.09/gcc/config/alpha/alpha.md
--- gcc/gcc/config/alpha/alpha.md 2004-07-07 21:24:03.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/config/alpha/alpha.md 2004-07-09 18:31:20.000000000 +0200
@@ -1363,6 +1363,36 @@
"TARGET_CIX"
"ctpop %1,%0"
[(set_attr "type" "mvi")])
+
+(define_expand "bswapsi2"
+ [(match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")]
+ ""
+{
+ rtx temp1, temp2, temp3, temp4, temp5, temp6;
+
+ temp1 = gen_reg_rtx (DImode);
+ temp2 = gen_reg_rtx (DImode);
+ temp3 = gen_reg_rtx (DImode);
+ temp4 = gen_reg_rtx (DImode);
+ temp5 = gen_reg_rtx (DImode);
+ temp6 = gen_reg_rtx (DImode);
+
+ operands[0] = gen_lowpart (DImode, operands[0]);
+ operands[1] = gen_lowpart (DImode, operands[1]);
+
+ /* Use Mike Burrows' 7-insn sequence. */
+ emit_insn (gen_insxh (temp1, operands[1], GEN_INT (32), GEN_INT (7)));
+ emit_insn (gen_inswl_le (temp2, gen_lowpart(HImode, operands[1]),
+ GEN_INT (3)));
+ emit_insn (gen_iordi3 (temp3, temp1, temp2));
+ emit_insn (gen_lshrdi3 (temp4, temp3, GEN_INT (16)));
+ emit_insn (gen_anddi3 (temp5, temp3, GEN_INT (0xff00ff00)));
+ emit_insn (gen_anddi3 (temp6, temp4, GEN_INT (0x00ff00ff)));
+ emit_insn (gen_adddi3 (operands[0], temp5, temp6));
+
+ DONE;
+})
;; Next come the shifts and the various extract and insert operations.
diff -x build -Nurp gcc/gcc/genopinit.c gcc-3.5-2004.07.09/gcc/genopinit.c
--- gcc/gcc/genopinit.c 2004-07-07 21:23:59.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/genopinit.c 2004-07-09 18:31:20.000000000 +0200
@@ -148,6 +148,7 @@ static const char * const optabs[] =
"ctz_optab->handlers[$A].insn_code = CODE_FOR_$(ctz$a2$)",
"popcount_optab->handlers[$A].insn_code = CODE_FOR_$(popcount$a2$)",
"parity_optab->handlers[$A].insn_code = CODE_FOR_$(parity$a2$)",
+ "bswap_optab->handlers[$A].insn_code = CODE_FOR_$(bswap$a2$)",
"mov_optab->handlers[$A].insn_code = CODE_FOR_$(mov$a$)",
"movstrict_optab->handlers[$A].insn_code = CODE_FOR_$(movstrict$a$)",
"cmp_optab->handlers[$A].insn_code = CODE_FOR_$(cmp$a$)",
diff -x build -Nurp gcc/gcc/libgcc-std.ver gcc-3.5-2004.07.09/gcc/libgcc-std.ver
--- gcc/gcc/libgcc-std.ver 2004-06-12 06:34:58.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/libgcc-std.ver 2004-07-09 18:31:20.000000000 +0200
@@ -215,4 +215,7 @@ GCC_3.4 {
__paritysi2
__paritydi2
__parityti2
+ # byte swapping
+ __bswapsi2
+ __bswapdi2
}
diff -x build -Nurp gcc/gcc/libgcc2.c gcc-3.5-2004.07.09/gcc/libgcc2.c
--- gcc/gcc/libgcc2.c 2004-05-20 01:43:13.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/libgcc2.c 2004-07-09 18:31:20.000000000 +0200
@@ -772,6 +772,32 @@ __parityDI2 (UDWtype x)
return (0x6996 >> nx) & 1;
}
#endif
+
+#ifdef L_bswapsi2
+USItype
+__bswapsi2 (USItype x)
+{
+ return ((x & 0x000000ff) << 24)
+ | ((x & 0x0000ff00) << 8)
+ | ((x & 0x00ff0000) >> 8)
+ | ((x & 0xff000000) >> 24);
+}
+#endif
+
+#ifdef L_bswapdi2
+UDItype
+__bswapdi2 (UDItype x)
+{
+ return ((x & 0xff00000000000000ULL) >> 56)
+ | ((x & 0x00ff000000000000ULL) >> 40)
+ | ((x & 0x0000ff0000000000ULL) >> 24)
+ | ((x & 0x000000ff00000000ULL) >> 8)
+ | ((x & 0x00000000ff000000ULL) << 8)
+ | ((x & 0x0000000000ff0000ULL) << 24)
+ | ((x & 0x000000000000ff00ULL) << 40)
+ | ((x & 0x00000000000000ffULL) << 56);
+}
+#endif
#ifdef L_udivmoddi4
diff -x build -Nurp gcc/gcc/libgcc2.h gcc-3.5-2004.07.09/gcc/libgcc2.h
--- gcc/gcc/libgcc2.h 2003-12-21 15:08:34.000000000 +0100
+++ gcc-3.5-2004.07.09/gcc/libgcc2.h 2004-07-09 18:31:20.000000000 +0200
@@ -221,6 +221,9 @@ typedef int word_type __attribute__ ((mo
#define __popcountDI2 __NDW(popcount,2)
#define __parityDI2 __NDW(parity,2)
+extern USItype __bswapsi2 (USItype);
+extern UDItype __bswapdi2 (UDItype);
+
extern DWtype __muldi3 (DWtype, DWtype);
extern DWtype __divdi3 (DWtype, DWtype);
extern UDWtype __udivdi3 (UDWtype, UDWtype);
diff -x build -Nurp gcc/gcc/mklibgcc.in gcc-3.5-2004.07.09/gcc/mklibgcc.in
--- gcc/gcc/mklibgcc.in 2004-03-19 04:32:07.000000000 +0100
+++ gcc-3.5-2004.07.09/gcc/mklibgcc.in 2004-07-09 18:31:20.000000000 +0200
@@ -51,7 +51,7 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ash
_trampoline __main _absvsi2 _absvdi2 _addvsi3 _addvdi3
_subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
- _popcountsi2 _popcountdi2 _paritysi2 _paritydi2'
+ _popcountsi2 _popcountdi2 _paritysi2 _paritydi2_bswapsi2 _bswapdi2'
# Disable SHLIB_LINK if shared libgcc not enabled.
if [ "@enable_shared@" = "no" ]; then
diff -x build -Nurp gcc/gcc/optabs.c gcc-3.5-2004.07.09/gcc/optabs.c
--- gcc/gcc/optabs.c 2004-07-09 05:29:34.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/optabs.c 2004-07-09 18:44:46.000000000 +0200
@@ -5377,6 +5377,7 @@ init_optabs (void)
ctz_optab = init_optab (CTZ);
popcount_optab = init_optab (POPCOUNT);
parity_optab = init_optab (PARITY);
+ bswap_optab = init_optab (BSWAP);
sqrt_optab = init_optab (SQRT);
floor_optab = init_optab (UNKNOWN);
ceil_optab = init_optab (UNKNOWN);
@@ -5513,6 +5514,9 @@ init_optabs (void)
ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
= init_one_libfunc ("ffs");
+ bswap_optab->handlers[(int) SImode].libfunc = init_one_libfunc ("__bswapsi2");
+ bswap_optab->handlers[(int) DImode].libfunc = init_one_libfunc ("__bswapdi2");
+
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
diff -x build -Nurp gcc/gcc/optabs.h gcc-3.5-2004.07.09/gcc/optabs.h
--- gcc/gcc/optabs.h 2004-07-07 21:24:00.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/optabs.h 2004-07-09 18:31:20.000000000 +0200
@@ -149,6 +149,8 @@ enum optab_index
OTI_ctz,
OTI_popcount,
OTI_parity,
+ /* Byte swapping */
+ OTI_bswap,
/* Square root */
OTI_sqrt,
/* Sine-Cosine */
@@ -281,6 +283,7 @@ extern GTY(()) optab optab_table[OTI_MAX
#define ctz_optab (optab_table[OTI_ctz])
#define popcount_optab (optab_table[OTI_popcount])
#define parity_optab (optab_table[OTI_parity])
+#define bswap_optab (optab_table[OTI_bswap])
#define sqrt_optab (optab_table[OTI_sqrt])
#define sincos_optab (optab_table[OTI_sincos])
#define sin_optab (optab_table[OTI_sin])
diff -x build -Nurp gcc/gcc/rtl.def gcc-3.5-2004.07.09/gcc/rtl.def
--- gcc/gcc/rtl.def 2004-07-04 10:06:54.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/rtl.def 2004-07-09 18:31:20.000000000 +0200
@@ -1106,6 +1106,9 @@ DEF_RTL_EXPR(POPCOUNT, "popcount", "e",
/* Population parity (number of 1 bits modulo 2). */
DEF_RTL_EXPR(PARITY, "parity", "e", RTX_UNARY)
+/* Byte swapping (reverse order of bytes). */
+DEF_RTL_EXPR(BSWAP, "bswap", "e", '1')
+
/* Reference to a signed bit-field of specified size and position.
Operand 0 is the memory unit (usually SImode or QImode) which
contains the field's first bit. Operand 1 is the width, in bits.
diff -x build -Nurp gcc/gcc/simplify-rtx.c gcc-3.5-2004.07.09/gcc/simplify-rtx.c
--- gcc/gcc/simplify-rtx.c 2004-07-01 15:09:39.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/simplify-rtx.c 2004-07-09 18:31:20.000000000 +0200
@@ -534,6 +534,9 @@ simplify_unary_operation (enum rtx_code
val &= 1;
break;
+ case BSWAP:
+ return 0; /* FIXME */
+
case TRUNCATE:
val = arg0;
break;
diff -x build -Nurp gcc/gcc/tree.def gcc-3.5-2004.07.09/gcc/tree.def
--- gcc/gcc/tree.def 2004-07-08 09:45:46.000000000 +0200
+++ gcc-3.5-2004.07.09/gcc/tree.def 2004-07-09 18:31:20.000000000 +0200
@@ -624,6 +624,9 @@ DEFTREECODE (MAX_EXPR, "max_expr", '2',
operand of the ABS_EXPR must have the same type. */
DEFTREECODE (ABS_EXPR, "abs_expr", '1', 1)
+/* Byte swapping. */
+DEFTREECODE (BSWAP_EXPR, "bswap_expr", '1', 1)
+
/* Shift operations for shift and rotate.
Shift means logical shift if done on an
unsigned type, arithmetic shift if done on a signed type.