]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Use extension instructions instead of bitwise "and"
authorJivan Hakobyan <jivanhakobyan9@gmail.com>
Mon, 29 May 2023 13:55:29 +0000 (07:55 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Mon, 29 May 2023 13:57:20 +0000 (07:57 -0600)
In the case where the target supports extension instructions,
it is preferable to use that instead of doing the same in other ways.
For the following case

void foo (unsigned long a, unsigned long* ptr) {
    ptr[0] = a & 0xffffffffUL;
    ptr[1] &= 0xffffffffUL;
}

GCC generates
foo:
        li      a5,-1
        srli    a5,a5,32
        and     a0,a0,a5
        sd      a0,0(a1)
        ld      a4,8(a1)
        and     a5,a4,a5
        sd      a5,8(a1)
        ret

but it will be profitable to generate this one

foo:
  zext.w a0,a0
  sd a0,0(a1)
  lwu a5,8(a1)
  sd a5,8(a1)
  ret

This patch fixes mentioned issue.
It supports HI -> DI, HI->SI and SI -> DI extensions.

gcc/ChangeLog:
* config/riscv/riscv.md (and<mode>3): New expander.
(*and<mode>3) New pattern.
* config/riscv/predicates.md (arith_operand_or_mode_mask): New
predicate.

gcc/testsuite/ChangeLog:
* gcc.target/riscv/and-extend-1.c: New test
* gcc.target/riscv/and-extend-2.c: New test

gcc/config/riscv/predicates.md
gcc/config/riscv/riscv.md
gcc/testsuite/gcc.target/riscv/and-extend-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/and-extend-2.c [new file with mode: 0644]

index ffcbb9a75899730033112159d759b00fb1464d2d..f7c4a3f030f13fd147c3f2821f3f1236b7d014f8 100644 (file)
   (ior (match_operand 0 "const_arith_operand")
        (match_operand 0 "register_operand")))
 
+(define_predicate "arith_operand_or_mode_mask"
+  (ior (match_operand 0 "arith_operand")
+       (and (match_code "const_int")
+            (match_test "INTVAL (op) == GET_MODE_MASK (HImode)
+                        || INTVAL (op) == GET_MODE_MASK (SImode)"))))
+
 (define_predicate "lui_operand"
   (and (match_code "const_int")
        (match_test "LUI_OPERAND (INTVAL (op))")))
index 124d8c95804b48a05b45b15a9cf926d27b13d029..aba203318a73ddd99f94c6b54cedaa49065a2f45 100644 (file)
 ;; For RV64, we don't expose the SImode operations to the rtl expanders,
 ;; but SImode versions exist for combine.
 
+(define_expand "and<mode>3"
+  [(set (match_operand:X                0 "register_operand")
+        (and:X (match_operand:X 1 "register_operand")
+                       (match_operand:X 2 "arith_operand_or_mode_mask")))]
+  ""
+{
+  /* If the second operand is a mode mask, emit an extension
+     insn instead.  */
+  if (CONST_INT_P (operands[2]))
+    {
+      enum machine_mode tmode = VOIDmode;
+      if (INTVAL (operands[2]) == GET_MODE_MASK (HImode))
+       tmode = HImode;
+      else if (INTVAL (operands[2]) == GET_MODE_MASK (SImode))
+       tmode = SImode;
+
+      if (tmode != VOIDmode)
+       {
+         rtx tmp = gen_lowpart (tmode, operands[1]);
+         emit_insn (gen_extend_insn (operands[0], tmp, <MODE>mode, tmode, 1));
+         DONE;
+       }
+    }
+  else
+    {
+      emit_move_insn (operands[0], gen_rtx_AND (<MODE>mode, operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_insn "*and<mode>3"
+  [(set (match_operand:X                0 "register_operand" "=r,r")
+       (and:X (match_operand:X 1 "register_operand" "%r,r")
+                      (match_operand:X 2 "arith_operand"    " r,I")))]
+  ""
+  "and%i2\t%0,%1,%2"
+  [(set_attr "type" "logical")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "<optab><mode>3"
   [(set (match_operand:X                0 "register_operand" "=r,r")
-       (any_bitwise:X (match_operand:X 1 "register_operand" "%r,r")
+       (any_or:X (match_operand:X 1 "register_operand" "%r,r")
                       (match_operand:X 2 "arith_operand"    " r,I")))]
   ""
   "<insn>%i2\t%0,%1,%2"
diff --git a/gcc/testsuite/gcc.target/riscv/and-extend-1.c b/gcc/testsuite/gcc.target/riscv/and-extend-1.c
new file mode 100644 (file)
index 0000000..a270d28
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba_zbb -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+void
+foo(unsigned long a, unsigned long* ptr)
+{
+    ptr[0] = a & 0xffffffffUL;
+    ptr[1] &= 0xffffffffUL;
+}
+
+void
+foo2(unsigned long a, unsigned long* ptr)
+{
+    ptr[0] = a & 0xffff;
+    ptr[1] &= 0xffff;
+}
+
+void
+foo3(unsigned int a, unsigned int* ptr)
+{
+    ptr[0] = a & 0xffff;
+    ptr[1] &= 0xffff;
+}
+
+/* { dg-final { scan-assembler-times "zext.w" 1 } } */
+/* { dg-final { scan-assembler-times "zext.h" 2 } } */
+/* { dg-final { scan-assembler-times "lwu" 1 } } */
+/* { dg-final { scan-assembler-times "lhu" 2 } } */
+/* { dg-final { scan-assembler-not "and\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/and-extend-2.c b/gcc/testsuite/gcc.target/riscv/and-extend-2.c
new file mode 100644 (file)
index 0000000..fe639cd
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_zba_zbb -mabi=ilp32" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+void
+foo(unsigned long a, unsigned long* ptr)
+{
+    ptr[0] = a & 0xffffffffUL;
+    ptr[1] &= 0xffffffffUL;
+}
+
+void
+foo2(unsigned long a, unsigned long* ptr)
+{
+    ptr[0] = a & 0xffff;
+    ptr[1] &= 0xffff;
+}
+
+void
+foo3(unsigned int a, unsigned int* ptr)
+{
+    ptr[0] = a & 0xffff;
+    ptr[1] &= 0xffff;
+}
+
+/* { dg-final { scan-assembler-times "zext.h" 2 } } */
+/* { dg-final { scan-assembler-times "lhu" 2 } } */
+/* { dg-final { scan-assembler-not "and\t" } } */