From c84241327480cec52608beaba811faf1f09e0b03 Mon Sep 17 00:00:00 2001
From: Adam Nemet <anemet@caviumnetworks.com>
Date: Thu, 4 Sep 2008 21:24:31 +0000
Subject: [PATCH] mips.h (ISA_HAS_EXTS): New macro.

	* config/mips/mips.h (ISA_HAS_EXTS): New macro.
	* config/mips/mips.md (*ashr_trunc<mode>): Name the pattern
	combining an arithmetic right shift by more than 31 and a
	trunction.  Don't match for out-of-range shift amounts.  Set
	attribute mode to <MODE>.
	(*lshr32_trunc<mode>): Name the pattern combining a logical right
	shift by 32 and and a truncation.  Set attribute mode to <MODE>.
	(*<optab>_trunc<mode>_exts): New pattern for truncated right
	shifts by less than 32.
	(extv): Change predicate on first operand to accept registers.
	Change predicate of the other operands from immediate_operand to
	const_int_operand.  Expand exts when source is a register.
	(extzv): Change predicate of the constant operands from
	immediate_operand to const_int_operand.
	(extzv<mode>): Change predicate of the constant operands from
	immediate_operand to const_int_operand and no constraint. Also
	remove mode.
	(*extzv_trunc<mode>_exts): New pattern.

testsuite/
	* gcc.target/mips/truncate-2.c: New test.
	* gcc.target/mips/octeon-exts-1.c: New test.
	* gcc.target/mips/octeon-exts-2.c: New test.
	* gcc.target/mips/octeon-exts-3.c: New test.
	* gcc.target/mips/octeon-exts-4.c: New test.

From-SVN: r140009
---
 gcc/ChangeLog                                 | 21 ++++++
 gcc/config/mips/mips.h                        |  3 +
 gcc/config/mips/mips.md                       | 72 +++++++++++++++----
 gcc/testsuite/ChangeLog                       |  8 +++
 gcc/testsuite/gcc.target/mips/octeon-exts-1.c | 16 +++++
 gcc/testsuite/gcc.target/mips/octeon-exts-2.c | 37 ++++++++++
 gcc/testsuite/gcc.target/mips/octeon-exts-3.c | 35 +++++++++
 gcc/testsuite/gcc.target/mips/octeon-exts-4.c | 20 ++++++
 gcc/testsuite/gcc.target/mips/truncate-2.c    | 20 ++++++
 9 files changed, 220 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-exts-1.c
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-exts-2.c
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-exts-3.c
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-exts-4.c
 create mode 100644 gcc/testsuite/gcc.target/mips/truncate-2.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2350a47c9eb4..d035a4bfdff5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,24 @@
+2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
+
+	* config/mips/mips.h (ISA_HAS_EXTS): New macro.
+	* config/mips/mips.md (*ashr_trunc<mode>): Name the pattern
+	combining an arithmetic right shift by more than 31 and a
+	trunction.  Don't match for out-of-range shift amounts.  Set
+	attribute mode to <MODE>.
+	(*lshr32_trunc<mode>): Name the pattern combining a logical right
+	shift by 32 and and a truncation.  Set attribute mode to <MODE>.
+	(*<optab>_trunc<mode>_exts): New pattern for truncated right
+	shifts by less than 32.
+	(extv): Change predicate on first operand to accept registers.
+	Change predicate of the other operands from immediate_operand to
+	const_int_operand.  Expand exts when source is a register.
+	(extzv): Change predicate of the constant operands from
+	immediate_operand to const_int_operand.
+	(extzv<mode>): Change predicate of the constant operands from
+	immediate_operand to const_int_operand and no constraint. Also
+	remove mode.
+	(*extzv_trunc<mode>_exts): New pattern.
+
 2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
 
 	* config/mips/mips.h (ISA_HAS_CINS): New macro.
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index a3f47f79dcfe..46775464470c 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1012,6 +1012,9 @@ enum mips_code_readable_setting {
 /* ISA includes the cins instruction.  */
 #define ISA_HAS_CINS		TARGET_OCTEON
 
+/* ISA includes the exts instruction.  */
+#define ISA_HAS_EXTS		TARGET_OCTEON
+
 /* ISA includes the pop instruction.  */
 #define ISA_HAS_POP		TARGET_OCTEON
 
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 04dd30a1e10c..0f478cf558fa 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -772,6 +772,10 @@
 ;; to use the same template.
 (define_code_iterator any_extend [sign_extend zero_extend])
 
+;; This code iterator allows the two right shift instructions to be
+;; generated from the same template.
+(define_code_iterator any_shiftrt [ashiftrt lshiftrt])
+
 ;; This code iterator allows the three shift instructions to be generated
 ;; from the same template.
 (define_code_iterator any_shift [ashift ashiftrt lshiftrt])
@@ -2683,17 +2687,17 @@
 
 ;; Combiner patterns to optimize shift/truncate combinations.
 
-(define_insn ""
+(define_insn "*ashr_trunc<mode>"
   [(set (match_operand:SUBDI 0 "register_operand" "=d")
         (truncate:SUBDI
 	  (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
 		       (match_operand:DI 2 "const_arith_operand" ""))))]
-  "TARGET_64BIT && !TARGET_MIPS16 && INTVAL (operands[2]) >= 32"
+  "TARGET_64BIT && !TARGET_MIPS16 && IN_RANGE (INTVAL (operands[2]), 32, 63)"
   "dsra\t%0,%1,%2"
   [(set_attr "type" "shift")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "<MODE>")])
 
-(define_insn ""
+(define_insn "*lshr32_trunc<mode>"
   [(set (match_operand:SUBDI 0 "register_operand" "=d")
         (truncate:SUBDI
 	  (lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
@@ -2701,8 +2705,19 @@
   "TARGET_64BIT && !TARGET_MIPS16"
   "dsra\t%0,%1,32"
   [(set_attr "type" "shift")
-   (set_attr "mode" "SI")])
+   (set_attr "mode" "<MODE>")])
 
+;; Logical shift by 32 or more results in proper SI values so
+;; truncation is removed by the middle end.
+(define_insn "*<optab>_trunc<mode>_exts"
+  [(set (match_operand:SUBDI 0 "register_operand" "=d")
+        (truncate:SUBDI
+	 (any_shiftrt:DI (match_operand:DI 1 "register_operand" "d")
+			 (match_operand:DI 2 "const_arith_operand" ""))))]
+  "ISA_HAS_EXTS && TARGET_64BIT && UINTVAL (operands[2]) < 32"
+  "exts\t%0,%1,%2,31"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
 
 ;; Combiner patterns for truncate/sign_extend combinations.  The SI versions
 ;; use the shift/truncate patterns above.
@@ -3353,24 +3368,46 @@
 
 (define_expand "extv"
   [(set (match_operand 0 "register_operand")
-	(sign_extract (match_operand:QI 1 "memory_operand")
-		      (match_operand 2 "immediate_operand")
-		      (match_operand 3 "immediate_operand")))]
+	(sign_extract (match_operand 1 "nonimmediate_operand")
+		      (match_operand 2 "const_int_operand")
+		      (match_operand 3 "const_int_operand")))]
   "!TARGET_MIPS16"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
 					 INTVAL (operands[2]),
 					 INTVAL (operands[3])))
     DONE;
+  else if (register_operand (operands[1], GET_MODE (operands[0]))
+	   && ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32)
+    {
+      if (GET_MODE (operands[0]) == DImode)
+	emit_insn (gen_extvdi (operands[0], operands[1], operands[2],
+			       operands[3]));
+      else
+	emit_insn (gen_extvsi (operands[0], operands[1], operands[2],
+			       operands[3]));
+      DONE;
+    }
   else
     FAIL;
 })
 
+(define_insn "extv<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+        (sign_extract:GPR (match_operand:GPR 1 "register_operand" "d")
+			  (match_operand 2 "const_int_operand" "")
+			  (match_operand 3 "const_int_operand" "")))]
+  "ISA_HAS_EXTS && UINTVAL (operands[2]) <= 32"
+  "exts\t%0,%1,%3,%m2"
+  [(set_attr "type"     "arith")
+   (set_attr "mode"     "<MODE>")])
+
+
 (define_expand "extzv"
   [(set (match_operand 0 "register_operand")
 	(zero_extract (match_operand 1 "nonimmediate_operand")
-		      (match_operand 2 "immediate_operand")
-		      (match_operand 3 "immediate_operand")))]
+		      (match_operand 2 "const_int_operand")
+		      (match_operand 3 "const_int_operand")))]
   "!TARGET_MIPS16"
 {
   if (mips_expand_ext_as_unaligned_load (operands[0], operands[1],
@@ -3395,14 +3432,25 @@
 (define_insn "extzv<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(zero_extract:GPR (match_operand:GPR 1 "register_operand" "d")
-			  (match_operand:SI 2 "immediate_operand" "I")
-			  (match_operand:SI 3 "immediate_operand" "I")))]
+			  (match_operand 2 "const_int_operand" "")
+			  (match_operand 3 "const_int_operand" "")))]
   "mips_use_ins_ext_p (operands[1], INTVAL (operands[2]),
 		       INTVAL (operands[3]))"
   "<d>ext\t%0,%1,%3,%2"
   [(set_attr "type"	"arith")
    (set_attr "mode"	"<MODE>")])
 
+(define_insn "*extzv_trunc<mode>_exts"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+        (truncate:GPR
+	 (zero_extract:DI (match_operand:DI 1 "register_operand" "d")
+			  (match_operand 2 "const_int_operand" "")
+			  (match_operand 3 "const_int_operand" ""))))]
+  "ISA_HAS_EXTS && TARGET_64BIT && IN_RANGE (INTVAL (operands[2]), 32, 63)"
+  "exts\t%0,%1,%3,31"
+  [(set_attr "type"     "arith")
+   (set_attr "mode"     "<MODE>")])
+
 
 (define_expand "insv"
   [(set (zero_extract (match_operand 0 "nonimmediate_operand")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b6f573e7fc03..9eeb9cc27dc5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
+
+	* gcc.target/mips/truncate-2.c: New test.
+	* gcc.target/mips/octeon-exts-1.c: New test.
+	* gcc.target/mips/octeon-exts-2.c: New test.
+	* gcc.target/mips/octeon-exts-3.c: New test.
+	* gcc.target/mips/octeon-exts-4.c: New test.
+
 2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
 
 	* gcc.target/mips/octeon-cins-1.c: New test.
diff --git a/gcc/testsuite/gcc.target/mips/octeon-exts-1.c b/gcc/testsuite/gcc.target/mips/octeon-exts-1.c
new file mode 100644
index 000000000000..bdaa0b927ef4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-exts-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-march=octeon" } */
+/* { dg-final { scan-assembler "\texts\t" } } */
+
+struct foo
+{
+  long long a:3;
+  long long b:23;
+  long long c:38;
+};
+
+NOMIPS16 int
+f (struct foo s)
+{
+  return s.b;
+}
diff --git a/gcc/testsuite/gcc.target/mips/octeon-exts-2.c b/gcc/testsuite/gcc.target/mips/octeon-exts-2.c
new file mode 100644
index 000000000000..a87c5fb45db9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-exts-2.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -march=octeon" } */
+/* { dg-final { scan-assembler-times "\texts\t" 4 } } */
+
+struct bar
+{
+  unsigned long long a:1;
+  long long b:14;
+  unsigned long long c:48;
+  long long d:1;
+};
+
+NOMIPS16 int
+f1 (struct bar *s, int a)
+{
+  return (int) s->b + a;
+}
+
+NOMIPS16 char
+f2 (struct bar *s)
+{
+  return s->d + 1;
+}
+
+NOMIPS16 int
+f3 ()
+{
+  struct bar s;
+  asm ("" : "=r"(s));
+  return (int) s.b + 1;
+}
+
+NOMIPS16 long long
+f4 (struct bar *s)
+{
+  return s->d;
+}
diff --git a/gcc/testsuite/gcc.target/mips/octeon-exts-3.c b/gcc/testsuite/gcc.target/mips/octeon-exts-3.c
new file mode 100644
index 000000000000..d7610f82e327
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-exts-3.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -march=octeon -mgp64" } */
+/* { dg-final { scan-assembler-times "\texts\t" 3 } } */
+
+struct foo
+{
+  unsigned long long a:10;
+  unsigned long long b:32;
+  unsigned long long c:22;
+};
+
+NOMIPS16 unsigned
+f (struct foo s)
+{
+  return s.b;
+}
+
+struct bar
+{
+  unsigned long long a:15;
+  unsigned long long b:48;
+  unsigned long long c:1;
+};
+
+NOMIPS16 int
+g (struct bar s)
+{
+  return (int) s.b;
+}
+
+NOMIPS16 int
+h (int i)
+{
+  return (i << 4) >> 24;
+}
diff --git a/gcc/testsuite/gcc.target/mips/octeon-exts-4.c b/gcc/testsuite/gcc.target/mips/octeon-exts-4.c
new file mode 100644
index 000000000000..475fa21e8dcd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-exts-4.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -march=octeon -mgp64" } */
+/* { dg-final { scan-assembler-not "\tsll\t\[^\n\]*,0" } } */
+/* { dg-final { scan-assembler-times "\texts\t" 6 } } */
+
+#define TEST(ID, TYPE, SHIFT)				\
+  int NOMIPS16						\
+  f##ID (long long y)					\
+  {							\
+    return (TYPE) ((TYPE) (y >> SHIFT) + 1);		\
+  }							\
+  int NOMIPS16						\
+  g##ID (unsigned long long y)				\
+  {							\
+    return (TYPE) ((TYPE) (y >> SHIFT) + 1);		\
+  }
+
+TEST (1, int, 10)
+TEST (2, short, 5)
+TEST (3, char, 31)
diff --git a/gcc/testsuite/gcc.target/mips/truncate-2.c b/gcc/testsuite/gcc.target/mips/truncate-2.c
new file mode 100644
index 000000000000..51125a481902
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/truncate-2.c
@@ -0,0 +1,20 @@
+/* { dg-mips-options "-O -mgp64" } */
+
+#define TEST(ID, TYPE, SHIFT)				\
+  int NOMIPS16						\
+  f##ID (long long y)					\
+  {							\
+    return (TYPE) ((TYPE) (y >> SHIFT) + 1);		\
+  }
+
+TEST (1, int, 32)
+TEST (2, short, 32)
+TEST (3, char, 32)
+TEST (4, int, 33)
+TEST (5, short, 33)
+TEST (6, char, 33)
+TEST (7, int, 61)
+TEST (8, short, 61)
+TEST (9, char, 61)
+
+/* { dg-final { scan-assembler-not "\tsll\t\[^\n\]*,0" } } */
-- 
GitLab