This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]