]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Implement instruction patterns for ZBS extension.
authorJim Wilson <jimw@sifive.com>
Wed, 1 Sep 2021 16:28:47 +0000 (00:28 +0800)
committerKito Cheng <kito.cheng@sifive.com>
Mon, 25 Oct 2021 09:10:02 +0000 (17:10 +0800)
2021-10-25  Jim Wilson  <jimw@sifive.com>
    Kito Cheng  <kito.cheng@sifive.com>

gcc/ChangeLog:

* config/riscv/bitmanip.md (shiftm1): New.
(*bset<mode>): Ditto.
(*bset<mode>_mask): Ditto.
(*bset<mode>_1): Ditto.
(*bset<mode>_1_mask): Ditto.
(*bseti<mode>): Ditto.
(*bclr<mode>): Ditto.
(*bclri<mode>): Ditto.
(*binv<mode>): Ditto.
(*binvi<mode>): Ditto.
(*bext<mode>): Ditto.
(*bexti): Ditto.
* config/riscv/predicates.md (splittable_const_int_operand):
Handle bseti.
(single_bit_mask_operand): New.
(not_single_bit_mask_operand): Ditto.
(const31_operand): Ditto.
(const63_operand): Ditto.
* config/riscv/riscv.c (riscv_build_integer_1): Handle bseti.
(riscv_output_move): Ditto.
(riscv_print_operand): Handle new operand type: T and S.
* config/riscv/riscv.h (SINGLE_BIT_MASK_OPERAND): New.

2021-10-25  Jia-Wei Chen  <jiawei@iscas.ac.cn>
    Shi-Hua Liao  <shihua@iscas.ac.cn>

gcc/testsuite/ChangeLog:

* gcc.target/riscv/zba-slliuw.c: Apply zbs to this testcase.
* gcc.target/riscv/zbs-bclr.c: New.
* gcc.target/riscv/zbs-bext.c: Ditto.
* gcc.target/riscv/zbs-binv.c: Ditto.
* gcc.target/riscv/zbs-bset.c: Ditto.

Co-authored-by: Kito Cheng <kito.cheng@sifive.com>
Co-authored-by: Jia-Wei Chen <jiawei@iscas.ac.cn>
Co-authored-by: Shi-Hua Liao <shihua@iscas.ac.cn>
gcc/config/riscv/bitmanip.md
gcc/config/riscv/predicates.md
gcc/config/riscv/riscv.c
gcc/config/riscv/riscv.h
gcc/testsuite/gcc.target/riscv/zba-slliuw.c
gcc/testsuite/gcc.target/riscv/zbs-bclr.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zbs-bext.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zbs-binv.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zbs-bset.c [new file with mode: 0644]

index 4d6245140495b0dec31ec7ba81c29b15aa07501c..59779b48f27c97546cc94c6a7445de562a034493 100644 (file)
@@ -40,6 +40,7 @@
                                 (ctz "ctz")
                                 (popcount "cpop")])
 
+(define_mode_attr shiftm1 [(SI "const31_operand") (DI "const63_operand")])
 
 ;; ZBA extension.
 
   "TARGET_ZBB"
   "<bitmanip_insn>\t%0,%1,%2"
   [(set_attr "type" "bitmanip")])
+
+;; ZBS extension.
+
+(define_insn "*bset<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (ior:X (ashift:X (const_int 1)
+                        (match_operand:QI 2 "register_operand" "r"))
+              (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_ZBS"
+  "bset\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_mask"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (ior:X (ashift:X (const_int 1)
+                        (subreg:QI
+                         (and:X (match_operand:X 2 "register_operand" "r")
+                                (match_operand 3 "<X:shiftm1>" "i")) 0))
+              (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_ZBS"
+  "bset\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_1"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (ashift:X (const_int 1)
+                 (match_operand:QI 1 "register_operand" "r")))]
+  "TARGET_ZBS"
+  "bset\t%0,x0,%1"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bset<mode>_1_mask"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (ashift:X (const_int 1)
+                 (subreg:QI
+                  (and:X (match_operand:X 1 "register_operand" "r")
+                         (match_operand 2 "<X:shiftm1>" "i")) 0)))]
+  "TARGET_ZBS"
+  "bset\t%0,x0,%1"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bseti<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (ior:X (match_operand:X 1 "register_operand" "r")
+              (match_operand 2 "single_bit_mask_operand" "i")))]
+  "TARGET_ZBS"
+  "bseti\t%0,%1,%S2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bclr<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (and:X (rotate:X (const_int -2)
+                        (match_operand:QI 2 "register_operand" "r"))
+              (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_ZBS"
+  "bclr\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bclri<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (and:X (match_operand:X 1 "register_operand" "r")
+              (match_operand 2 "not_single_bit_mask_operand" "i")))]
+  "TARGET_ZBS"
+  "bclri\t%0,%1,%T2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*binv<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (xor:X (ashift:X (const_int 1)
+                        (match_operand:QI 2 "register_operand" "r"))
+              (match_operand:X 1 "register_operand" "r")))]
+  "TARGET_ZBS"
+  "binv\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*binvi<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (xor:X (match_operand:X 1 "register_operand" "r")
+              (match_operand 2 "single_bit_mask_operand" "i")))]
+  "TARGET_ZBS"
+  "binvi\t%0,%1,%S2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bext<mode>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (zero_extract:X (match_operand:X 1 "register_operand" "r")
+                       (const_int 1)
+                       (zero_extend:X
+                        (match_operand:QI 2 "register_operand" "r"))))]
+  "TARGET_ZBS"
+  "bext\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
+
+(define_insn "*bexti"
+  [(set (match_operand:X 0 "register_operand" "=r")
+       (zero_extract:X (match_operand:X 1 "register_operand" "r")
+                       (const_int 1)
+                       (match_operand 2 "immediate_operand" "i")))]
+  "TARGET_ZBS"
+  "bexti\t%0,%1,%2"
+  [(set_attr "type" "bitmanip")])
index 23211513554463cce3e7df13d995f487042994b5..3da6fd4c0491cf5af505d828b3fc8a4da3d72ce6 100644 (file)
   if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     return false;
 
+  /* Check whether the constant can be loaded in a single
+     instruction with zbs extensions.  */
+  if (TARGET_64BIT && TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op)))
+    return false;
+
   /* Otherwise check whether the constant can be loaded in a single
      instruction.  */
   return !LUI_OPERAND (INTVAL (op)) && !SMALL_OPERAND (INTVAL (op));
 {
   return riscv_gpr_save_operation_p (op);
 })
+
+;; Predicates for the ZBS extension.
+(define_predicate "single_bit_mask_operand"
+  (and (match_code "const_int")
+       (match_test "pow2p_hwi (INTVAL (op))")))
+
+(define_predicate "not_single_bit_mask_operand"
+  (and (match_code "const_int")
+       (match_test "pow2p_hwi (~INTVAL (op))")))
+
+(define_predicate "const31_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 31")))
+
+(define_predicate "const63_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 63")))
index 3ed34f234e555f4f9bba8dfcf8e6b8f6f53558bf..3943eb4636d9c1d9c6c1cc20139580ca1b290515 100644 (file)
@@ -410,6 +410,13 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS],
       codes[0].value = value;
       return 1;
     }
+  if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (value))
+    {
+      /* Simply BSETI.  */
+      codes[0].code = UNKNOWN;
+      codes[0].value = value;
+      return 1;
+    }
 
   /* End with ADDI.  When constructing HImode constants, do not generate any
      intermediate value that is not itself a valid HImode constant.  The
@@ -2220,7 +2227,17 @@ riscv_output_move (rtx dest, rtx src)
          }
 
       if (src_code == CONST_INT)
-       return "li\t%0,%1";
+       {
+         if (SMALL_OPERAND (INTVAL (src)) || LUI_OPERAND (INTVAL (src)))
+           return "li\t%0,%1";
+
+         if (TARGET_ZBS
+             && SINGLE_BIT_MASK_OPERAND (INTVAL (src)))
+           return "bseti\t%0,zero,%S1";
+
+         /* Should never reach here.  */
+         abort ();
+       }
 
       if (src_code == HIGH)
        return "lui\t%0,%h1";
@@ -3561,7 +3578,9 @@ riscv_memmodel_needs_release_fence (enum memmodel model)
    'A' Print the atomic operation suffix for memory model OP.
    'F' Print a FENCE if the memory model requires a release.
    'z' Print x0 if OP is zero, otherwise print OP normally.
-   'i' Print i if the operand is not a register.  */
+   'i' Print i if the operand is not a register.
+   'S' Print shift-index of single-bit mask OP.
+   'T' Print shift-index of inverted single-bit mask OP.  */
 
 static void
 riscv_print_operand (FILE *file, rtx op, int letter)
@@ -3601,6 +3620,18 @@ riscv_print_operand (FILE *file, rtx op, int letter)
         fputs ("i", file);
       break;
 
+    case 'S':
+      {
+       rtx newop = GEN_INT (ctz_hwi (INTVAL (op)));
+       output_addr_const (file, newop);
+       break;
+      }
+    case 'T':
+      {
+       rtx newop = GEN_INT (ctz_hwi (~INTVAL (op)));
+       output_addr_const (file, newop);
+       break;
+      }
     default:
       switch (code)
        {
index f47d5b40a66afa902ce52dc4e5b6ad1e07880f65..6428712473560d4b9b19ba766237c86a425576d2 100644 (file)
@@ -526,6 +526,14 @@ enum reg_class
   (((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH)      \
    || ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0)
 
+/* If this is a single bit mask, then we can load it with bseti.  But this
+   is not useful for any of the low 31 bits because we can use addi or lui
+   to load them.  It is wrong for loading SImode 0x80000000 on rv64 because it
+   needs to be sign-extended.  So we restrict this to the upper 32-bits
+   only.  */
+#define SINGLE_BIT_MASK_OPERAND(VALUE) \
+  (pow2p_hwi (VALUE) && (ctz_hwi (VALUE) >= 32))
+
 /* Stack layout; function entry, exit and calling.  */
 
 #define STACK_GROWS_DOWNWARD 1
index 50399f68e089d136d6771fe7411a30321d87b80c..a7a3dc77d535dd592bbfff06a3c0aed5dedf085b 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-march=rv64gc_zba -mabi=lp64 -O2" } */
+/* { dg-options "-march=rv64gc_zba_zbs -mabi=lp64 -O2" } */
 
 long
 foo (long i)
@@ -8,4 +8,4 @@ foo (long i)
 }
 /* XXX: This pattern need combine improvement or intermediate instruction
  *      from zbs.   */
-/* { dg-final { scan-assembler-not "slli.uw" } } */
+/* { dg-final { scan-assembler "slli.uw" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bclr.c b/gcc/testsuite/gcc.target/riscv/zbs-bclr.c
new file mode 100644 (file)
index 0000000..4a3c2f1
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bclr */
+long
+foo0 (long i, long j)
+{
+  return i & ~(1L << j);
+}
+
+/* bclri */
+long
+foo1 (long i)
+{
+  return i & ~(1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "bclr\t" 1 } } */
+/* { dg-final { scan-assembler-times "bclri\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bext.c b/gcc/testsuite/gcc.target/riscv/zbs-bext.c
new file mode 100644 (file)
index 0000000..a093cdc
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bext */
+long
+foo0 (long i, long j)
+{
+  return 1L & (i >> j);
+}
+
+/* bexti */
+long
+foo1 (long i)
+{
+  return 1L & (i >> 20);
+}
+
+/* { dg-final { scan-assembler-times "bexti\t" 1 } } */
+/* { dg-final { scan-assembler-times "bext\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-binv.c b/gcc/testsuite/gcc.target/riscv/zbs-binv.c
new file mode 100644 (file)
index 0000000..e4e48b9
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* binv */
+long
+foo0 (long i, long j)
+{
+  return i ^ (1L << j);
+}
+
+/* binvi */
+long
+foo1 (long i)
+{
+  return i ^ (1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "binv\t" 1 } } */
+/* { dg-final { scan-assembler-times "binvi\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bset.c b/gcc/testsuite/gcc.target/riscv/zbs-bset.c
new file mode 100644 (file)
index 0000000..733d427
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64 -O2" } */
+
+/* bset */
+long
+sub0 (long i, long j)
+{
+  return i | (1L << j);
+}
+
+/* bset_mask */
+long
+sub1 (long i, long j)
+{
+  return i | (1L << (j & 0x3f));
+}
+
+/* bset_1 */
+long
+sub2 (long i)
+{
+  return 1L << i;
+}
+
+/* bset_1_mask */
+long
+sub3 (long i)
+{
+  return 1L << (i & 0x3f);
+}
+
+/* bseti */
+long
+sub4 (long i)
+{
+  return i | (1L << 20);
+}
+
+/* { dg-final { scan-assembler-times "bset\t" 4 } } */
+/* { dg-final { scan-assembler-times "bseti\t" 1 } } */
+/* { dg-final { scan-assembler-not "andi" } } */