public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-2248] MIPS: Add bitwise instructions for mips16e2
@ 2023-07-03  3:39 YunQiang Su
  0 siblings, 0 replies; only message in thread
From: YunQiang Su @ 2023-07-03  3:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:42d6b905c454e8f1b59d9248465d62a489b64972

commit r14-2248-g42d6b905c454e8f1b59d9248465d62a489b64972
Author: Jie Mei <jie.mei@oss.cipunited.com>
Date:   Mon Jun 19 16:29:53 2023 +0800

    MIPS: Add bitwise instructions for mips16e2
    
    There are shortened bitwise instructions in the mips16e2 ASE,
    for instance, ANDI, ORI/XORI, EXT, INS etc. .
    
    This patch adds these instrutions with corresponding tests.
    
    gcc/ChangeLog:
    
            * config/mips/constraints.md(Yz): New constraints for mips16e2.
            * config/mips/mips-protos.h(mips_bit_clear_p): Declared new function.
            (mips_bit_clear_info): Same as above.
            * config/mips/mips.cc(mips_bit_clear_info): New function for
            generating instructions.
            (mips_bit_clear_p): Same as above.
            * config/mips/mips.h(ISA_HAS_EXT_INS): Add clause for ISA_HAS_MIPS16E2.
            * config/mips/mips.md(extended_mips16): Generates EXT and INS instructions.
            (*and<mode>3): Generates INS instruction.
            (*and<mode>3_mips16): Generates EXT, INS and ANDI instructions.
            (ior<mode>3): Add logics for ORI instruction.
            (*ior<mode>3_mips16_asmacro): Generates ORI instrucion.
            (*ior<mode>3_mips16): Add logics for XORI instruction.
            (*xor<mode>3_mips16): Generates XORI instrucion.
            (*extzv<mode>): Add logics for EXT instruction.
            (*insv<mode>): Add logics for INS instruction.
            * config/mips/predicates.md(bit_clear_operand): New predicate for
            generating bitwise instructions.
            (and_reg_operand): Add logics for generating bitwise instructions.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/mips/mips16e2.c: New tests for mips16e2.

Diff:
---
 gcc/config/mips/constraints.md           |   4 ++
 gcc/config/mips/mips-protos.h            |   4 ++
 gcc/config/mips/mips.cc                  |  67 +++++++++++++++++++-
 gcc/config/mips/mips.h                   |   3 +-
 gcc/config/mips/mips.md                  |  91 +++++++++++++++++++++------
 gcc/config/mips/predicates.md            |  13 +++-
 gcc/testsuite/gcc.target/mips/mips16e2.c | 102 +++++++++++++++++++++++++++++++
 7 files changed, 263 insertions(+), 21 deletions(-)

diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md
index 49d1a43c613..22d4d84f074 100644
--- a/gcc/config/mips/constraints.md
+++ b/gcc/config/mips/constraints.md
@@ -264,6 +264,10 @@
   (and (match_code "const_vector")
        (match_test "op == CONST0_RTX (mode)")))
 
+(define_constraint "Yz"
+  "@internal"
+  (match_operand 0 "bit_clear_operand"))
+
 (define_constraint "YA"
   "@internal
    An unsigned 6-bit constant."
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index da7902c235b..a5a6f6fcbd3 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -390,4 +390,8 @@ extern void mips_expand_vec_cmp_expr (rtx *);
 
 extern void mips_emit_speculation_barrier_function (void);
 
+extern bool mips_bit_clear_p (enum machine_mode, unsigned HOST_WIDE_INT);
+extern void mips_bit_clear_info (enum machine_mode, unsigned HOST_WIDE_INT,
+				  int *, int *);
+
 #endif /* ! GCC_MIPS_PROTOS_H */
diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index 4e50a87d71c..941562ecece 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -3976,6 +3976,10 @@ mips16_constant_cost (int code, HOST_WIDE_INT x)
 	return 0;
       return -1;
 
+    case ZERO_EXTRACT:
+      /* The bit position and size are immediate operands.  */
+      return ISA_HAS_EXT_INS ? COSTS_N_INSNS (1) : -1;
+
     default:
       return -1;
     }
@@ -22877,7 +22881,68 @@ mips_asm_file_end (void)
   if (NEED_INDICATE_EXEC_STACK)
     file_end_indicate_exec_stack ();
 }
-\f
+
+void
+mips_bit_clear_info (enum machine_mode mode, unsigned HOST_WIDE_INT m,
+		      int *start_pos, int *size)
+{
+  unsigned int shift = 0;
+  unsigned int change_count = 0;
+  unsigned int prev_val = 1;
+  unsigned int curr_val = 0;
+  unsigned int end_pos = GET_MODE_SIZE (mode) * BITS_PER_UNIT;
+
+  for (shift = 0 ; shift < (GET_MODE_SIZE (mode) * BITS_PER_UNIT) ; shift++)
+    {
+      curr_val = (unsigned int)((m & (unsigned int)(1 << shift)) >> shift);
+      if (curr_val != prev_val)
+	{
+	  change_count++;
+	  switch (change_count)
+	    {
+	      case 1:
+		*start_pos = shift;
+		break;
+	      case 2:
+		end_pos = shift;
+		break;
+	      default:
+		gcc_unreachable ();
+	    }
+	}
+      prev_val = curr_val;
+   }
+  *size = (end_pos - *start_pos);
+}
+
+bool
+mips_bit_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT m)
+{
+  unsigned int shift = 0;
+  unsigned int change_count = 0;
+  unsigned int prev_val = 1;
+  unsigned int curr_val = 0;
+
+  if (mode != SImode && mode != VOIDmode)
+    return false;
+
+  if (!ISA_HAS_EXT_INS)
+    return false;
+
+  for (shift = 0 ; shift < (UNITS_PER_WORD * BITS_PER_UNIT) ; shift++)
+    {
+      curr_val = (unsigned int)((m & (unsigned int)(1 << shift)) >> shift);
+      if (curr_val != prev_val)
+	change_count++;
+      prev_val = curr_val;
+    }
+
+  if (change_count == 2)
+    return true;
+
+  return false;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 3ec33fbba71..eefe2aa0910 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1266,7 +1266,8 @@ struct mips_cpu_info {
 #define ISA_HAS_SEB_SEH		(mips_isa_rev >= 2 && !TARGET_MIPS16)
 
 /* ISA includes the MIPS32/64 rev 2 ext and ins instructions.  */
-#define ISA_HAS_EXT_INS		(mips_isa_rev >= 2 && !TARGET_MIPS16)
+#define ISA_HAS_EXT_INS		((mips_isa_rev >= 2 && !TARGET_MIPS16)	\
+				 || ISA_HAS_MIPS16E2)
 
 /* ISA has instructions for accessing top part of 64-bit fp regs.  */
 #define ISA_HAS_MXHC1		(!TARGET_FLOAT32	\
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 973d265e27d..b9eb541cf4a 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -463,7 +463,7 @@
   (if_then_else (ior ;; In general, constant-pool loads are extended
   		     ;; instructions.  We don't yet optimize for 16-bit
 		     ;; PC-relative references.
-  		     (eq_attr "move_type" "sll0,loadpool")
+		     (eq_attr "move_type" "sll0,loadpool,ext_ins")
 		     (eq_attr "jal" "direct")
 		     (eq_attr "got" "load"))
 		(const_string "yes")
@@ -3314,12 +3314,13 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d,0")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d,Yz")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
+  int pos;
 
   switch (which_alternative)
     {
@@ -3344,20 +3345,28 @@
     case 7:
     case 8:
       return "and\t%0,%1,%2";
+    case 9:
+      mips_bit_clear_info (<MODE>mode, INTVAL (operands[2]), &pos, &len);
+      operands[1] = GEN_INT (pos);
+      operands[2] = GEN_INT (len);
+      return "<d>ins\t%0,$0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
-   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical,ext_ins")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%W,W,W,d,0")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "%W,W,W,d,0,d,0,0?")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Yw,d,Yx,Yz,K")))]
   "TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
+  int len;
+  int pos;
+
   switch (which_alternative)
     {
     case 0:
@@ -3373,12 +3382,32 @@
       return "#";
     case 4:
       return "and\t%0,%2";
+    case 5:
+      len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
+      operands[2] = GEN_INT (len);
+      return "ext\t%0,%1,0,%2";
+    case 6:
+      mips_bit_clear_info (<MODE>mode, INTVAL (operands[2]), &pos, &len);
+      operands[1] = GEN_INT (pos);
+      operands[2] = GEN_INT (len);
+      return "ins\t%0,$0,%1,%2";
+    case 7:
+      return "andi\t%0,%x2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,shift_shift,logical")
-   (set_attr "mode" "<MODE>")])
+  [(set_attr "move_type" "load,load,load,shift_shift,logical,ext_ins,ext_ins,andi")
+   (set_attr "mode" "<MODE>")
+   (set_attr "extended_mips16" "no,no,no,no,no,yes,yes,yes")
+   (set (attr "enabled")
+   (cond [(and (eq_attr "alternative" "7")
+			   (not (match_test "ISA_HAS_MIPS16E2")))
+		  (const_string "no")
+		  (and (eq_attr "alternative" "0,1")
+			   (match_test "!GENERATE_MIPS16E"))
+		  (const_string "no")]
+		 (const_string "yes")))])
 
 (define_expand "ior<mode>3"
   [(set (match_operand:GPR 0 "register_operand")
@@ -3386,7 +3415,7 @@
 		 (match_operand:GPR 2 "uns_arith_operand")))]
   ""
 {
-  if (TARGET_MIPS16)
+  if (TARGET_MIPS16 && !ISA_HAS_MIPS16E2)
     operands[2] = force_reg (<MODE>mode, operands[2]);
 })
 
@@ -3403,11 +3432,23 @@
    (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*ior<mode>3_mips16_asmacro"
+  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,0")
+		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  "ISA_HAS_MIPS16E2"
+  "@
+   or\t%0,%2
+   ori\t%0,%x2"
+   [(set_attr "alu_type" "or")
+    (set_attr "mode" "<MODE>")
+    (set_attr "extended_mips16" "*,yes")])
+
 (define_insn "*ior<mode>3_mips16"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(ior:GPR (match_operand:GPR 1 "register_operand" "%0")
 		 (match_operand:GPR 2 "register_operand" "d")))]
-  "TARGET_MIPS16"
+  "TARGET_MIPS16 && !ISA_HAS_MIPS16E2"
   "or\t%0,%2"
   [(set_attr "alu_type" "or")
    (set_attr "mode" "<MODE>")])
@@ -3432,19 +3473,31 @@
    (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
+;; We increase statically the cost of the output register for XORI
+;; to counterweight LRA cost calculation as XORI tends to be chosen
+;; frequently hurting the code size.  The reason of not choosing CMPI is
+;; that LRA tends to add up the cost of the T register as it is in a small
+;; class and a possible reload.  In reality, the use of T register comes for
+;; free in a number of cases as we don't need any MIPS16 registers.
 (define_insn "*xor<mode>3_mips16"
-  [(set (match_operand:GPR 0 "register_operand" "=d,t,t,t")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,Uub8,K,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,t,t,t,d?")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d,d,0")
+		 (match_operand:GPR 2 "uns_arith_operand" "d,Uub8,K,d,K")))]
   "TARGET_MIPS16"
   "@
    xor\t%0,%2
    cmpi\t%1,%2
    cmpi\t%1,%2
-   cmp\t%1,%2"
+   cmp\t%1,%2
+   xori\t%0,%x2"
   [(set_attr "alu_type" "xor")
    (set_attr "mode" "<MODE>")
-   (set_attr "extended_mips16" "no,no,yes,no")])
+   (set_attr "extended_mips16" "no,no,yes,no,yes")
+   (set (attr "enabled")
+		(cond [(and (eq_attr "alternative" "4")
+					(not (match_test "ISA_HAS_MIPS16E2")))
+			   (const_string "no")]
+			  (const_string "yes")))])
 
 (define_insn "*nor<mode>3"
   [(set (match_operand:GPR 0 "register_operand" "=d")
@@ -4344,6 +4397,7 @@
 		       INTVAL (operands[3]))"
   "<d>ext\t%0,%1,%3,%2"
   [(set_attr "type"	"arith")
+   (set_attr "extended_mips16"  "yes")
    (set_attr "mode"	"<MODE>")])
 
 (define_insn "*extzv_truncsi_exts"
@@ -4394,6 +4448,7 @@
 		       INTVAL (operands[2]))"
   "<d>ins\t%0,%z3,%2,%1"
   [(set_attr "type"	"arith")
+   (set_attr "extended_mips16"  "yes")
    (set_attr "mode"	"<MODE>")])
 
 ;; Combiner pattern for cins (clear and insert bit field).  We can
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index 4f9458ed72f..e8a85ac32fb 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -170,6 +170,10 @@
   (and (match_code "const_int")
        (match_test "UINTVAL (op) == 0xffffffff")))
 
+(define_predicate "bit_clear_operand"
+  (and (match_code "const_int")
+       (match_test "mips_bit_clear_p (mode, INTVAL (op))")))
+
 (define_predicate "and_load_operand"
   (ior (match_operand 0 "qi_mask_operand")
        (match_operand 0 "hi_mask_operand")
@@ -184,8 +188,15 @@
   (ior (match_operand 0 "register_operand")
        (and (not (match_test "TARGET_MIPS16"))
 	    (match_operand 0 "const_uns_arith_operand"))
+       (and (match_test "ISA_HAS_MIPS16E2")
+	    (match_operand 0 "const_uns_arith_operand")
+	    (not (match_operand 0 "hi_mask_operand"))
+	    (not (match_operand 0 "qi_mask_operand")))
+       (and (match_test "ISA_HAS_MIPS16E2")
+	    (match_operand 0 "const_uns_arith_operand"))
        (match_operand 0 "low_bitmask_operand")
-       (match_operand 0 "si_mask_operand")))
+       (match_operand 0 "si_mask_operand")
+       (match_operand 0 "bit_clear_operand")))
 
 (define_predicate "and_operand"
   (ior (match_operand 0 "and_load_operand")
diff --git a/gcc/testsuite/gcc.target/mips/mips16e2.c b/gcc/testsuite/gcc.target/mips/mips16e2.c
new file mode 100644
index 00000000000..ce8b4f1819b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips16e2.c
@@ -0,0 +1,102 @@
+/* { dg-options "-mno-abicalls -mgpopt -G8 -mabi=32 -mips16 -mmips16e2" } */
+/* { dg-skip-if "per-function expected output" { *-*-* } { "-flto" } { "" } } */
+ 
+/* ANDI is a two operand instruction.  Hence, it won't be generated if src and
+ *    dest are in different registers.  */
+   
+/* { dg-final { scan-assembler "test01:.*\tandi\t.*test01\n" } } */
+unsigned int
+test01 (unsigned int a)
+{
+  return ((a + 0x2) & 0x3ff);
+}
+
+/* Test EXT */
+
+/* { dg-final { scan-assembler "test02:.*\text\t.*test02\n" } } */
+struct
+{
+  unsigned int a:9;
+  unsigned int d:31;
+  unsigned int e:9;
+  unsigned int f:10;
+} t02;
+
+unsigned int
+test02 (void)
+{
+  return t02.f;
+}
+
+/* Use EXT when ANDing with low-order bitmasks.  */
+
+/* { dg-final { scan-assembler "test03:.*\text\t.*test03\n" } } */
+/* { dg-final { scan-assembler-not "test03.*\tandi?\t.*test03\n" } } */
+unsigned int
+test03 (unsigned int x)
+{
+  return (x & 0x1fffffff);
+}
+
+/* Test INS */
+
+/* { dg-final { scan-assembler "test04:.*\tins\t.*test04\n" } } */
+struct
+{
+  unsigned int i : 9;
+  unsigned int j : 15;
+  unsigned int k : 4;
+} s04;
+
+void
+test04 (void)
+{
+  s04.j = 1;
+}
+
+/* Use INS with hardcoded $0.  */
+
+/* { dg-final { scan-assembler "test05:.*\tins\t\\\$.*,\\\$0.*test05\n" } } */
+struct
+{
+  unsigned int i : 8;
+  unsigned int j : 9;
+  unsigned int k : 10;
+} __attribute__ ((packed)) s05 __attribute__((aligned(1)));
+
+void
+test05 (void)
+{
+  s05.k = 0;
+}
+
+/* Use INS when ANDing to clear only one consecutive chunk of bits.  */
+
+/* { dg-final { scan-assembler "test06:.*\tins\t\\\$.*,\\\$0,11,5.*test06\n" } } */
+/* { dg-final { scan-assembler-not "test06:.*\tandi?\t.*test06\n" } } */
+unsigned int
+test06 (unsigned int x)
+{
+  return (x & 0xffff07ff);
+}
+
+/* ORI is a two operand instruction.  Hence, it won't be generated if src and
+   dest are in different registers.  */
+
+/* { dg-final { scan-assembler "test07:.*\tori\t.*test07\n" } } */
+unsigned int
+test07 (unsigned int a)
+{
+  return (a + 0x2) | 0x7f0;
+}
+
+/* XORI is a two operand instruction.  Hence, it won't be generated if src and
+   dest are in different registers.  */
+
+/* { dg-final { scan-assembler "test08:.*\txori\t.*test08\n" } } */
+unsigned int
+test08 (unsigned int a)
+{
+  return ((a + 0x2) ^ 0x3f0);
+}
+

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-07-03  3:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-03  3:39 [gcc r14-2248] MIPS: Add bitwise instructions for mips16e2 YunQiang Su

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).