diff mbox series

[COMMITTED,3/9] pru: Optimize the extzv and insv patterns

Message ID 974fb8bda715b7fc8b2f3f9e227bf9b516a22a53.1715065537.git.dimitar@dinux.eu
State New
Headers show
Series Small cleanups and improvements for PRU backend | expand

Commit Message

Dimitar Dimitrov May 7, 2024, 7:22 a.m. UTC
Optimize the generated code for the bit-field extract and insert
patterns:
  - Use bit-set and bit-clear instructions for 1-bit fields.
  - Expand to SImode operations instead of relying on the default
    expansion to word (QI) mode.

gcc/ChangeLog:

	* config/pru/pru.md (extzv<mode>): Make it an expand pattern,
	handle efficiently zero-positioned bit-fields.
	(insv<mode>): New expand pattern.

gcc/testsuite/ChangeLog:

	* gcc.target/pru/ashiftrt.c: Minor update due to new (but
	equivalent) generated code sequence.
	* gcc.target/pru/extzv-1.c: New test.
	* gcc.target/pru/extzv-2.c: New test.
	* gcc.target/pru/extzv-3.c: New test.
	* gcc.target/pru/insv-1.c: New test.
	* gcc.target/pru/insv-2.c: New test.
	* gcc.target/pru/insv-3.c: New test.
	* gcc.target/pru/insv-4.c: New test.

Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
 gcc/config/pru/pru.md                   | 104 ++++++++++++++++++++++--
 gcc/testsuite/gcc.target/pru/ashiftrt.c |   2 +-
 gcc/testsuite/gcc.target/pru/extzv-1.c  |  14 ++++
 gcc/testsuite/gcc.target/pru/extzv-2.c  |  15 ++++
 gcc/testsuite/gcc.target/pru/extzv-3.c  |  13 +++
 gcc/testsuite/gcc.target/pru/insv-1.c   |  14 ++++
 gcc/testsuite/gcc.target/pru/insv-2.c   |  14 ++++
 gcc/testsuite/gcc.target/pru/insv-3.c   |  14 ++++
 gcc/testsuite/gcc.target/pru/insv-4.c   |  14 ++++
 9 files changed, 194 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/pru/extzv-1.c
 create mode 100644 gcc/testsuite/gcc.target/pru/extzv-2.c
 create mode 100644 gcc/testsuite/gcc.target/pru/extzv-3.c
 create mode 100644 gcc/testsuite/gcc.target/pru/insv-1.c
 create mode 100644 gcc/testsuite/gcc.target/pru/insv-2.c
 create mode 100644 gcc/testsuite/gcc.target/pru/insv-3.c
 create mode 100644 gcc/testsuite/gcc.target/pru/insv-4.c
diff mbox series

Patch

diff --git a/gcc/config/pru/pru.md b/gcc/config/pru/pru.md
index 0123952aa9e..2ceea2e7b1c 100644
--- a/gcc/config/pru/pru.md
+++ b/gcc/config/pru/pru.md
@@ -486,22 +486,108 @@  (define_expand "extend<EQS0:mode><EQDHIDI:mode>2"
 })
 
 ;; Bit extraction
-;; We define it solely to allow combine to choose SImode
+;; One reason to define it is to allow combine to choose SImode
 ;; for word mode when trying to match our cbranch_qbbx_* insn.
 ;;
 ;; Check how combine.cc:make_extraction() uses
 ;; get_best_reg_extraction_insn() to select the op size.
-(define_insn "extzv<mode>"
-  [(set (match_operand:QISI 0 "register_operand"	"=r")
+(define_expand "extzv<mode>"
+  [(set (match_operand:QISI 0 "register_operand")
 	  (zero_extract:QISI
-	   (match_operand:QISI 1 "register_operand"	"r")
-	   (match_operand:QISI 2 "const_int_operand"	"i")
-	   (match_operand:QISI 3 "const_int_operand"	"i")))]
+	   (match_operand:QISI 1 "register_operand")
+	   (match_operand:QISI 2 "const_int_operand")
+	   (match_operand:QISI 3 "const_int_operand")))]
   ""
-  "lsl\\t%0, %1, (%S0 * 8 - %2 - %3)\;lsr\\t%0, %0, (%S0 * 8 - %2)"
-  [(set_attr "type" "complex")
-   (set_attr "length" "8")])
+{
+  const int nbits = INTVAL (operands[2]);
+  const int bitpos = INTVAL (operands[3]);
+  const int trailing_bits = GET_MODE_BITSIZE (<MODE>mode) - nbits - bitpos;
+
+  if (bitpos == 0 && nbits <= 7)
+    {
+      emit_insn (gen_and<mode>3 (operands[0],
+				 operands[1],
+				 gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1,
+					       <MODE>mode)));
+      DONE;
+    }
+
+  rtx src = operands[1];
+  if (trailing_bits != 0)
+    {
+      emit_insn (gen_ashl<mode>3 (operands[0],
+				  operands[1],
+				  GEN_INT (trailing_bits)));
+      src = operands[0];
+    }
+  emit_insn (gen_lshr<mode>3 (operands[0],
+			      src,
+			      GEN_INT (trailing_bits + bitpos)));
+  DONE;
+})
+
+;; Bit-field insert.
+(define_expand "insv<mode>"
+  [(set (zero_extract:QISI
+	  (match_operand:QISI 0 "register_operand")
+	  (match_operand:QISI 1 "const_int_operand")
+	  (match_operand:QISI 2 "const_int_operand"))
+	(match_operand:QISI 3 "reg_or_ubyte_operand"))]
+  ""
+{
+  const int nbits = INTVAL (operands[1]);
+  const int bitpos = INTVAL (operands[2]);
 
+  if (nbits == 1)
+    {
+      rtx j;
+      rtx src = gen_reg_rtx (<MODE>mode);
+      rtx dst = operands[0];
+
+      emit_move_insn (src, operands[3]);
+
+      emit_insn (gen_and<mode>3 (dst,
+				 dst,
+				 gen_int_mode (~(HOST_WIDE_INT_1U << bitpos),
+					       <MODE>mode)));
+
+      rtx_code_label *skip_set_label = gen_label_rtx ();
+      j = emit_jump_insn (gen_cbranch_qbbx_eq<mode><mode><mode>4 (
+						  src,
+						  GEN_INT (0),
+						  skip_set_label));
+      JUMP_LABEL (j) = skip_set_label;
+      LABEL_NUSES (skip_set_label)++;
+
+      emit_insn (gen_ior<mode>3 (dst,
+				 dst,
+				 gen_int_mode (HOST_WIDE_INT_1U << bitpos,
+					       <MODE>mode)));
+      emit_label (skip_set_label);
+
+      DONE;
+    }
+
+  /* Explicitly expand in order to avoid using word_mode for PRU, and instead
+     use SI and HI modes as applicable.  */
+  rtx dst = operands[0];
+  rtx src = gen_reg_rtx (<MODE>mode);
+  emit_insn (gen_and<mode>3 (src,
+			     force_reg (<MODE>mode, operands[3]),
+			     gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1,
+					   <MODE>mode)));
+  if (bitpos > 0)
+    emit_insn (gen_ashl<mode>3 (src, src, gen_int_mode (bitpos, <MODE>mode)));
+
+  HOST_WIDE_INT vmask = ~(((HOST_WIDE_INT_1U << nbits) - 1) << bitpos);
+  emit_insn (gen_and<mode>3 (dst,
+			     dst,
+			     gen_int_mode (vmask, <MODE>mode)));
+
+  emit_insn (gen_ior<mode>3 (dst, dst, src));
+
+  DONE;
+})
 
 
 ;; Arithmetic Operations
diff --git a/gcc/testsuite/gcc.target/pru/ashiftrt.c b/gcc/testsuite/gcc.target/pru/ashiftrt.c
index ee8d55d60e6..fb8e4759a0e 100644
--- a/gcc/testsuite/gcc.target/pru/ashiftrt.c
+++ b/gcc/testsuite/gcc.target/pru/ashiftrt.c
@@ -8,6 +8,6 @@  extern void func2(unsigned char);
 
 void test(unsigned char v)
 {
-    /* { dg-final { scan-assembler "lsl\tr14.b0, r14.b0, .\+\n\tlsr\tr14.b0, r14.b0" } } */
+    /* { dg-final { scan-assembler "lsr\tr14(.b0)?, r14.b0, .\+\n\tand\tr14.b0, r14.b0" } } */
     func2((v & 2) ? 1 : 0);
 }
diff --git a/gcc/testsuite/gcc.target/pru/extzv-1.c b/gcc/testsuite/gcc.target/pru/extzv-1.c
new file mode 100644
index 00000000000..573ded99830
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/extzv-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 12 } } */
+
+struct S {
+    unsigned int a : 5;
+    unsigned int b : 1;
+    unsigned int c : 1;
+};
+
+unsigned int test(struct S s)
+{
+  return s.a;
+}
diff --git a/gcc/testsuite/gcc.target/pru/extzv-2.c b/gcc/testsuite/gcc.target/pru/extzv-2.c
new file mode 100644
index 00000000000..e34ba138f16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/extzv-2.c
@@ -0,0 +1,15 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 12 } } */
+
+struct S {
+    unsigned int a : 5;
+    unsigned int b : 1;
+    unsigned int c : 24;
+    unsigned int d : 2;
+};
+
+unsigned int test(struct S s)
+{
+  return s.d;
+}
diff --git a/gcc/testsuite/gcc.target/pru/extzv-3.c b/gcc/testsuite/gcc.target/pru/extzv-3.c
new file mode 100644
index 00000000000..66f4f376885
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/extzv-3.c
@@ -0,0 +1,13 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+    unsigned int a : 9;
+    unsigned int b : 4;
+};
+
+unsigned int test(struct S s)
+{
+  return s.b;
+}
diff --git a/gcc/testsuite/gcc.target/pru/insv-1.c b/gcc/testsuite/gcc.target/pru/insv-1.c
new file mode 100644
index 00000000000..50e29a1b818
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/insv-1.c
@@ -0,0 +1,14 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+    unsigned int a : 5;
+    unsigned int b : 1;
+    unsigned int c : 1;
+};
+
+void test(struct S *s)
+{
+  s->b = 1;
+}
diff --git a/gcc/testsuite/gcc.target/pru/insv-2.c b/gcc/testsuite/gcc.target/pru/insv-2.c
new file mode 100644
index 00000000000..50272b713e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/insv-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 16 } } */
+
+struct S {
+    unsigned int a : 5;
+    unsigned int b : 1;
+    unsigned int c : 1;
+};
+
+void test(struct S *s)
+{
+  s->b = 0;
+}
diff --git a/gcc/testsuite/gcc.target/pru/insv-3.c b/gcc/testsuite/gcc.target/pru/insv-3.c
new file mode 100644
index 00000000000..5ff0feb2ca1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/insv-3.c
@@ -0,0 +1,14 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 24 } } */
+
+struct S {
+    unsigned int a : 5;
+    unsigned int b : 1;
+    unsigned int c : 1;
+};
+
+void test(struct S *s, unsigned int val)
+{
+  s->b = val;
+}
diff --git a/gcc/testsuite/gcc.target/pru/insv-4.c b/gcc/testsuite/gcc.target/pru/insv-4.c
new file mode 100644
index 00000000000..4eaa733c560
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/insv-4.c
@@ -0,0 +1,14 @@ 
+/* { dg-do assemble } */
+/* { dg-options "-Os" } */
+/* { dg-final { object-size text <= 28 } } */
+
+struct S {
+    unsigned int a : 3;
+    unsigned int b : 3;
+    unsigned int c : 3;
+};
+
+void test(struct S *s, unsigned int val)
+{
+  s->b = val;
+}