From 49912bcd97ec640f130fcf1551ea472d50f06f53 Mon Sep 17 00:00:00 2001
From: Adam Nemet <anemet@caviumnetworks.com>
Date: Thu, 4 Sep 2008 21:02:30 +0000
Subject: [PATCH] mips.h (ISA_HAS_CINS): New macro.

	* config/mips/mips.h (ISA_HAS_CINS): New macro.
	* config/mips/mips-protos.h (mask_low_and_shift_p,
	mask_low_and_shift_len): Declare.
	* config/mips/mips.c (mask_low_and_shift_p,
	mask_low_and_shift_len): New functions.
	(mips_print_operand): Handle new operand prefix "m".
	* config/mips/mips.md (*cins<mode>): New pattern.

testsuite/
	* gcc.target/mips/octeon-cins-1.c: New test.
	* gcc.target/mips/octeon-cins-2.c: New test.

From-SVN: r140008
---
 gcc/ChangeLog                                 | 10 ++++++
 gcc/config/mips/mips-protos.h                 |  4 +++
 gcc/config/mips/mips.c                        | 34 +++++++++++++++++++
 gcc/config/mips/mips.h                        |  3 ++
 gcc/config/mips/mips.md                       | 22 ++++++++++++
 gcc/testsuite/ChangeLog                       |  5 +++
 gcc/testsuite/gcc.target/mips/octeon-cins-1.c | 24 +++++++++++++
 gcc/testsuite/gcc.target/mips/octeon-cins-2.c | 15 ++++++++
 8 files changed, 117 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-cins-1.c
 create mode 100644 gcc/testsuite/gcc.target/mips/octeon-cins-2.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9146cfb945aa..2350a47c9eb4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
+
+	* config/mips/mips.h (ISA_HAS_CINS): New macro.
+	* config/mips/mips-protos.h (mask_low_and_shift_p,
+	mask_low_and_shift_len): Declare.
+	* config/mips/mips.c (mask_low_and_shift_p,
+	mask_low_and_shift_len): New functions.
+	(mips_print_operand): Handle new operand prefix "m".
+	* config/mips/mips.md (*cins<mode>): New pattern.
+
 2008-09-04  Bernd Schmidt  <bernd.schmidt@analog.com>
 
 	* config/bfin/bfin.c (gen_one_bundle): Don't create new nops when
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 01645a1ebc29..9403945a4f3b 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -314,6 +314,10 @@ extern bool mips_use_ins_ext_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 extern const char *mips16e_output_save_restore (rtx, HOST_WIDE_INT);
 extern bool mips16e_save_restore_pattern_p (rtx, HOST_WIDE_INT,
 					    struct mips16e_save_restore_info *);
+
+extern bool mask_low_and_shift_p (enum machine_mode, rtx, rtx, int);
+extern int mask_low_and_shift_len (enum machine_mode, rtx, rtx);
+
 union mips_gen_fn_ptrs
 {
   rtx (*fn_6) (rtx, rtx, rtx, rtx, rtx, rtx);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index dea7ffe57fab..911f93c2b4fc 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -6659,6 +6659,32 @@ mips_use_ins_ext_p (rtx op, HOST_WIDE_INT width, HOST_WIDE_INT bitpos)
 
   return true;
 }
+
+/* Check if MASK and SHIFT are valid in mask-low-and-shift-left
+   operation if MAXLEN is the maxium length of consecutive bits that
+   can make up MASK.  MODE is the mode of the operation.  See
+   mask_low_and_shift_len for the actual definition.  */
+
+bool
+mask_low_and_shift_p (enum machine_mode mode, rtx mask, rtx shift, int maxlen)
+{
+  return IN_RANGE (mask_low_and_shift_len (mode, mask, shift), 1, maxlen);
+}
+
+/* The canonical form of a mask-low-and-shift-left operation is
+   (and (ashift X SHIFT) MASK) where MASK has the lower SHIFT number of bits
+   cleared.  Thus we need to shift MASK to the right before checking if it
+   is a valid mask value.  MODE is the mode of the operation.  If true
+   return the length of the mask, otherwise return -1.  */
+
+int
+mask_low_and_shift_len (enum machine_mode mode, rtx mask, rtx shift)
+{
+  HOST_WIDE_INT shval;
+
+  shval = INTVAL (shift) & (GET_MODE_BITSIZE (mode) - 1);
+  return exact_log2 ((UINTVAL (mask) >> shval) + 1);
+}
 
 /* Return true if -msplit-addresses is selected and should be honored.
 
@@ -7026,6 +7052,7 @@ mips_print_float_branch_condition (FILE *file, enum rtx_code code, int letter)
    'X'	Print CONST_INT OP in hexadecimal format.
    'x'	Print the low 16 bits of CONST_INT OP in hexadecimal format.
    'd'	Print CONST_INT OP in decimal.
+   'm'	Print one less than CONST_INT OP in decimal.
    'h'	Print the high-part relocation associated with OP, after stripping
 	  any outermost HIGH.
    'R'	Print the low-part relocation associated with OP.
@@ -7081,6 +7108,13 @@ mips_print_operand (FILE *file, rtx op, int letter)
 	output_operand_lossage ("invalid use of '%%%c'", letter);
       break;
 
+    case 'm':
+      if (GET_CODE (op) == CONST_INT)
+	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op) - 1);
+      else
+	output_operand_lossage ("invalid use of '%%%c'", letter);
+      break;
+
     case 'h':
       if (code == HIGH)
 	op = XEXP (op, 0);
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 86b886a373f0..a3f47f79dcfe 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1009,6 +1009,9 @@ enum mips_code_readable_setting {
 /* ISA includes the bbit* instructions.  */
 #define ISA_HAS_BBIT		TARGET_OCTEON
 
+/* ISA includes the cins instruction.  */
+#define ISA_HAS_CINS		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 0aba384144db..04dd30a1e10c 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -3441,6 +3441,28 @@
   [(set_attr "type"	"arith")
    (set_attr "mode"	"<MODE>")])
 
+;; Combiner pattern for cins (clear and insert bit field).  We can
+;; implement mask-and-shift-left operation with this.  Note that if
+;; the upper bit of the mask is set in an SImode operation, the mask
+;; itself will be sign-extended.  mask_low_and_shift_len will
+;; therefore be greater than our threshold of 32.
+
+(define_insn "*cins<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+	(and:GPR
+	 (ashift:GPR (match_operand:GPR 1 "register_operand" "d")
+		     (match_operand:GPR 2 "const_int_operand" ""))
+	 (match_operand:GPR 3 "const_int_operand" "")))]
+  "ISA_HAS_CINS
+   && mask_low_and_shift_p (<MODE>mode, operands[3], operands[2], 32)"
+{
+  operands[3] =
+    GEN_INT (mask_low_and_shift_len (<MODE>mode, operands[3], operands[2]));
+  return "cins\t%0,%1,%2,%m3";
+}
+  [(set_attr "type"     "shift")
+   (set_attr "mode"     "<MODE>")])
+
 ;; Unaligned word moves generated by the bit field patterns.
 ;;
 ;; As far as the rtl is concerned, both the left-part and right-part
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6849f7c9af1f..b6f573e7fc03 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
+
+	* gcc.target/mips/octeon-cins-1.c: New test.
+	* gcc.target/mips/octeon-cins-2.c: New test.
+
 2008-09-04  Richard Guenther  <rguenther@suse.de>
 
 	* gfortran.dg/internal_pack_4.f90: Adjust pattern.
diff --git a/gcc/testsuite/gcc.target/mips/octeon-cins-1.c b/gcc/testsuite/gcc.target/mips/octeon-cins-1.c
new file mode 100644
index 000000000000..27dc6b3d2b74
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-cins-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* The tests also work with -mgp32.  For long long tests, only one of
+   the 32-bit parts is used.  */
+/* { dg-mips-options "-O -march=octeon" } */
+/* { dg-final { scan-assembler-times "\tcins\t" 3 } } */
+/* { dg-final { scan-assembler-not "\tandi\t|sll\t" } } */
+
+NOMIPS16 long long
+f (long long i)
+{
+  return (i & 0xff) << 34;
+}
+
+NOMIPS16 int
+g (int i)
+{
+  return (i << 4) & 0xff0;
+}
+
+NOMIPS16 long long
+h (long long i)
+{
+  return (i << 4) & 0xfff;
+}
diff --git a/gcc/testsuite/gcc.target/mips/octeon-cins-2.c b/gcc/testsuite/gcc.target/mips/octeon-cins-2.c
new file mode 100644
index 000000000000..c60ee933ffab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-cins-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-mips-options "-O -march=octeon -mgp64" } */
+/* { dg-final { scan-assembler-not "\tcins\t" } } */
+
+NOMIPS16 unsigned
+f (unsigned i)
+{
+  return (i & 0xff) << 24;
+}
+
+NOMIPS16 unsigned long long
+g (unsigned long long i)
+{
+  return (i & 0x1ffffffffULL) << 4;
+}
-- 
GitLab