commit 7950b0de3d0e172a76c5e694be775614055eadbe
Author: Christophe Lyon <christophe.lyon@st.com>
Date:   Wed Sep 5 10:22:20 2012 +0200

    2012-09-11  Christophe Lyon  <christophe.lyon@linaro.org>
    	    Richard Earnshaw  <rearnsha@arm.com>
    
    	gcc/
    	* config/arm/arm.md (arm_rev): Factorize thumb1, thumb2 and arm
    	variants for rev instruction..
    	(arm_rev_cond): New pattern for conditional variants.
    	(thumb1_rev): Delete pattern.
    	(arm_revsh): New pattern to support builtin_bswap16.
    	(arm_revsh_cond, arm_rev16, arm_rev16_cond, bswaphi2): Likewise.
    
    	gcc/testsuite/
    	* gcc.target/arm/builtin-swap-1.c: New testcase.

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 6a642bf..ff9c1d4 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -11372,20 +11372,26 @@
 )
 
 (define_insn "*arm_rev"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(bswap:SI (match_operand:SI 1 "s_register_operand" "r")))]
+  [(set (match_operand:SI 0 "s_register_operand" "=l,l,r")
+	(bswap:SI (match_operand:SI 1 "s_register_operand" "l,l,r")))]
+  "arm_arch6"
+  "@
+   rev\t%0, %1
+   rev%?\t%0, %1
+   rev%?\t%0, %1"
+  [(set_attr "arch" "t1,t2,32")
+   (set_attr "length" "2,2,4")]
+)
+
+(define_insn "*arm_rev_cond"
+  [(cond_exec (match_operator 2 "arm_comparison_operator"
+	       [(match_operand 3 "cc_register" "") (const_int 0)])
+	      (set (match_operand:SI 0 "s_register_operand" "=l,r")
+		   (bswap:SI (match_operand:SI 1 "s_register_operand" "l,r"))))]
   "TARGET_32BIT && arm_arch6"
   "rev%?\t%0, %1"
-  [(set_attr "predicable" "yes")
-   (set_attr "length" "4")]
-)
-
-(define_insn "*thumb1_rev"
-  [(set (match_operand:SI 0 "s_register_operand" "=l")
-	(bswap:SI (match_operand:SI 1 "s_register_operand" "l")))]
-  "TARGET_THUMB1 && arm_arch6"
-   "rev\t%0, %1"
-  [(set_attr "length" "2")]
+  [(set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
 )
 
 (define_expand "arm_legacy_rev"
@@ -11473,6 +11479,62 @@
   "
 )
 
+;; bswap16 patterns: use revsh and rev16 instructions for the signed
+;; and unsigned variants, respectively. For rev16, expose
+;; byte-swapping in the lower 16 bits only.
+(define_insn "*arm_revsh"
+  [(set (match_operand:SI 0 "s_register_operand" "=l,l,r")
+	(sign_extend:SI (bswap:HI (match_operand:HI 1 "s_register_operand" "l,l,r"))))]
+  "arm_arch6"
+  "@
+  revsh\t%0, %1
+  revsh%?\t%0, %1
+  revsh%?\t%0, %1"
+  [(set_attr "arch" "t1,t2,32")
+   (set_attr "length" "2,2,4")]
+)
+
+(define_insn "*arm_revsh_cond"
+  [(cond_exec (match_operator 2 "arm_comparison_operator"
+	       [(match_operand 3 "cc_register" "") (const_int 0)])
+	      (set (match_operand:SI 0 "s_register_operand" "=l,r")
+		   (sign_extend:SI (bswap:HI (match_operand:HI 1 "s_register_operand" "l,r")))))]
+  "TARGET_32BIT && arm_arch6"
+  "revsh%?\t%0, %1"
+  [(set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
+)
+
+(define_insn "*arm_rev16"
+  [(set (match_operand:HI 0 "s_register_operand" "=l,l,r")
+	(bswap:HI (match_operand:HI 1 "s_register_operand" "l,l,r")))]
+  "arm_arch6"
+  "@
+   rev16\t%0, %1
+   rev16%?\t%0, %1
+   rev16%?\t%0, %1"
+  [(set_attr "arch" "t1,t2,32")
+   (set_attr "length" "2,2,4")]
+)
+
+(define_insn "*arm_rev16_cond"
+  [(cond_exec (match_operator 2 "arm_comparison_operator"
+	       [(match_operand 3 "cc_register" "") (const_int 0)])
+	      (set (match_operand:HI 0 "s_register_operand" "=l,r")
+		   (bswap:HI (match_operand:HI 1 "s_register_operand" "l,r"))))]
+  "TARGET_32BIT && arm_arch6"
+  "rev16%?\t%0, %1"
+  [(set_attr "arch" "t2,*")
+   (set_attr "length" "2,4")]
+)
+
+(define_expand "bswaphi2"
+  [(set (match_operand:HI 0 "s_register_operand" "=r")
+	(bswap:HI (match_operand:HI 1 "s_register_operand" "r")))]
+"arm_arch6"
+""
+)
+
 ;; Load the load/store multiple patterns
 (include "ldmstm.md")
 
diff --git a/gcc/testsuite/gcc.target/arm/builtin-bswap-1.c b/gcc/testsuite/gcc.target/arm/builtin-bswap-1.c
new file mode 100644
index 0000000..43195bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/builtin-bswap-1.c
@@ -0,0 +1,81 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_arch_v6_ok } */
+/* { dg-add-options arm_arch_v6 } */
+/* { dg-final { scan-assembler-not "orr\[ \t\]" } } */
+/* { dg-final { scan-assembler-times "revsh\\t" 1 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "revshne\\t" 1 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "revsh\\t" 2 { target { ! arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "rev16\\t" 1 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "rev16ne\\t" 1 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "rev16\\t" 2 { target { ! arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "rev\\t" 2 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "revne\\t" 2 { target { arm_nothumb } } } }  */
+/* { dg-final { scan-assembler-times "rev\\t" 4 { target { ! arm_nothumb } } } }  */
+
+/* revsh */
+short swaps16 (short x)
+{
+  return __builtin_bswap16 (x);
+}
+
+extern short foos16 (short);
+
+/* revshne */
+short swaps16_cond (short x, int y)
+{
+  short z = x;
+  if (y)
+    z = __builtin_bswap16 (x);
+  return foos16 (z);
+}
+
+/* rev16 */
+unsigned short swapu16 (unsigned short x)
+{
+  return __builtin_bswap16 (x);
+}
+
+extern unsigned short foou16 (unsigned short);
+
+/* rev16ne */
+unsigned short swapu16_cond (unsigned short x, int y)
+{
+  unsigned short z = x;
+  if (y)
+    z = __builtin_bswap16 (x);
+  return foou16 (z);
+}
+
+/* rev */
+int swaps32 (int x) {
+  return __builtin_bswap32 (x);
+}
+
+extern int foos32 (int);
+
+/* revne */
+int swaps32_cond (int x, int y)
+{
+  int z = x;
+  if (y)
+    z = __builtin_bswap32 (x);
+  return foos32 (z);
+}
+
+/* rev */
+unsigned int swapu32 (unsigned int x)
+{
+  return __builtin_bswap32 (x);
+}
+
+extern unsigned int foou32 (unsigned int);
+
+/* revne */
+unsigned int swapsu2 (unsigned int x, int y)
+{
+  int z = x;
+  if (y)
+    z = __builtin_bswap32 (x);
+  return foou32 (z);
+}
