public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension
@ 2023-02-10 22:41 Philipp Tomsich
  2023-02-10 22:41 ` [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns Philipp Tomsich
                   ` (9 more replies)
  0 siblings, 10 replies; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich


The (proposed, but about to be frozen) Zicond extension adds 2
unconditional R-type instructions that can be used to build branchless
sequences that have conditional-arithmetic/bitwise/select semantics
and integrate will with the RISC-V architecture.

See the Zicond specification for details:
  https://github.com/riscv/riscv-zicond/releases/download/v1.0-draft-20230207/riscv-zicond_1.0-draft-20230207.pdf

The Zicond extension defines a conditional-zero(-or-value)
instruction, which is similar to the following C construct:
  rd = rc ? rs : 0

This functionality can be tied back into if-convertsion and also
matches some typical programming idioms.  This series includes backend
support for Zicond both to handle conditional-zero constructions and
if-conversion.  We also change the previously submitted
XVentanaCondops support to use the Zicond infrastructure.

Tested against SPEC CPU 2017.



Philipp Tomsich (10):
  docs: Document a canonical RTL for a conditional-zero insns
  RISC-V: Recognize Zicond (conditional operations) extension
  RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask
    if-conversion
  RISC-V: Support immediates in Zicond
  RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez
  RISC-V: Recognize sign-extract + and cases for czero.eqz/nez
  RISC-V: Recognize bexti in negated if-conversion
  ifcvt: add if-conversion to conditional-zero instructions
  RISC-V: Recognize xventanacondops extension
  RISC-V: Support XVentanaCondOps extension

 gcc/common/config/riscv/riscv-common.cc       |   5 +
 gcc/config/riscv/predicates.md                |  12 +
 gcc/config/riscv/riscv-opts.h                 |   5 +
 gcc/config/riscv/riscv.cc                     |  15 ++
 gcc/config/riscv/riscv.md                     |  28 +++
 gcc/config/riscv/riscv.opt                    |   3 +
 gcc/config/riscv/xventanacondops.md           |  29 +++
 gcc/config/riscv/zicond.md                    | 156 +++++++++++++
 gcc/doc/md.texi                               |  17 ++
 gcc/ifcvt.cc                                  | 216 ++++++++++++++++++
 .../gcc.target/riscv/xventanacondops-and-01.c |  16 ++
 .../gcc.target/riscv/xventanacondops-and-02.c |  15 ++
 .../gcc.target/riscv/xventanacondops-eq-01.c  |  11 +
 .../gcc.target/riscv/xventanacondops-eq-02.c  |  14 ++
 .../riscv/xventanacondops-ifconv-imm.c        |  19 ++
 .../gcc.target/riscv/xventanacondops-le-01.c  |  16 ++
 .../gcc.target/riscv/xventanacondops-le-02.c  |  11 +
 .../gcc.target/riscv/xventanacondops-lt-01.c  |  16 ++
 .../gcc.target/riscv/xventanacondops-lt-03.c  |  16 ++
 .../gcc.target/riscv/xventanacondops-ne-01.c  |  10 +
 .../gcc.target/riscv/xventanacondops-ne-03.c  |  13 ++
 .../gcc.target/riscv/xventanacondops-ne-04.c  |  13 ++
 .../gcc.target/riscv/xventanacondops-xor-01.c |  14 ++
 .../gcc.target/riscv/zicond-and-01.c          |  16 ++
 .../gcc.target/riscv/zicond-and-02.c          |  15 ++
 gcc/testsuite/gcc.target/riscv/zicond-eq-01.c |  11 +
 gcc/testsuite/gcc.target/riscv/zicond-eq-02.c |  14 ++
 .../gcc.target/riscv/zicond-ifconv-imm.c      |  19 ++
 gcc/testsuite/gcc.target/riscv/zicond-le-01.c |  16 ++
 gcc/testsuite/gcc.target/riscv/zicond-le-02.c |  11 +
 gcc/testsuite/gcc.target/riscv/zicond-lt-01.c |  16 ++
 gcc/testsuite/gcc.target/riscv/zicond-lt-03.c |  16 ++
 gcc/testsuite/gcc.target/riscv/zicond-ne-01.c |  10 +
 gcc/testsuite/gcc.target/riscv/zicond-ne-03.c |  13 ++
 gcc/testsuite/gcc.target/riscv/zicond-ne-04.c |  13 ++
 .../gcc.target/riscv/zicond-xor-01.c          |  14 ++
 36 files changed, 854 insertions(+)
 create mode 100644 gcc/config/riscv/xventanacondops.md
 create mode 100644 gcc/config/riscv/zicond.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-and-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-and-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-eq-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-eq-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ifconv-imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-le-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-le-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-lt-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-lt-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-04.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-xor-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-le-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-le-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-lt-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-04.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-xor-01.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-02-10 23:18   ` Andrew Pinski
  2023-02-10 22:41 ` [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension Philipp Tomsich
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

On RISC-V, conditional-zero (i.e., move a register value or zero to a
destination register) instructions are part if the Zicond extension.
To support architectures that have similar constructs, we define a
canonical RTL representation that can be used in if-conversion.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/doc/md.texi | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 7235d34c4b3..579462ea67f 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -8347,6 +8347,23 @@ operand of @code{mult} is also a shift, then that is extended also.
 This transformation is only applied when it can be proven that the
 original operation had sufficient precision to prevent overflow.
 
+@cindex @code{conditional-zero}, canonicalization of
+@item
+A machine that has an instruction that performs a conditional-zero
+operation (i.e., an instruction that moves a register value or puts 0
+into the destination register) should specify the pattern for that
+instruction as:
+@smallexample
+(define_insn ""
+  [(set (match_operand:@var{m} 0 @dots{})
+        (and:@var{m}
+          (neg:@var{m} (@var{eq_or_ne} (match_operand:@var{m} 1 @dots{})
+                                       (const_int 0)))
+          (match_operand:@var{m} 2 @dots{})))]
+  "@dots{}"
+  "@dots{}")
+@end smallexample
+
 @end itemize
 
 Further canonicalization rules are defined in the function
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
  2023-02-10 22:41 ` [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-20 17:44   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion Philipp Tomsich
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

This adds the RISC-V Zicond extension to the option parsing.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc: Recognize "zicond"
	as part of an architecture string.
	* config/riscv/riscv-opts.h (MASK_ZICOND): Define.
	(TARGET_ZICOND): Define.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/common/config/riscv/riscv-common.cc | 3 +++
 gcc/config/riscv/riscv-opts.h           | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 787674003cb..999e1926db1 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -163,6 +163,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0},
   {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0},
 
+  {"zicond", ISA_SPEC_CLASS_NONE, 1, 0},
+
   {"zawrs", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"zba", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1181,6 +1183,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
 
   {"zicsr",    &gcc_options::x_riscv_zi_subext, MASK_ZICSR},
   {"zifencei", &gcc_options::x_riscv_zi_subext, MASK_ZIFENCEI},
+  {"zicond",   &gcc_options::x_riscv_zi_subext, MASK_ZICOND},
 
   {"zawrs", &gcc_options::x_riscv_za_subext, MASK_ZAWRS},
 
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index ff398c0a2ae..61d5212da20 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -69,9 +69,11 @@ enum stack_protector_guard {
 
 #define MASK_ZICSR    (1 << 0)
 #define MASK_ZIFENCEI (1 << 1)
+#define MASK_ZICOND   (1 << 2)
 
 #define TARGET_ZICSR    ((riscv_zi_subext & MASK_ZICSR) != 0)
 #define TARGET_ZIFENCEI ((riscv_zi_subext & MASK_ZIFENCEI) != 0)
+#define TARGET_ZICOND   ((riscv_zi_subext & MASK_ZICOND) != 0)
 
 #define MASK_ZAWRS   (1 << 0)
 #define TARGET_ZAWRS ((riscv_za_subext & MASK_ZAWRS) != 0)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
  2023-02-10 22:41 ` [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns Philipp Tomsich
  2023-02-10 22:41 ` [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-20 17:53   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond Philipp Tomsich
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

Adds a pattern to map the output of noce_try_store_flag_mask
if-conversion in the combiner onto vt.maskc<n>; the input patterns
supported are similar to the following:
  (set (reg/v/f:DI 75 [ <retval> ])
       (and:DI (neg:DI (ne:DI (reg:DI 82)
		       (const_int 0 [0])))
	       (reg/v/f:DI 75 [ <retval> ])))

To ensure that the combine-pass doesn't get confused about
profitability, we recognize the idiom as requiring a single
instruction when the Zicond extension is present.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_rtx_costs): Recongnize the idiom
	for conditional-zero as a single instruction for TARGET_ZICOND
	* config/riscv/riscv.md: Include zicond.md.
	* config/riscv/zicond.md: New file.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-ne-03.c: New test.
	* gcc.target/riscv/zicond-ne-04.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/riscv.cc                     | 15 ++++++++++
 gcc/config/riscv/riscv.md                     |  1 +
 gcc/config/riscv/zicond.md                    | 30 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/zicond-ne-03.c | 13 ++++++++
 gcc/testsuite/gcc.target/riscv/zicond-ne-04.c | 13 ++++++++
 5 files changed, 72 insertions(+)
 create mode 100644 gcc/config/riscv/zicond.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-04.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index e4d3e1a3229..7e69a652fc5 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2331,6 +2331,21 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
       return false;
 
     case AND:
+      /* czero.eqz/nez */
+      if ((TARGET_ZICOND)
+	  && mode == word_mode
+	  && GET_CODE (XEXP (x, 0)) == NEG)
+	{
+	  rtx inner = XEXP (XEXP (x, 0), 0);
+
+	  if ((GET_CODE (inner) == EQ || GET_CODE (inner) == NE)
+	      && CONST_INT_P (XEXP (inner, 1))
+	      && INTVAL (XEXP (inner, 1)) == 0)
+	    {
+	      *total = COSTS_N_INSNS (1);
+	      return true;
+	    }
+	}
       /* slli.uw pattern for zba.  */
       if (TARGET_ZBA && TARGET_64BIT && mode == DImode
 	  && GET_CODE (XEXP (x, 0)) == ASHIFT)
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index e8b5fc6644d..7c632bb4d65 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3228,3 +3228,4 @@ (define_insn "riscv_prefetchi_<mode>"
 (include "generic.md")
 (include "sifive-7.md")
 (include "vector.md")
+(include "zicond.md")
diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
new file mode 100644
index 00000000000..278e3a67802
--- /dev/null
+++ b/gcc/config/riscv/zicond.md
@@ -0,0 +1,30 @@
+;; Machine description for the RISC-V Zicond extension
+;; Copyright (C) 2022-23 Free Software Foundation, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_code_iterator eq_or_ne [eq ne])
+(define_code_attr eqz [(eq "nez") (ne "eqz")])
+
+(define_insn "*czero.<eqz>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(and:DI (neg:DI (eq_or_ne:DI
+			(match_operand:DI 1 "register_operand" "r")
+			(const_int 0)))
+		(match_operand:DI 2 "register_operand" "r")))]
+  "TARGET_ZICOND"
+  "czero.<eqz>\t%0,%2,%1")
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ne-03.c b/gcc/testsuite/gcc.target/riscv/zicond-ne-03.c
new file mode 100644
index 00000000000..887b1273ce7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-ne-03.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mtune=thead-c906" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz" } } */
+
+long long ne3(long long a, long long b)
+{
+  if (a != 0)
+    return b;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ne-04.c b/gcc/testsuite/gcc.target/riscv/zicond-ne-04.c
new file mode 100644
index 00000000000..6f6df06b4b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-ne-04.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mtune=thead-c906" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long long ne4(long long a, long long b)
+{
+  if (a != 0)
+    return 0;
+
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (2 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-20 18:00   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez Philipp Tomsich
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

When if-conversion encounters sequences using immediates, the
sequences can't trivially map back onto czero.eqz/czero.nezt (even if
benefitial) due to czero.eqz/czero.nez not having immediate forms.

This adds a splitter to rewrite opportunities for Zicond that operate
on an immediate by first putting the immediate into a register to
enable the non-immediate czero.eqz/czero.nez instructions to operate
on the value.

Consider code, such as

  long func2 (long a, long c)
  {
    if (c)
      a = 2;
    else
      a = 5;
    return a;
  }

which will be converted to

  func2:
	seqz    a0,a2
	neg     a0,a0
	andi    a0,a0,3
	addi    a0,a0,2
	ret

Following this change, we generate

	li      a0,3
	czero.nez a0,a0,a2
	addi    a0,a0,2
	ret

This commit also introduces a simple unit test for if-conversion with
immediate (literal) values as the sources for simple sets in the THEN
and ELSE blocks. The test checks that the conditional-zero instruction
(czero.eqz/nez) is emitted as part of the resulting branchless
instruction sequence.

gcc/ChangeLog:

	* config/riscv/zicond.md: Support immediates for
	czero.eqz/czero.nez through a splitter.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-ifconv-imm.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/zicond.md                    | 20 +++++++++++++++++++
 .../gcc.target/riscv/zicond-ifconv-imm.c      | 19 ++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c

diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 278e3a67802..19d0b35585b 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -28,3 +28,23 @@ (define_insn "*czero.<eqz>"
 		(match_operand:DI 2 "register_operand" "r")))]
   "TARGET_ZICOND"
   "czero.<eqz>\t%0,%2,%1")
+
+;; Zicond does not have immediate forms, so we need to do extra work
+;; to support these: if we encounter a vt.maskc/n with an immediate,
+;; we split this into a load-immediate followed by a czero.eqz/nez.
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+	(and:DI (neg:DI (match_operator:DI 1 "equality_operator"
+			       [(match_operand:DI 2 "register_operand")
+				(const_int 0)]))
+		(match_operand:DI 3 "immediate_operand")))
+   (clobber (match_operand:DI 4 "register_operand"))]
+  "TARGET_ZICOND"
+  [(set (match_dup 4) (match_dup 3))
+   (set (match_dup 0) (and:DI (neg:DI (match_dup 1))
+			      (match_dup 4)))]
+{
+  /* Eliminate the clobber/temporary, if it is not needed. */
+  if (!rtx_equal_p (operands[0], operands[2]))
+     operands[4] = operands[0];
+})
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c b/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c
new file mode 100644
index 00000000000..f410537a4f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-ifconv-imm.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+/* Each function below should emit a czero.nez instruction */
+
+long
+foo0 (long a, long b, long c)
+{
+  if (c)
+    a = 0;
+  else
+    a = 5;
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */
+/* { dg-final { scan-assembler-not "beqz\t" } } */
+/* { dg-final { scan-assembler-not "bnez\t" } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (3 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-21 19:31   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez Philipp Tomsich
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

When if-conversion in noce_try_store_flag_mask starts the sequence off
with an order-operator, our patterns for czero.eqz/nez will receive
the result of the order-operator as a register argument; consequently,
they can't know that the result will be either 1 or 0.

To convey this information (and make czero.eqz/nez applicable), we
wrap the result of the order-operator in a eq/ne against (const_int 0).
This commit adds the split pattern to handle these cases.

During if-conversion, if noce_try_store_flag_mask succeeds, we may see
    if (cur < next) {
	next = 0;
    }
transformed into
   27: r82:SI=ltu(r76:DI,r75:DI)
      REG_DEAD r76:DI
   28: r81:SI=r82:SI^0x1
      REG_DEAD r82:SI
   29: r80:DI=zero_extend(r81:SI)
      REG_DEAD r81:SI

This currently escapes the combiner, as RISC-V does not have a pattern
to apply the 'slt' instruction to 'geu' verbs.  By adding a pattern in
this commit, we match such cases.

gcc/ChangeLog:

	* config/riscv/predicates.md (anyge_operator): Define.
	(anygt_operator): Same.
	(anyle_operator): Same.
	(anylt_operator): Same.
	* config/riscv/riscv.md: Helpers for ge(u) & le(u).
	* config/riscv/zicond.md: Add split to wrap an an
	order-operator suitably for generating czero.eqz/nez

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-le-02.c: New test.
	* gcc.target/riscv/zicond-lt-03.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/predicates.md                | 12 +++++
 gcc/config/riscv/riscv.md                     | 26 ++++++++++
 gcc/config/riscv/zicond.md                    | 50 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/zicond-le-02.c | 11 ++++
 gcc/testsuite/gcc.target/riscv/zicond-lt-03.c | 16 ++++++
 5 files changed, 115 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-le-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-lt-03.c

diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 034d088c656..6b6f867824e 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -204,6 +204,18 @@ (define_predicate "modular_operator"
 (define_predicate "equality_operator"
   (match_code "eq,ne"))
 
+(define_predicate "anyge_operator"
+  (match_code "ge,geu"))
+
+(define_predicate "anygt_operator"
+  (match_code "gt,gtu"))
+
+(define_predicate "anyle_operator"
+  (match_code "le,leu"))
+
+(define_predicate "anylt_operator"
+  (match_code "lt,ltu"))
+
 (define_predicate "order_operator"
   (match_code "eq,ne,lt,ltu,le,leu,ge,geu,gt,gtu"))
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 7c632bb4d65..6f255a80379 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2668,6 +2668,19 @@ (define_insn "*sge<u>_<X:mode><GPR:mode>"
   [(set_attr "type" "slt")
    (set_attr "mode" "<X:MODE>")])
 
+(define_split
+  [(set (match_operand:GPR 0 "register_operand")
+	(match_operator:GPR 1 "anyle_operator"
+	       [(match_operand:X 2 "register_operand")
+		(match_operand:X 3 "register_operand")]))]
+  "TARGET_ZICOND"
+  [(set (match_dup 0) (match_dup 4))
+   (set (match_dup 0) (eq:GPR (match_dup 0) (const_int 0)))]
+ {
+  operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == LE ? LT : LTU,
+				<GPR:MODE>mode, operands[3], operands[2]);
+ })
+
 (define_insn "*slt<u>_<X:mode><GPR:mode>"
   [(set (match_operand:GPR           0 "register_operand" "= r")
 	(any_lt:GPR (match_operand:X 1 "register_operand" "  r")
@@ -2689,6 +2702,19 @@ (define_insn "*sle<u>_<X:mode><GPR:mode>"
   [(set_attr "type" "slt")
    (set_attr "mode" "<X:MODE>")])
 
+(define_split
+  [(set (match_operand:GPR 0 "register_operand")
+	(match_operator:GPR 1 "anyge_operator"
+	       [(match_operand:X 2 "register_operand")
+		(match_operand:X 3 "register_operand")]))]
+  "TARGET_ZICOND"
+  [(set (match_dup 0) (match_dup 4))
+   (set (match_dup 0) (eq:GPR (match_dup 0) (const_int 0)))]
+{
+  operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == GE ? LT : LTU,
+				<GPR:MODE>mode, operands[2], operands[3]);
+})
+
 ;;
 ;;  ....................
 ;;
diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 19d0b35585b..9d1ce067150 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -48,3 +48,53 @@ (define_split
   if (!rtx_equal_p (operands[0], operands[2]))
      operands[4] = operands[0];
 })
+
+;; Make order operators digestible to the vt.maskc<n> logic by
+;; wrapping their result in a comparison against (const_int 0).
+
+;; "a >= b" is "!(a < b)"
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (neg:X (match_operator:X 1 "anyge_operator"
+			     [(match_operand:X 2 "register_operand")
+			      (match_operand:X 3 "arith_operand")]))
+	       (match_operand:X 4 "register_operand")))
+   (clobber (match_operand:X 5 "register_operand"))]
+  "TARGET_ZICOND"
+  [(set (match_dup 5) (match_dup 6))
+   (set (match_dup 0) (and:X (neg:X (eq:X (match_dup 5) (const_int 0)))
+			     (match_dup 4)))]
+{
+  operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == GE ? LT : LTU,
+				<X:MODE>mode, operands[2], operands[3]);
+})
+
+;; "a > b"
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (neg:X (match_operator:X 1 "anygt_operator"
+			     [(match_operand:X 2 "register_operand")
+			      (match_operand:X 3 "arith_operand")]))
+	       (match_operand:X 4 "register_operand")))
+   (clobber (match_operand:X 5 "register_operand"))]
+  "TARGET_ZICOND"
+  [(set (match_dup 5) (match_dup 1))
+   (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 5) (const_int 0)))
+			     (match_dup 4)))])
+
+;; "a <= b" is "!(a > b)"
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (neg:X (match_operator:X 1 "anyle_operator"
+			     [(match_operand:X 2 "register_operand")
+			      (match_operand:X 3 "arith_operand")]))
+	       (match_operand:X 4 "register_operand")))
+   (clobber (match_operand:X 5 "register_operand"))]
+  "TARGET_ZICOND"
+  [(set (match_dup 5) (match_dup 6))
+   (set (match_dup 0) (and:X (neg:X (eq:X (match_dup 5) (const_int 0)))
+			     (match_dup 4)))]
+{
+  operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == LE ? GT : GTU,
+				<X:MODE>mode, operands[2], operands[3]);
+})
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-le-02.c b/gcc/testsuite/gcc.target/riscv/zicond-le-02.c
new file mode 100644
index 00000000000..32844bc0278
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-le-02.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long le2 (long long a, long long b, long long c)
+{
+  return (a <= c) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "sgt\t" 1 } } */
+/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-lt-03.c b/gcc/testsuite/gcc.target/riscv/zicond-lt-03.c
new file mode 100644
index 00000000000..1c4f0d6ba10
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-lt-03.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long sink (long long);
+
+long long lt3 (long long a, long long b)
+{
+  if (a < b)
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "slt\t" 1 } } */
+/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (4 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-21 19:40   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion Philipp Tomsich
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

Users might use explicit arithmetic operations to create a mask and
then and it, in a sequence like
    cond = (bits >> SHIFT) & 1;
    mask = ~(cond - 1);
    val &= mask;
which will present as a single-bit sign-extract.

Dependening on what combination of XVentanaCondOps and Zbs are
available, this will map to the following sequences:
 - bexti + czero,     if both Zbs and XVentanaCondOps are present
 - andi + czero,      if only XVentanaCondOps is available and the
		      sign-extract is operating on bits 10:0 (bit 11
		      can't be reached, as the immediate is
		      sign-extended)
 - slli + srli + and, otherwise.

gcc/ChangeLog:

	* config/riscv/zicond.md: Recognize SIGN_EXTRACT of a
	single-bit followed by AND for Zicond.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-le-01.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/zicond.md                    | 45 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/zicond-le-01.c | 16 +++++++
 2 files changed, 61 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-le-01.c

diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 9d1ce067150..15fdaa539f1 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -98,3 +98,48 @@ (define_split
   operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]) == LE ? GT : GTU,
 				<X:MODE>mode, operands[2], operands[3]);
 })
+
+;; Users might use explicit arithmetic operations to create a mask and
+;; then and it, in a sequence like
+;;    cond = (bits >> SHIFT) & 1;
+;;    mask = ~(cond - 1);
+;;    val &= mask;
+;; which will present as a single-bit sign-extract in the combiner.
+;;
+;; This will give rise to any of the following cases:
+;; - with Zbs and XVentanaCondOps: bexti + vt.maskc
+;; - with XVentanaCondOps (but w/o Zbs):
+;;   - andi + vt.maskc, if the mask is representable in the immediate
+;;                      (which requires extra care due to the immediate
+;;                       being sign-extended)
+;;   - slli + srli + and
+;; - otherwise: slli + srli + and
+
+;; With Zbb, we have bexti for all possible bits...
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (sign_extract:X (match_operand:X 1 "register_operand")
+			       (const_int 1)
+			       (match_operand 2 "immediate_operand"))
+	       (match_operand:X 3 "register_operand")))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND && TARGET_ZBS"
+  [(set (match_dup 4) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2)))
+   (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 4) (const_int 0)))
+			     (match_dup 3)))])
+
+;; ...whereas RV64I only allows us access to bits 0..10 in a single andi.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(and:X (sign_extract:X (match_operand:X 1 "register_operand")
+			       (const_int 1)
+			       (match_operand 2 "immediate_operand"))
+	       (match_operand:X 3 "register_operand")))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND && !TARGET_ZBS && (UINTVAL (operands[2]) < 11)"
+  [(set (match_dup 4) (and:X (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 4) (const_int 0)))
+			     (match_dup 3)))]
+{
+  operands[2] = GEN_INT(1 << UINTVAL(operands[2]));
+})
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-le-01.c b/gcc/testsuite/gcc.target/riscv/zicond-le-01.c
new file mode 100644
index 00000000000..e5902d1ca5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-le-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long sink (long long);
+
+long long le1 (long long a, long long b)
+{
+  if (a <= b)
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "sgt\t" 1 } } */
+/* { dg-final { scan-assembler-times "czero.eqz\t" 1 } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (5 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-21 19:56   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions Philipp Tomsich
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

While the positive case "if ((bits >> SHAMT) & 1)" for SHAMT 0..10 can
trigger conversion into efficient branchless sequences
  - with Zbs (bexti + neg + and)
  - with Zicond (andi + czero.nez)
the inverted/negated case results in
  andi a5,a0,1024
  seqz a5,a5
  neg a5,a5
  and a5,a5,a1
due to how the sequence presents to the combine pass.

This adds an additional splitter to reassociate the polarity reversed
case into bexti + addi, if Zbs is present.

gcc/ChangeLog:

	* config/riscv/zicond.md: Add split to reassociate
	"andi + seqz + neg" into "bexti + addi".

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/zicond.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 15fdaa539f1..0aad61c7009 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -143,3 +143,13 @@ (define_split
 {
   operands[2] = GEN_INT(1 << UINTVAL(operands[2]));
 })
+
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+	(neg:X (eq:X (zero_extract:X (match_operand:X 1 "register_operand")
+				     (const_int 1)
+				     (match_operand 2 "immediate_operand"))
+		     (const_int 0))))]
+  "!TARGET_ZICOND && TARGET_ZBS"
+  [(set (match_dup 0) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2)))
+   (set (match_dup 0) (plus:X (match_dup 0) (const_int -1)))])
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (6 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-02-10 23:07   ` Andrew Pinski
  2023-02-13  7:31   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension Philipp Tomsich
  2023-02-10 22:41 ` [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension Philipp Tomsich
  9 siblings, 2 replies; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

Some architectures, as it the case on RISC-V with the proposed
ZiCondOps and the vendor-defined XVentanaCondOps, define a
conditional-zero instruction that is equivalent to:
 - the positive form:  rd = (rc != 0) ? rs : 0
 - the negated form:   rd = (rc == 0) ? rs : 0

While noce_try_store_flag_mask will somewhat work for this case, it
will generate a number of atomic RTX that will misdirect the cost
calculation and may be too long (i.e., 4 RTX and more) to successfully
merge at combine-time.

Instead, we add two new transforms that attempt to build up what we
define as the canonical form of a conditional-zero expression:

  (set (match_operand 0 "register_operand" "=r")
       (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
                           (const_int 0)))
            (match_operand 2 "register_operand" "r")))

Architectures that provide a conditional-zero are thus expected to
define an instruction matching this pattern in their backend.

Based on this, we support the following cases:
 - noce_try_condzero:
      a ? a : b
      a ? b : 0  (and then/else swapped)
     !a ? b : 0  (and then/else swapped)
 - noce_try_condzero_arith:
     conditional-plus, conditional-minus, conditional-and,
     conditional-or, conditional-xor, conditional-shift,
     conditional-and

Given that this is hooked into the CE passes, it is less powerful than
a tree-pass (e.g., it can not transform cases where an extension, such
as for uint16_t operations is in either the then or else-branch
together with the arithmetic) but already covers a good array of cases
and triggers across SPEC CPU 2017.

Adding transformations in a tree pass should come in a future
improvement.

gcc/ChangeLog:

	* ifcvt.cc (noce_emit_insn): Add prototype.
	(noce_emit_condzero): Helper for noce_try_condzero and
	noce_try_condzero_arith transforms.
	(noce_try_condzero): New transform.
	(noce_try_condzero_arith): New transform for conditional
	arithmetic that can be built up by exploiting that the
	conditional-zero instruction will inject 0, which acts
	as the neutral element for operations.
	(noce_process_if_block): Call noce_try_condzero and
	noce_try_condzero_arith.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xventanacondops-and-01.c: New test.
	* gcc.target/riscv/xventanacondops-and-02.c: New test.
	* gcc.target/riscv/xventanacondops-eq-01.c: New test.
	* gcc.target/riscv/xventanacondops-eq-02.c: New test.
	* gcc.target/riscv/xventanacondops-lt-01.c: New test.
	* gcc.target/riscv/xventanacondops-ne-01.c: New test.
	* gcc.target/riscv/xventanacondops-xor-01.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/ifcvt.cc                                  | 216 ++++++++++++++++++
 .../gcc.target/riscv/zicond-and-01.c          |  16 ++
 .../gcc.target/riscv/zicond-and-02.c          |  15 ++
 gcc/testsuite/gcc.target/riscv/zicond-eq-01.c |  11 +
 gcc/testsuite/gcc.target/riscv/zicond-eq-02.c |  14 ++
 gcc/testsuite/gcc.target/riscv/zicond-lt-01.c |  16 ++
 gcc/testsuite/gcc.target/riscv/zicond-ne-01.c |  10 +
 .../gcc.target/riscv/zicond-xor-01.c          |  14 ++
 8 files changed, 312 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-xor-01.c

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 008796838f7..7ac3bd8f18e 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -97,6 +97,7 @@ static int find_if_case_2 (basic_block, edge, edge);
 static int dead_or_predicable (basic_block, basic_block, basic_block,
 			       edge, int);
 static void noce_emit_move_insn (rtx, rtx);
+static rtx_insn *noce_emit_insn (rtx);
 static rtx_insn *block_has_only_trap (basic_block);
 static void need_cmov_or_rewire (basic_block, hash_set<rtx_insn *> *,
 				 hash_map<rtx_insn *, int> *);
@@ -787,6 +788,9 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
 static int noce_try_minmax (struct noce_if_info *);
 static int noce_try_abs (struct noce_if_info *);
 static int noce_try_sign_mask (struct noce_if_info *);
+static rtx noce_emit_condzero (struct noce_if_info *, rtx, bool = false);
+static int noce_try_condzero (struct noce_if_info *);
+static int noce_try_condzero_arith (struct noce_if_info *);
 
 /* Return the comparison code for reversed condition for IF_INFO,
    or UNKNOWN if reversing the condition is not possible.  */
@@ -1664,6 +1668,214 @@ noce_try_addcc (struct noce_if_info *if_info)
   return FALSE;
 }
 
+/* Helper to noce_try_condzero: cond ? a : 0. */
+static rtx
+noce_emit_condzero (struct noce_if_info *if_info, rtx a, bool reverse)
+{
+  /* The canonical form for a conditional-zero-or-value is:
+       (set (match_operand 0 "register_operand" "=r")
+	    (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
+				(const_int 0)))
+		 (match_operand 2 "register_operand" "r")))
+   */
+
+  machine_mode opmode = GET_MODE (if_info->x);
+  enum rtx_code code = GET_CODE (if_info->cond);
+  rtx cond;
+  rtx op_a = XEXP (if_info->cond, 0);
+  rtx op_b = XEXP (if_info->cond, 1);
+
+  /* If it is not a EQ/NE comparison against const0_rtx, canonicalize
+     by first synthesizing a truth-value and then building a NE
+     condition around it. */
+  if ((code != EQ && code != NE) || XEXP (if_info->cond, 1) != const0_rtx)
+    {
+      rtx tmp = gen_reg_rtx (opmode);
+
+      start_sequence ();
+      cond = gen_rtx_fmt_ee (code, opmode, op_a, op_b);
+      if (!noce_emit_insn (gen_rtx_SET (tmp, cond)))
+	{
+	  end_sequence ();
+
+	  /* If we can't emit this pattern, try to reverse it and
+	     invert the polarity of the second test. */
+	  start_sequence ();
+	  cond = gen_rtx_fmt_ee (reverse_condition (code), opmode, op_a, op_b);
+	  if (!noce_emit_insn (gen_rtx_SET (tmp, cond))) {
+	    end_sequence ();
+	    return NULL_RTX;
+	  }
+
+	  /* We have recovered by reversing the first comparison,
+	     so we need change the second one around as well... */
+	  reverse = !reverse;
+	}
+      rtx_insn *seq = get_insns ();
+      end_sequence ();
+      emit_insn (seq);
+
+      /* Set up the second comparison that will be embedded in the
+	 canonical conditional-zero-or-value RTX. */
+      code = NE;
+      op_a = tmp;
+      op_b = const0_rtx;
+    }
+
+  cond = gen_rtx_fmt_ee (reverse ? reverse_condition (code) : code,
+			 opmode, op_a, op_b);
+
+  /* Build (and (neg (eq_or_ne ... const0_rtx)) (reg <a>)) */
+  rtx target = gen_reg_rtx (opmode);
+  rtx czero = gen_rtx_AND (opmode, gen_rtx_NEG (opmode, cond), a);
+  noce_emit_move_insn (target, czero);
+
+  return target;
+}
+
+/* Use a conditional-zero instruction for "if (test) x = 0;", if available. */
+static int
+noce_try_condzero (struct noce_if_info *if_info)
+{
+  rtx target;
+  rtx_insn *seq;
+  int reversep = 0;
+  /* Keep local copies of the constituent elements of if_info, as we
+     may be changing them.  We are not allowed to modify if_info
+     though, as we may fail in this function and can't leave different
+     semantics behind for the next functions.  */
+  rtx a = if_info->a;
+  rtx b = if_info->b;
+  rtx x = if_info->x;
+  rtx cond = if_info->cond;
+  enum rtx_code code = GET_CODE (cond);
+  rtx cond_arg0 = XEXP (cond, 0);
+  rtx cond_arg1 = XEXP (cond, 1);
+  rtx orig_b = NULL_RTX;
+
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
+  /* We may encounter the form "(b != 0) ? b : a", which can be
+     simplified to "b | ((b != 0) ? 0 : a)".  */
+  if (code == NE && cond_arg1 == const0_rtx &&
+      REG_P (b) && rtx_equal_p (b, cond_arg0))
+    {
+      orig_b = b;
+      b = const0_rtx;
+    }
+
+  /* We may encounter the form "(b == 0) ? b : a", which can be
+     simplied to "(b == 0) ? 0 : a".  */
+  if (code == EQ && cond_arg1 == const0_rtx &&
+      REG_P (b) && rtx_equal_p (b, cond_arg0))
+    {
+      b = const0_rtx;
+    }
+
+  start_sequence ();
+
+  if ((a == const0_rtx && (REG_P (b) || rtx_equal_p (b, x)))
+      || ((reversep = (noce_reversed_cond_code (if_info) != UNKNOWN))
+	  && b == const0_rtx && (REG_P (a) || rtx_equal_p (a, x))))
+    {
+      target = noce_emit_condzero(if_info, reversep ? a : b, reversep);
+
+      /* Handle the case where we replace b in "(b != 0) ? b : a" with
+	 with const0_rtx to then emit "b | ((b != 0) ? 0 : a)".  */
+      if (orig_b && target)
+	target = expand_simple_binop (GET_MODE (x), IOR, orig_b,
+				      target, x, 0, OPTAB_WIDEN);
+
+      if (target)
+	{
+	  if (target != if_info->x)
+	    noce_emit_move_insn (if_info->x, target);
+
+	  seq = end_ifcvt_sequence (if_info);
+	  if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
+	    return FALSE;
+
+	  emit_insn_before_setloc (seq, if_info->jump,
+				   INSN_LOCATION (if_info->insn_a));
+	  if_info->transform_name = "noce_try_condzero";
+
+	  return TRUE;
+	}
+    }
+
+  end_sequence ();
+
+  return FALSE;
+}
+
+/* Convert "if (test) x op= a;" to a branchless sequence using the
+   canonical form for a conditional-zero. */
+static int
+noce_try_condzero_arith (struct noce_if_info *if_info)
+{
+  rtx target;
+  rtx_insn *seq;
+  rtx_code op = GET_CODE (if_info->a);
+  const rtx arg0 = XEXP (if_info->a, 0);
+  const rtx arg1 = XEXP (if_info->a, 1);
+
+  if (!noce_simple_bbs (if_info))
+    return FALSE;
+
+  /* Check for no else condition.  */
+  if (!rtx_equal_p (if_info->x, if_info->b))
+    return FALSE;
+
+  if (op != PLUS && op != MINUS && op != IOR && op != XOR &&
+      op != ASHIFT && op != ASHIFTRT && op != LSHIFTRT && op != AND)
+    return FALSE;
+
+  if (!rtx_equal_p (if_info->x, arg0))
+    return FALSE;
+
+  start_sequence ();
+
+  target = noce_emit_condzero(if_info, arg1, op != AND ? true : false);
+
+  if (target)
+    {
+      rtx op1 = if_info->x;
+      
+      if (op == AND)
+	{
+	  /* Emit "tmp = x & val;" followed by "tmp |= !cond ? x : 0;" */
+	  op1 = expand_simple_binop (GET_MODE (if_info->x), AND, op1,
+				     arg1, NULL_RTX, 0, OPTAB_WIDEN);
+	  op = IOR;
+	}
+
+      if (op1)
+	target = expand_simple_binop (GET_MODE (if_info->x), op, op1,
+				      target, if_info->x, 0, OPTAB_WIDEN);
+    }
+
+  if (target)
+    {
+      if (target != if_info->x)
+	noce_emit_move_insn (if_info->x, target);
+
+      seq = end_ifcvt_sequence (if_info);
+      if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
+	return FALSE;
+
+      emit_insn_before_setloc(seq, if_info->jump,
+			      INSN_LOCATION(if_info->insn_a));
+      if_info->transform_name = "noce_try_condzero_arith";
+
+      return TRUE;
+    }
+
+  end_sequence ();
+
+  return FALSE;
+}
+
 /* Convert "if (test) x = 0;" to "x &= -(test == 0);"  */
 
 static int
@@ -3967,8 +4179,12 @@ noce_process_if_block (struct noce_if_info *if_info)
     {
       if (noce_try_addcc (if_info))
 	goto success;
+      if (noce_try_condzero (if_info))
+	goto success;
       if (noce_try_store_flag_mask (if_info))
 	goto success;
+      if (noce_try_condzero_arith (if_info))
+	goto success;
       if (HAVE_conditional_move
 	  && noce_try_cmove_arith (if_info))
 	goto success;
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-and-01.c b/gcc/testsuite/gcc.target/riscv/zicond-and-01.c
new file mode 100644
index 00000000000..d9b0ff00756
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-and-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long and1(long a, long b, long c, long d)
+{
+  if (c < d)
+    a &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "and\t" 1 } } */
+/* { dg-final { scan-assembler-times "slt" 1 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
+/* { dg-final { scan-assembler-times "or\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-and-02.c b/gcc/testsuite/gcc.target/riscv/zicond-and-02.c
new file mode 100644
index 00000000000..80f417cfb54
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-and-02.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+int and2(int a, int b, long c)
+{
+  if (c)
+    a &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "and\t" 1 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
+/* { dg-final { scan-assembler-times "or\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c b/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
new file mode 100644
index 00000000000..4f933c1db60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long
+eq1 (long a, long b)
+{
+  return (a == 0) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c b/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
new file mode 100644
index 00000000000..a7bc747ab1d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long
+eq2 (long a, long b)
+{
+  if (a == 0)
+    return b;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c b/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
new file mode 100644
index 00000000000..830bfc6449f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long long sink (long long);
+
+long long lt3 (long long a, long long b)
+{
+  if (a < b) 
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */
+/* { dg-final { scan-assembler-times "slt\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c b/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
new file mode 100644
index 00000000000..f25e601ae3c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long long ne1(long long a, long long b)
+{
+  return (a != 0) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
new file mode 100644
index 00000000000..c45a3be2680
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long xor1(long crc, long poly)
+{
+  if (crc & 1)
+    crc ^= poly;
+
+  return crc;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 1 } } */
+/* { dg-final { scan-assembler-times "xor\t" 1 } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (7 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-21 19:57   ` Jeff Law
  2023-02-10 22:41 ` [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension Philipp Tomsich
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

This adds the xventanacondops extension to the option parsing and as a
default for the ventana-vt1 core:

gcc/Changelog:

	* common/config/riscv/riscv-common.cc: Recognize
          "xventanacondops" as part of an architecture string.
	* config/riscv/riscv-opts.h (MASK_XVENTANACONDOPS): Define.
	(TARGET_XVENTANACONDOPS): Define.
	* config/riscv/riscv.opt: Add "riscv_xventanacondops".

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/common/config/riscv/riscv-common.cc | 2 ++
 gcc/config/riscv/riscv-opts.h           | 3 +++
 gcc/config/riscv/riscv.opt              | 3 +++
 3 files changed, 8 insertions(+)

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 999e1926db1..a77a04d68d9 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -1250,6 +1250,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"svinval", &gcc_options::x_riscv_sv_subext, MASK_SVINVAL},
   {"svnapot", &gcc_options::x_riscv_sv_subext, MASK_SVNAPOT},
 
+  {"xventanacondops", &gcc_options::x_riscv_xventanacondops, MASK_XVENTANACONDOPS},
+
   {NULL, NULL, 0}
 };
 
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 61d5212da20..d80e81c6c28 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -191,4 +191,7 @@ enum stack_protector_guard {
    ? 0 \
    : 32 << (__builtin_popcount (riscv_zvl_flags) - 1))
 
+#define MASK_XVENTANACONDOPS (1 << 0)
+#define TARGET_XVENTANACONDOPS ((riscv_xventanacondops & MASK_XVENTANACONDOPS) != 0)
+
 #endif /* ! GCC_RISCV_OPTS_H */
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index e78c99382cd..6ebaad43d0e 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -233,6 +233,9 @@ int riscv_zm_subext
 TargetVariable
 int riscv_sv_subext
 
+TargetVariable
+int riscv_xventanacondops = 0
+
 Enum
 Name(isa_spec_class) Type(enum riscv_isa_spec_class)
 Supported ISA specs (for use with the -misa-spec= option):
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension
  2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
                   ` (8 preceding siblings ...)
  2023-02-10 22:41 ` [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension Philipp Tomsich
@ 2023-02-10 22:41 ` Philipp Tomsich
  2023-04-21 19:58   ` Jeff Law
  9 siblings, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-02-10 22:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, Philipp Tomsich

The vendor-defined XVentanaCondOps extension adds two instructions
with semantics identical to Zicond.

This plugs the 2 new instruction in using the canonical RTX, which
also matches the combiner-input for noce_try_store_flag_mask and
noce_try_store_flag, defined for conditional-zero.

For documentation on XVentanaCondOps, refer to:
  https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.1/ventana-custom-extensions-v1.0.1.pdf

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_rtx_costs): Recognize idiom
	for conditional zero as a single instruction for TARGET_XVENTANACONDOPS.
	* config/riscv/riscv.md: Include xventanacondops.md.
	* config/riscv/zicond.md: Enable splitters for TARGET_XVENTANACONDOPS.
	* config/riscv/xventanacondops.md: New file.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/xventanacondops-and-01.c: New test.
	* gcc.target/riscv/xventanacondops-and-02.c: New test.
	* gcc.target/riscv/xventanacondops-eq-01.c: New test.
	* gcc.target/riscv/xventanacondops-eq-02.c: New test.
	* gcc.target/riscv/xventanacondops-ifconv-imm.c: New test.
	* gcc.target/riscv/xventanacondops-le-01.c: New test.
	* gcc.target/riscv/xventanacondops-le-02.c: New test.
	* gcc.target/riscv/xventanacondops-lt-01.c: New test.
	* gcc.target/riscv/xventanacondops-lt-03.c: New test.
	* gcc.target/riscv/xventanacondops-ne-01.c: New test.
	* gcc.target/riscv/xventanacondops-ne-03.c: New test.
	* gcc.target/riscv/xventanacondops-ne-04.c: New test.
	* gcc.target/riscv/xventanacondops-xor-01.c: New test.

Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
---

 gcc/config/riscv/riscv.cc                     |  4 +--
 gcc/config/riscv/riscv.md                     |  5 ++--
 gcc/config/riscv/xventanacondops.md           | 29 +++++++++++++++++++
 gcc/config/riscv/zicond.md                    | 15 +++++-----
 .../gcc.target/riscv/xventanacondops-and-01.c | 16 ++++++++++
 .../gcc.target/riscv/xventanacondops-and-02.c | 15 ++++++++++
 .../gcc.target/riscv/xventanacondops-eq-01.c  | 11 +++++++
 .../gcc.target/riscv/xventanacondops-eq-02.c  | 14 +++++++++
 .../riscv/xventanacondops-ifconv-imm.c        | 19 ++++++++++++
 .../gcc.target/riscv/xventanacondops-le-01.c  | 16 ++++++++++
 .../gcc.target/riscv/xventanacondops-le-02.c  | 11 +++++++
 .../gcc.target/riscv/xventanacondops-lt-01.c  | 16 ++++++++++
 .../gcc.target/riscv/xventanacondops-lt-03.c  | 16 ++++++++++
 .../gcc.target/riscv/xventanacondops-ne-01.c  | 10 +++++++
 .../gcc.target/riscv/xventanacondops-ne-03.c  | 13 +++++++++
 .../gcc.target/riscv/xventanacondops-ne-04.c  | 13 +++++++++
 .../gcc.target/riscv/xventanacondops-xor-01.c | 14 +++++++++
 17 files changed, 226 insertions(+), 11 deletions(-)
 create mode 100644 gcc/config/riscv/xventanacondops.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-and-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-and-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-eq-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-eq-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ifconv-imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-le-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-le-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-lt-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-lt-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-ne-04.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/xventanacondops-xor-01.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 7e69a652fc5..94ac8f350e6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2331,8 +2331,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
       return false;
 
     case AND:
-      /* czero.eqz/nez */
-      if ((TARGET_ZICOND)
+      /* czero.eqz/nez or vt.maskc/vt.maskcn */
+      if ((TARGET_ZICOND || TARGET_XVENTANACONDOPS)
 	  && mode == word_mode
 	  && GET_CODE (XEXP (x, 0)) == NEG)
 	{
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 6f255a80379..e6b73c316cb 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2673,7 +2673,7 @@ (define_split
 	(match_operator:GPR 1 "anyle_operator"
 	       [(match_operand:X 2 "register_operand")
 		(match_operand:X 3 "register_operand")]))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 0) (match_dup 4))
    (set (match_dup 0) (eq:GPR (match_dup 0) (const_int 0)))]
  {
@@ -2707,7 +2707,7 @@ (define_split
 	(match_operator:GPR 1 "anyge_operator"
 	       [(match_operand:X 2 "register_operand")
 		(match_operand:X 3 "register_operand")]))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 0) (match_dup 4))
    (set (match_dup 0) (eq:GPR (match_dup 0) (const_int 0)))]
 {
@@ -3255,3 +3255,4 @@ (define_insn "riscv_prefetchi_<mode>"
 (include "sifive-7.md")
 (include "vector.md")
 (include "zicond.md")
+(include "xventanacondops.md")
diff --git a/gcc/config/riscv/xventanacondops.md b/gcc/config/riscv/xventanacondops.md
new file mode 100644
index 00000000000..3cca14feaf9
--- /dev/null
+++ b/gcc/config/riscv/xventanacondops.md
@@ -0,0 +1,29 @@
+;; Machine description for X-Ventana-CondOps
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_code_attr vt_n [(eq "n") (ne "")])
+
+(define_insn "*vt.maskc<vt_n>"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(and:DI (neg:DI (eq_or_ne:DI
+			(match_operand:DI 1 "register_operand" "r")
+			(const_int 0)))
+		(match_operand:DI 2 "register_operand" "r")))]
+  "TARGET_XVENTANACONDOPS"
+  "vt.maskc<vt_n>\t%0,%2,%1")
diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md
index 0aad61c7009..ea518bbb5b1 100644
--- a/gcc/config/riscv/zicond.md
+++ b/gcc/config/riscv/zicond.md
@@ -39,7 +39,7 @@ (define_split
 				(const_int 0)]))
 		(match_operand:DI 3 "immediate_operand")))
    (clobber (match_operand:DI 4 "register_operand"))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 4) (match_dup 3))
    (set (match_dup 0) (and:DI (neg:DI (match_dup 1))
 			      (match_dup 4)))]
@@ -60,7 +60,7 @@ (define_split
 			      (match_operand:X 3 "arith_operand")]))
 	       (match_operand:X 4 "register_operand")))
    (clobber (match_operand:X 5 "register_operand"))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 5) (match_dup 6))
    (set (match_dup 0) (and:X (neg:X (eq:X (match_dup 5) (const_int 0)))
 			     (match_dup 4)))]
@@ -77,7 +77,7 @@ (define_split
 			      (match_operand:X 3 "arith_operand")]))
 	       (match_operand:X 4 "register_operand")))
    (clobber (match_operand:X 5 "register_operand"))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 5) (match_dup 1))
    (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 5) (const_int 0)))
 			     (match_dup 4)))])
@@ -90,7 +90,7 @@ (define_split
 			      (match_operand:X 3 "arith_operand")]))
 	       (match_operand:X 4 "register_operand")))
    (clobber (match_operand:X 5 "register_operand"))]
-  "TARGET_ZICOND"
+  "TARGET_ZICOND || TARGET_XVENTANACONDOPS"
   [(set (match_dup 5) (match_dup 6))
    (set (match_dup 0) (and:X (neg:X (eq:X (match_dup 5) (const_int 0)))
 			     (match_dup 4)))]
@@ -123,7 +123,7 @@ (define_split
 			       (match_operand 2 "immediate_operand"))
 	       (match_operand:X 3 "register_operand")))
    (clobber (match_operand:X 4 "register_operand"))]
-  "TARGET_ZICOND && TARGET_ZBS"
+  "(TARGET_ZICOND || TARGET_XVENTANACONDOPS) && TARGET_ZBS"
   [(set (match_dup 4) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2)))
    (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 4) (const_int 0)))
 			     (match_dup 3)))])
@@ -136,7 +136,8 @@ (define_split
 			       (match_operand 2 "immediate_operand"))
 	       (match_operand:X 3 "register_operand")))
    (clobber (match_operand:X 4 "register_operand"))]
-  "TARGET_ZICOND && !TARGET_ZBS && (UINTVAL (operands[2]) < 11)"
+  "(TARGET_ZICOND || TARGET_XVENTANACONDOPS)
+   && !TARGET_ZBS && (UINTVAL (operands[2]) < 11)"
   [(set (match_dup 4) (and:X (match_dup 1) (match_dup 2)))
    (set (match_dup 0) (and:X (neg:X (ne:X (match_dup 4) (const_int 0)))
 			     (match_dup 3)))]
@@ -150,6 +151,6 @@ (define_split
 				     (const_int 1)
 				     (match_operand 2 "immediate_operand"))
 		     (const_int 0))))]
-  "!TARGET_ZICOND && TARGET_ZBS"
+  "!(TARGET_ZICOND || TARGET_XVENTANACONDOPS) && TARGET_ZBS"
   [(set (match_dup 0) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2)))
    (set (match_dup 0) (plus:X (match_dup 0) (const_int -1)))])
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-and-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-and-01.c
new file mode 100644
index 00000000000..9b26cdf0513
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-and-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long and1(long a, long b, long c, long d)
+{
+  if (c < d)
+    a &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "and\t" 1 } } */
+/* { dg-final { scan-assembler-times "slt" 1 } } */
+/* { dg-final { scan-assembler-times "vt.maskcn" 1 } } */
+/* { dg-final { scan-assembler-times "or\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-and-02.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-and-02.c
new file mode 100644
index 00000000000..66d2ec10211
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-and-02.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+int and2(int a, int b, long c)
+{
+  if (c)
+    a &= b;
+
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "and\t" 1 } } */
+/* { dg-final { scan-assembler-times "vt.maskcn" 1 } } */
+/* { dg-final { scan-assembler-times "or\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-01.c
new file mode 100644
index 00000000000..bc877d9e81b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-01.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long
+eq1 (long a, long b)
+{
+  return (a == 0) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskcn" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-02.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-02.c
new file mode 100644
index 00000000000..28317613ba8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-eq-02.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long
+eq2 (long a, long b)
+{
+  if (a == 0)
+    return b;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskcn" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-ifconv-imm.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-ifconv-imm.c
new file mode 100644
index 00000000000..0012e7b669c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-ifconv-imm.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+/* Each function below should emit a vt.maskcn instruction */
+
+long
+foo0 (long a, long b, long c)
+{
+  if (c)
+    a = 0;
+  else
+    a = 5;
+  return a;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskcn\t" 1 } } */
+/* { dg-final { scan-assembler-not "beqz\t" } } */
+/* { dg-final { scan-assembler-not "bnez\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-le-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-le-01.c
new file mode 100644
index 00000000000..eb463e3c161
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-le-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba_zbb_zbs_xventanacondops -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long sink (long long);
+
+long long le1 (long long a, long long b)
+{
+  if (a <= b)
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "sgt\t" 1 } } */
+/* { dg-final { scan-assembler-times "vt.maskc\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-le-02.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-le-02.c
new file mode 100644
index 00000000000..daa115d70c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-le-02.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba_zbb_zbs_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long le2 (long long a, long long b, long long c)
+{
+  return (a <= c) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "sgt\t" 1 } } */
+/* { dg-final { scan-assembler-times "vt.maskcn\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-01.c
new file mode 100644
index 00000000000..18762ee2bd0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-01.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long long sink (long long);
+
+long long lt3 (long long a, long long b)
+{
+  if (a < b) 
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "vt.maskcn\t" 1 } } */
+/* { dg-final { scan-assembler-times "slt\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-03.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-03.c
new file mode 100644
index 00000000000..f671f357f91
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-lt-03.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba_zbb_zbs_xventanacondops -mabi=lp64 -mbranch-cost=4" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz"  } } */
+
+long long sink (long long);
+
+long long lt3 (long long a, long long b)
+{
+  if (a < b)
+    b = 0;
+
+  return sink(b);
+}
+
+/* { dg-final { scan-assembler-times "slt\t" 1 } } */
+/* { dg-final { scan-assembler-times "vt.maskcn\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-01.c
new file mode 100644
index 00000000000..be8375ba5cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-01.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long long ne1(long long a, long long b)
+{
+  return (a != 0) ? b : 0;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskc" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-03.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-03.c
new file mode 100644
index 00000000000..4a762a1ed61
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-03.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64 -mtune=thead-c906" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" "-Os" "-Oz" } } */
+
+long long ne3(long long a, long long b)
+{
+  if (a != 0)
+    return b;
+
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskc" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-04.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-04.c
new file mode 100644
index 00000000000..18b35ac7070
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-ne-04.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64 -mtune=thead-c906" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long long ne4(long long a, long long b)
+{
+  if (a != 0)
+    return 0;
+
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskcn" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/xventanacondops-xor-01.c b/gcc/testsuite/gcc.target/riscv/xventanacondops-xor-01.c
new file mode 100644
index 00000000000..43020790a22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xventanacondops-xor-01.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_xventanacondops -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long xor1(long crc, long poly)
+{
+  if (crc & 1)
+    crc ^= poly;
+
+  return crc;
+}
+
+/* { dg-final { scan-assembler-times "vt.maskc" 1 } } */
+/* { dg-final { scan-assembler-times "xor\t" 1 } } */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-10 22:41 ` [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions Philipp Tomsich
@ 2023-02-10 23:07   ` Andrew Pinski
  2023-02-13 17:32     ` Richard Sandiford
  2023-02-13  7:31   ` Jeff Law
  1 sibling, 1 reply; 31+ messages in thread
From: Andrew Pinski @ 2023-02-10 23:07 UTC (permalink / raw)
  To: Philipp Tomsich
  Cc: gcc-patches, Kito Cheng, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta

On Fri, Feb 10, 2023 at 2:47 PM Philipp Tomsich
<philipp.tomsich@vrull.eu> wrote:
>
> Some architectures, as it the case on RISC-V with the proposed
> ZiCondOps and the vendor-defined XVentanaCondOps, define a
> conditional-zero instruction that is equivalent to:
>  - the positive form:  rd = (rc != 0) ? rs : 0
>  - the negated form:   rd = (rc == 0) ? rs : 0
>
> While noce_try_store_flag_mask will somewhat work for this case, it
> will generate a number of atomic RTX that will misdirect the cost
> calculation and may be too long (i.e., 4 RTX and more) to successfully
> merge at combine-time.

Can you expand on this? Especially when there are patterns that use
(if_then_else) already.

>
> Instead, we add two new transforms that attempt to build up what we
> define as the canonical form of a conditional-zero expression:
>
>   (set (match_operand 0 "register_operand" "=r")
>        (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
>                            (const_int 0)))
>             (match_operand 2 "register_operand" "r")))

Again why are you not using:
(set (reg) (if_then_else (eq_ne (reg) (const_int 0)) (reg) (const_int 0)))
Form instead of the really bad "canonical" form of the above?

Thanks,
Andrew Pinski

>
> Architectures that provide a conditional-zero are thus expected to
> define an instruction matching this pattern in their backend.
>
> Based on this, we support the following cases:
>  - noce_try_condzero:
>       a ? a : b
>       a ? b : 0  (and then/else swapped)
>      !a ? b : 0  (and then/else swapped)
>  - noce_try_condzero_arith:
>      conditional-plus, conditional-minus, conditional-and,
>      conditional-or, conditional-xor, conditional-shift,
>      conditional-and
>
> Given that this is hooked into the CE passes, it is less powerful than
> a tree-pass (e.g., it can not transform cases where an extension, such
> as for uint16_t operations is in either the then or else-branch
> together with the arithmetic) but already covers a good array of cases
> and triggers across SPEC CPU 2017.
>
> Adding transformations in a tree pass should come in a future
> improvement.
>
> gcc/ChangeLog:
>
>         * ifcvt.cc (noce_emit_insn): Add prototype.
>         (noce_emit_condzero): Helper for noce_try_condzero and
>         noce_try_condzero_arith transforms.
>         (noce_try_condzero): New transform.
>         (noce_try_condzero_arith): New transform for conditional
>         arithmetic that can be built up by exploiting that the
>         conditional-zero instruction will inject 0, which acts
>         as the neutral element for operations.
>         (noce_process_if_block): Call noce_try_condzero and
>         noce_try_condzero_arith.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/xventanacondops-and-01.c: New test.
>         * gcc.target/riscv/xventanacondops-and-02.c: New test.
>         * gcc.target/riscv/xventanacondops-eq-01.c: New test.
>         * gcc.target/riscv/xventanacondops-eq-02.c: New test.
>         * gcc.target/riscv/xventanacondops-lt-01.c: New test.
>         * gcc.target/riscv/xventanacondops-ne-01.c: New test.
>         * gcc.target/riscv/xventanacondops-xor-01.c: New test.
>
> Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> ---
>
>  gcc/ifcvt.cc                                  | 216 ++++++++++++++++++
>  .../gcc.target/riscv/zicond-and-01.c          |  16 ++
>  .../gcc.target/riscv/zicond-and-02.c          |  15 ++
>  gcc/testsuite/gcc.target/riscv/zicond-eq-01.c |  11 +
>  gcc/testsuite/gcc.target/riscv/zicond-eq-02.c |  14 ++
>  gcc/testsuite/gcc.target/riscv/zicond-lt-01.c |  16 ++
>  gcc/testsuite/gcc.target/riscv/zicond-ne-01.c |  10 +
>  .../gcc.target/riscv/zicond-xor-01.c          |  14 ++
>  8 files changed, 312 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-01.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-and-02.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
>
> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
> index 008796838f7..7ac3bd8f18e 100644
> --- a/gcc/ifcvt.cc
> +++ b/gcc/ifcvt.cc
> @@ -97,6 +97,7 @@ static int find_if_case_2 (basic_block, edge, edge);
>  static int dead_or_predicable (basic_block, basic_block, basic_block,
>                                edge, int);
>  static void noce_emit_move_insn (rtx, rtx);
> +static rtx_insn *noce_emit_insn (rtx);
>  static rtx_insn *block_has_only_trap (basic_block);
>  static void need_cmov_or_rewire (basic_block, hash_set<rtx_insn *> *,
>                                  hash_map<rtx_insn *, int> *);
> @@ -787,6 +788,9 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
>  static int noce_try_minmax (struct noce_if_info *);
>  static int noce_try_abs (struct noce_if_info *);
>  static int noce_try_sign_mask (struct noce_if_info *);
> +static rtx noce_emit_condzero (struct noce_if_info *, rtx, bool = false);
> +static int noce_try_condzero (struct noce_if_info *);
> +static int noce_try_condzero_arith (struct noce_if_info *);
>
>  /* Return the comparison code for reversed condition for IF_INFO,
>     or UNKNOWN if reversing the condition is not possible.  */
> @@ -1664,6 +1668,214 @@ noce_try_addcc (struct noce_if_info *if_info)
>    return FALSE;
>  }
>
> +/* Helper to noce_try_condzero: cond ? a : 0. */
> +static rtx
> +noce_emit_condzero (struct noce_if_info *if_info, rtx a, bool reverse)
> +{
> +  /* The canonical form for a conditional-zero-or-value is:
> +       (set (match_operand 0 "register_operand" "=r")
> +           (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
> +                               (const_int 0)))
> +                (match_operand 2 "register_operand" "r")))
> +   */
> +
> +  machine_mode opmode = GET_MODE (if_info->x);
> +  enum rtx_code code = GET_CODE (if_info->cond);
> +  rtx cond;
> +  rtx op_a = XEXP (if_info->cond, 0);
> +  rtx op_b = XEXP (if_info->cond, 1);
> +
> +  /* If it is not a EQ/NE comparison against const0_rtx, canonicalize
> +     by first synthesizing a truth-value and then building a NE
> +     condition around it. */
> +  if ((code != EQ && code != NE) || XEXP (if_info->cond, 1) != const0_rtx)
> +    {
> +      rtx tmp = gen_reg_rtx (opmode);
> +
> +      start_sequence ();
> +      cond = gen_rtx_fmt_ee (code, opmode, op_a, op_b);
> +      if (!noce_emit_insn (gen_rtx_SET (tmp, cond)))
> +       {
> +         end_sequence ();
> +
> +         /* If we can't emit this pattern, try to reverse it and
> +            invert the polarity of the second test. */
> +         start_sequence ();
> +         cond = gen_rtx_fmt_ee (reverse_condition (code), opmode, op_a, op_b);
> +         if (!noce_emit_insn (gen_rtx_SET (tmp, cond))) {
> +           end_sequence ();
> +           return NULL_RTX;
> +         }
> +
> +         /* We have recovered by reversing the first comparison,
> +            so we need change the second one around as well... */
> +         reverse = !reverse;
> +       }
> +      rtx_insn *seq = get_insns ();
> +      end_sequence ();
> +      emit_insn (seq);
> +
> +      /* Set up the second comparison that will be embedded in the
> +        canonical conditional-zero-or-value RTX. */
> +      code = NE;
> +      op_a = tmp;
> +      op_b = const0_rtx;
> +    }
> +
> +  cond = gen_rtx_fmt_ee (reverse ? reverse_condition (code) : code,
> +                        opmode, op_a, op_b);
> +
> +  /* Build (and (neg (eq_or_ne ... const0_rtx)) (reg <a>)) */
> +  rtx target = gen_reg_rtx (opmode);
> +  rtx czero = gen_rtx_AND (opmode, gen_rtx_NEG (opmode, cond), a);
> +  noce_emit_move_insn (target, czero);
> +
> +  return target;
> +}
> +
> +/* Use a conditional-zero instruction for "if (test) x = 0;", if available. */
> +static int
> +noce_try_condzero (struct noce_if_info *if_info)
> +{
> +  rtx target;
> +  rtx_insn *seq;
> +  int reversep = 0;
> +  /* Keep local copies of the constituent elements of if_info, as we
> +     may be changing them.  We are not allowed to modify if_info
> +     though, as we may fail in this function and can't leave different
> +     semantics behind for the next functions.  */
> +  rtx a = if_info->a;
> +  rtx b = if_info->b;
> +  rtx x = if_info->x;
> +  rtx cond = if_info->cond;
> +  enum rtx_code code = GET_CODE (cond);
> +  rtx cond_arg0 = XEXP (cond, 0);
> +  rtx cond_arg1 = XEXP (cond, 1);
> +  rtx orig_b = NULL_RTX;
> +
> +  if (!noce_simple_bbs (if_info))
> +    return FALSE;
> +
> +  /* We may encounter the form "(b != 0) ? b : a", which can be
> +     simplified to "b | ((b != 0) ? 0 : a)".  */
> +  if (code == NE && cond_arg1 == const0_rtx &&
> +      REG_P (b) && rtx_equal_p (b, cond_arg0))
> +    {
> +      orig_b = b;
> +      b = const0_rtx;
> +    }
> +
> +  /* We may encounter the form "(b == 0) ? b : a", which can be
> +     simplied to "(b == 0) ? 0 : a".  */
> +  if (code == EQ && cond_arg1 == const0_rtx &&
> +      REG_P (b) && rtx_equal_p (b, cond_arg0))
> +    {
> +      b = const0_rtx;
> +    }
> +
> +  start_sequence ();
> +
> +  if ((a == const0_rtx && (REG_P (b) || rtx_equal_p (b, x)))
> +      || ((reversep = (noce_reversed_cond_code (if_info) != UNKNOWN))
> +         && b == const0_rtx && (REG_P (a) || rtx_equal_p (a, x))))
> +    {
> +      target = noce_emit_condzero(if_info, reversep ? a : b, reversep);
> +
> +      /* Handle the case where we replace b in "(b != 0) ? b : a" with
> +        with const0_rtx to then emit "b | ((b != 0) ? 0 : a)".  */
> +      if (orig_b && target)
> +       target = expand_simple_binop (GET_MODE (x), IOR, orig_b,
> +                                     target, x, 0, OPTAB_WIDEN);
> +
> +      if (target)
> +       {
> +         if (target != if_info->x)
> +           noce_emit_move_insn (if_info->x, target);
> +
> +         seq = end_ifcvt_sequence (if_info);
> +         if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
> +           return FALSE;
> +
> +         emit_insn_before_setloc (seq, if_info->jump,
> +                                  INSN_LOCATION (if_info->insn_a));
> +         if_info->transform_name = "noce_try_condzero";
> +
> +         return TRUE;
> +       }
> +    }
> +
> +  end_sequence ();
> +
> +  return FALSE;
> +}
> +
> +/* Convert "if (test) x op= a;" to a branchless sequence using the
> +   canonical form for a conditional-zero. */
> +static int
> +noce_try_condzero_arith (struct noce_if_info *if_info)
> +{
> +  rtx target;
> +  rtx_insn *seq;
> +  rtx_code op = GET_CODE (if_info->a);
> +  const rtx arg0 = XEXP (if_info->a, 0);
> +  const rtx arg1 = XEXP (if_info->a, 1);
> +
> +  if (!noce_simple_bbs (if_info))
> +    return FALSE;
> +
> +  /* Check for no else condition.  */
> +  if (!rtx_equal_p (if_info->x, if_info->b))
> +    return FALSE;
> +
> +  if (op != PLUS && op != MINUS && op != IOR && op != XOR &&
> +      op != ASHIFT && op != ASHIFTRT && op != LSHIFTRT && op != AND)
> +    return FALSE;
> +
> +  if (!rtx_equal_p (if_info->x, arg0))
> +    return FALSE;
> +
> +  start_sequence ();
> +
> +  target = noce_emit_condzero(if_info, arg1, op != AND ? true : false);
> +
> +  if (target)
> +    {
> +      rtx op1 = if_info->x;
> +
> +      if (op == AND)
> +       {
> +         /* Emit "tmp = x & val;" followed by "tmp |= !cond ? x : 0;" */
> +         op1 = expand_simple_binop (GET_MODE (if_info->x), AND, op1,
> +                                    arg1, NULL_RTX, 0, OPTAB_WIDEN);
> +         op = IOR;
> +       }
> +
> +      if (op1)
> +       target = expand_simple_binop (GET_MODE (if_info->x), op, op1,
> +                                     target, if_info->x, 0, OPTAB_WIDEN);
> +    }
> +
> +  if (target)
> +    {
> +      if (target != if_info->x)
> +       noce_emit_move_insn (if_info->x, target);
> +
> +      seq = end_ifcvt_sequence (if_info);
> +      if (!seq || !targetm.noce_conversion_profitable_p (seq, if_info))
> +       return FALSE;
> +
> +      emit_insn_before_setloc(seq, if_info->jump,
> +                             INSN_LOCATION(if_info->insn_a));
> +      if_info->transform_name = "noce_try_condzero_arith";
> +
> +      return TRUE;
> +    }
> +
> +  end_sequence ();
> +
> +  return FALSE;
> +}
> +
>  /* Convert "if (test) x = 0;" to "x &= -(test == 0);"  */
>
>  static int
> @@ -3967,8 +4179,12 @@ noce_process_if_block (struct noce_if_info *if_info)
>      {
>        if (noce_try_addcc (if_info))
>         goto success;
> +      if (noce_try_condzero (if_info))
> +       goto success;
>        if (noce_try_store_flag_mask (if_info))
>         goto success;
> +      if (noce_try_condzero_arith (if_info))
> +       goto success;
>        if (HAVE_conditional_move
>           && noce_try_cmove_arith (if_info))
>         goto success;
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-and-01.c b/gcc/testsuite/gcc.target/riscv/zicond-and-01.c
> new file mode 100644
> index 00000000000..d9b0ff00756
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-and-01.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
> +
> +long and1(long a, long b, long c, long d)
> +{
> +  if (c < d)
> +    a &= b;
> +
> +  return a;
> +}
> +
> +/* { dg-final { scan-assembler-times "and\t" 1 } } */
> +/* { dg-final { scan-assembler-times "slt" 1 } } */
> +/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
> +/* { dg-final { scan-assembler-times "or\t" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-and-02.c b/gcc/testsuite/gcc.target/riscv/zicond-and-02.c
> new file mode 100644
> index 00000000000..80f417cfb54
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-and-02.c
> @@ -0,0 +1,15 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64 -mbranch-cost=4" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
> +
> +int and2(int a, int b, long c)
> +{
> +  if (c)
> +    a &= b;
> +
> +  return a;
> +}
> +
> +/* { dg-final { scan-assembler-times "and\t" 1 } } */
> +/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
> +/* { dg-final { scan-assembler-times "or\t" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c b/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
> new file mode 100644
> index 00000000000..4f933c1db60
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-eq-01.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
> +
> +long
> +eq1 (long a, long b)
> +{
> +  return (a == 0) ? b : 0;
> +}
> +
> +/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c b/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
> new file mode 100644
> index 00000000000..a7bc747ab1d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-eq-02.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
> +
> +long
> +eq2 (long a, long b)
> +{
> +  if (a == 0)
> +    return b;
> +
> +  return 0;
> +}
> +
> +/* { dg-final { scan-assembler-times "czero.nez" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c b/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
> new file mode 100644
> index 00000000000..830bfc6449f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-lt-01.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
> +
> +long long sink (long long);
> +
> +long long lt3 (long long a, long long b)
> +{
> +  if (a < b)
> +    b = 0;
> +
> +  return sink(b);
> +}
> +
> +/* { dg-final { scan-assembler-times "czero.nez\t" 1 } } */
> +/* { dg-final { scan-assembler-times "slt\t" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c b/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
> new file mode 100644
> index 00000000000..f25e601ae3c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-ne-01.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
> +
> +long long ne1(long long a, long long b)
> +{
> +  return (a != 0) ? b : 0;
> +}
> +
> +/* { dg-final { scan-assembler-times "czero.eqz" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
> new file mode 100644
> index 00000000000..c45a3be2680
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
> +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
> +
> +long xor1(long crc, long poly)
> +{
> +  if (crc & 1)
> +    crc ^= poly;
> +
> +  return crc;
> +}
> +
> +/* { dg-final { scan-assembler-times "czero.eqz" 1 } } */
> +/* { dg-final { scan-assembler-times "xor\t" 1 } } */
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns
  2023-02-10 22:41 ` [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns Philipp Tomsich
@ 2023-02-10 23:18   ` Andrew Pinski
  0 siblings, 0 replies; 31+ messages in thread
From: Andrew Pinski @ 2023-02-10 23:18 UTC (permalink / raw)
  To: Philipp Tomsich
  Cc: gcc-patches, Kito Cheng, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta

On Fri, Feb 10, 2023 at 2:43 PM Philipp Tomsich
<philipp.tomsich@vrull.eu> wrote:
>
> On RISC-V, conditional-zero (i.e., move a register value or zero to a
> destination register) instructions are part if the Zicond extension.
> To support architectures that have similar constructs, we define a
> canonical RTL representation that can be used in if-conversion.

This is seems like worse canonical form than say:
(define_insn ""
  [(set (match_operand:m 0 ...)
      (if_then_else (eq_or_ne (match_operand:m 1 ...) (const_int 0))
         (match_operand:m 2 ...)
         (const_int 0)
       ))]
  "..."
  "...")
(define_insn ""
  [(set (match_operand:m 0 ...)
      (if_then_else (eq_or_ne (match_operand:m 1 ...) (const_int 0))
         (const_int 0)
         (match_operand:m 2 ...)
       ))]
  "..."
  "...")

Why can't you use the above form instead? This is the standard way of
expressing condition moves of 0.
This matches even what aarch64 form is already:
(define_insn "*cmov<mode>_insn"
  [(set (match_operand:ALLI 0 "register_operand" "=r,r,r,r,r,r,r")
        (if_then_else:ALLI
         (match_operator 1 "aarch64_comparison_operator"
          [(match_operand 2 "cc_register" "") (const_int 0)])
         (match_operand:ALLI 3 "aarch64_reg_zero_or_m1_or_1"
"rZ,rZ,UsM,rZ,Ui1,UsM,Ui1")
         (match_operand:ALLI 4 "aarch64_reg_zero_or_m1_or_1"
"rZ,UsM,rZ,Ui1,rZ,UsM,Ui1")))]
  "!((operands[3] == const1_rtx && operands[4] == constm1_rtx)
     || (operands[3] == constm1_rtx && operands[4] == const1_rtx))"
  ;; Final two alternatives should be unreachable, but included for completeness
  "..."
  [(set_attr "type" "csel, csel, csel, csel, csel, mov_imm, mov_imm")]
)

(Which is more complex as it can handle even more than just the simple
case you provide).

Thanks,
Andrew Pinski

> +(define_insn ""
> +  [(set (match_operand:@var{m} 0 @dots{})
> +        (and:@var{m}
> +          (neg:@var{m} (@var{eq_or_ne} (match_operand:@var{m} 1 @dots{})
> +                                       (const_int 0)))
> +          (match_operand:@var{m} 2 @dots{})))]
> +  "@dots{}"
> +  "@dots{}")

>
> Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> ---
>
>  gcc/doc/md.texi | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
> index 7235d34c4b3..579462ea67f 100644
> --- a/gcc/doc/md.texi
> +++ b/gcc/doc/md.texi
> @@ -8347,6 +8347,23 @@ operand of @code{mult} is also a shift, then that is extended also.
>  This transformation is only applied when it can be proven that the
>  original operation had sufficient precision to prevent overflow.
>
> +@cindex @code{conditional-zero}, canonicalization of
> +@item
> +A machine that has an instruction that performs a conditional-zero
> +operation (i.e., an instruction that moves a register value or puts 0
> +into the destination register) should specify the pattern for that
> +instruction as:
> +@smallexample
> +(define_insn ""
> +  [(set (match_operand:@var{m} 0 @dots{})
> +        (and:@var{m}
> +          (neg:@var{m} (@var{eq_or_ne} (match_operand:@var{m} 1 @dots{})
> +                                       (const_int 0)))
> +          (match_operand:@var{m} 2 @dots{})))]
> +  "@dots{}"
> +  "@dots{}")
> +@end smallexample
> +
>  @end itemize
>
>  Further canonicalization rules are defined in the function
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-10 22:41 ` [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions Philipp Tomsich
  2023-02-10 23:07   ` Andrew Pinski
@ 2023-02-13  7:31   ` Jeff Law
  2023-02-28 16:42     ` Maciej W. Rozycki
  1 sibling, 1 reply; 31+ messages in thread
From: Jeff Law @ 2023-02-13  7:31 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> Some architectures, as it the case on RISC-V with the proposed
> ZiCondOps and the vendor-defined XVentanaCondOps, define a
> conditional-zero instruction that is equivalent to:
>   - the positive form:  rd = (rc != 0) ? rs : 0
>   - the negated form:   rd = (rc == 0) ? rs : 0
> 
> While noce_try_store_flag_mask will somewhat work for this case, it
> will generate a number of atomic RTX that will misdirect the cost
> calculation and may be too long (i.e., 4 RTX and more) to successfully
> merge at combine-time.
> 
> Instead, we add two new transforms that attempt to build up what we
> define as the canonical form of a conditional-zero expression:
> 
>    (set (match_operand 0 "register_operand" "=r")
>         (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
>                             (const_int 0)))
>              (match_operand 2 "register_operand" "r")))
> 
> Architectures that provide a conditional-zero are thus expected to
> define an instruction matching this pattern in their backend.
> 
> Based on this, we support the following cases:
>   - noce_try_condzero:
>        a ? a : b
>        a ? b : 0  (and then/else swapped)
>       !a ? b : 0  (and then/else swapped)
>   - noce_try_condzero_arith:
>       conditional-plus, conditional-minus, conditional-and,
>       conditional-or, conditional-xor, conditional-shift,
>       conditional-and
> 
> Given that this is hooked into the CE passes, it is less powerful than
> a tree-pass (e.g., it can not transform cases where an extension, such
> as for uint16_t operations is in either the then or else-branch
> together with the arithmetic) but already covers a good array of cases
> and triggers across SPEC CPU 2017.
> 
> Adding transformations in a tree pass should come in a future
> improvement.
> 
> gcc/ChangeLog:
> 
> 	* ifcvt.cc (noce_emit_insn): Add prototype.
> 	(noce_emit_condzero): Helper for noce_try_condzero and
> 	noce_try_condzero_arith transforms.
> 	(noce_try_condzero): New transform.
> 	(noce_try_condzero_arith): New transform for conditional
> 	arithmetic that can be built up by exploiting that the
> 	conditional-zero instruction will inject 0, which acts
> 	as the neutral element for operations.
> 	(noce_process_if_block): Call noce_try_condzero and
> 	noce_try_condzero_arith.
A few things we've noted while working with this patch internally.

1. The canonical conditional-zero-or-value requires operand 2 to be a 
register.  That will tend to inhibit if-conversion of something like a 
shift-by-constant.  This showed up somewhere in leela.

2. Internally we fixed #1 by forcing that argument into a register when 
it was a constant and reload hasn't completed.  This (naturally) 
resulted in more if-conversions happening.  That in turn caused 
perlbench to fail.  This was tracked down to a conditional-and sequence. 
  I think the call to noce_emit_condzero needs adjustment to pass arg0 
instead of arg1 when OP == AND.

3. The canaonical conditional-zero-or-value assumes the target can do a 
generic SEQ/SNE of two register values.  As you know, on RISC-V we have 
SEQZ/SNEZ.  So we've added another fallback path to handle that case in 
noce_emit_condzero.  You subtract the two values, then you can do an 
SEQZ/SNEZ on the result.




Formatting nits noted below.




> +	  if (!noce_emit_insn (gen_rtx_SET (tmp, cond))) {
> +	    end_sequence ();
> +	    return NULL_RTX;
> +	  }
Open-curly on new line, indented two places from the IF, similarly for 
the close curly.  That will probably require adjusting the indentation 
of the statements.


> +  if (code == NE && cond_arg1 == const0_rtx &&
> +      REG_P (b) && rtx_equal_p (b, cond_arg0))
Don't end with &&, instead bring it down indented one position from the 
open parenthesis.


> +    {
> +      orig_b = b;
> +      b = const0_rtx;
> +    }
> +
> +  /* We may encounter the form "(b == 0) ? b : a", which can be
> +     simplied to "(b == 0) ? 0 : a".  */
> +  if (code == EQ && cond_arg1 == const0_rtx &&
> +      REG_P (b) && rtx_equal_p (b, cond_arg0))
Likewise.


> +    {
> +      target = noce_emit_condzero(if_info, reversep ? a : b, reversep);
Missing whitespace before open-paren of function call.


> +
> +  if (op != PLUS && op != MINUS && op != IOR && op != XOR &&
> +      op != ASHIFT && op != ASHIFTRT && op != LSHIFTRT && op != AND)
Bring the "&&" down to the next line here too.


> +
> +  if (!rtx_equal_p (if_info->x, arg0))
> +    return FALSE;
?!?  What's this for?


> +
> +  target = noce_emit_condzero(if_info, arg1, op != AND ? true : false);
Missing space before open-paren.


> +
> +      emit_insn_before_setloc(seq, if_info->jump,
> +			      INSN_LOCATION(if_info->insn_a));
Here too.

I think the ChangeLog entry for the testsuite needs its filenames 
updated :-)

While this was submitted before stage1 closed, I think we're probably 
too late for it to go forward until we re-open stage1.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-10 23:07   ` Andrew Pinski
@ 2023-02-13 17:32     ` Richard Sandiford
  2023-02-13 18:43       ` Jeff Law
  0 siblings, 1 reply; 31+ messages in thread
From: Richard Sandiford @ 2023-02-13 17:32 UTC (permalink / raw)
  To: Andrew Pinski via Gcc-patches
  Cc: Philipp Tomsich, Andrew Pinski, Kito Cheng, Christoph Muellner,
	Palmer Dabbelt, Andrew Waterman, Vineet Gupta

Andrew Pinski via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> On Fri, Feb 10, 2023 at 2:47 PM Philipp Tomsich
> <philipp.tomsich@vrull.eu> wrote:
>>
>> Some architectures, as it the case on RISC-V with the proposed
>> ZiCondOps and the vendor-defined XVentanaCondOps, define a
>> conditional-zero instruction that is equivalent to:
>>  - the positive form:  rd = (rc != 0) ? rs : 0
>>  - the negated form:   rd = (rc == 0) ? rs : 0
>>
>> While noce_try_store_flag_mask will somewhat work for this case, it
>> will generate a number of atomic RTX that will misdirect the cost
>> calculation and may be too long (i.e., 4 RTX and more) to successfully
>> merge at combine-time.
>
> Can you expand on this? Especially when there are patterns that use
> (if_then_else) already.
>
>>
>> Instead, we add two new transforms that attempt to build up what we
>> define as the canonical form of a conditional-zero expression:
>>
>>   (set (match_operand 0 "register_operand" "=r")
>>        (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
>>                            (const_int 0)))
>>             (match_operand 2 "register_operand" "r")))
>
> Again why are you not using:
> (set (reg) (if_then_else (eq_ne (reg) (const_int 0)) (reg) (const_int 0)))
> Form instead of the really bad "canonical" form of the above?

I don't think one form is inherently better than the other if we think
about just this one case.  But I agree that the if_then_else form is
currently the canonical form for the operation, and extends more
naturally to the general case.  AArch64 already matches specifically
for it (with xzr providing the zero value).

Thanks,
Richard

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-13 17:32     ` Richard Sandiford
@ 2023-02-13 18:43       ` Jeff Law
  2023-02-13 18:53         ` Andrew Pinski
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Law @ 2023-02-13 18:43 UTC (permalink / raw)
  To: Andrew Pinski via Gcc-patches, Philipp Tomsich, Andrew Pinski,
	Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, richard.sandiford



On 2/13/23 10:32, Richard Sandiford via Gcc-patches wrote:
> Andrew Pinski via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>> On Fri, Feb 10, 2023 at 2:47 PM Philipp Tomsich
>> <philipp.tomsich@vrull.eu> wrote:
>>>
>>> Some architectures, as it the case on RISC-V with the proposed
>>> ZiCondOps and the vendor-defined XVentanaCondOps, define a
>>> conditional-zero instruction that is equivalent to:
>>>   - the positive form:  rd = (rc != 0) ? rs : 0
>>>   - the negated form:   rd = (rc == 0) ? rs : 0
>>>
>>> While noce_try_store_flag_mask will somewhat work for this case, it
>>> will generate a number of atomic RTX that will misdirect the cost
>>> calculation and may be too long (i.e., 4 RTX and more) to successfully
>>> merge at combine-time.
>>
>> Can you expand on this? Especially when there are patterns that use
>> (if_then_else) already.
>>
>>>
>>> Instead, we add two new transforms that attempt to build up what we
>>> define as the canonical form of a conditional-zero expression:
>>>
>>>    (set (match_operand 0 "register_operand" "=r")
>>>         (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
>>>                             (const_int 0)))
>>>              (match_operand 2 "register_operand" "r")))
>>
>> Again why are you not using:
>> (set (reg) (if_then_else (eq_ne (reg) (const_int 0)) (reg) (const_int 0)))
>> Form instead of the really bad "canonical" form of the above?
> 
> I don't think one form is inherently better than the other if we think
> about just this one case.  But I agree that the if_then_else form is
> currently the canonical form for the operation, and extends more
> naturally to the general case.  AArch64 already matches specifically
> for it (with xzr providing the zero value).
The more I think about it, the more I prefer the if-then-else form.   My 
biggest hesitation with getting behind one form or the other is a lack 
of knowledge about which is likely better interpreted by simplify-rtx 
and friends -- though it may not matter much in practice.

Jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-13 18:43       ` Jeff Law
@ 2023-02-13 18:53         ` Andrew Pinski
  0 siblings, 0 replies; 31+ messages in thread
From: Andrew Pinski @ 2023-02-13 18:53 UTC (permalink / raw)
  To: Jeff Law
  Cc: Andrew Pinski via Gcc-patches, Philipp Tomsich, Kito Cheng,
	Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta, richard.sandiford

On Mon, Feb 13, 2023 at 10:43 AM Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
> On 2/13/23 10:32, Richard Sandiford via Gcc-patches wrote:
> > Andrew Pinski via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> >> On Fri, Feb 10, 2023 at 2:47 PM Philipp Tomsich
> >> <philipp.tomsich@vrull.eu> wrote:
> >>>
> >>> Some architectures, as it the case on RISC-V with the proposed
> >>> ZiCondOps and the vendor-defined XVentanaCondOps, define a
> >>> conditional-zero instruction that is equivalent to:
> >>>   - the positive form:  rd = (rc != 0) ? rs : 0
> >>>   - the negated form:   rd = (rc == 0) ? rs : 0
> >>>
> >>> While noce_try_store_flag_mask will somewhat work for this case, it
> >>> will generate a number of atomic RTX that will misdirect the cost
> >>> calculation and may be too long (i.e., 4 RTX and more) to successfully
> >>> merge at combine-time.
> >>
> >> Can you expand on this? Especially when there are patterns that use
> >> (if_then_else) already.
> >>
> >>>
> >>> Instead, we add two new transforms that attempt to build up what we
> >>> define as the canonical form of a conditional-zero expression:
> >>>
> >>>    (set (match_operand 0 "register_operand" "=r")
> >>>         (and (neg (eq_or_ne (match_operand 1 "register_operand" "r")
> >>>                             (const_int 0)))
> >>>              (match_operand 2 "register_operand" "r")))
> >>
> >> Again why are you not using:
> >> (set (reg) (if_then_else (eq_ne (reg) (const_int 0)) (reg) (const_int 0)))
> >> Form instead of the really bad "canonical" form of the above?
> >
> > I don't think one form is inherently better than the other if we think
> > about just this one case.  But I agree that the if_then_else form is
> > currently the canonical form for the operation, and extends more
> > naturally to the general case.  AArch64 already matches specifically
> > for it (with xzr providing the zero value).
> The more I think about it, the more I prefer the if-then-else form.   My
> biggest hesitation with getting behind one form or the other is a lack
> of knowledge about which is likely better interpreted by simplify-rtx
> and friends -- though it may not matter much in practice.

In the case of IF_THEN_ELSE, combine tries a few things:
  /* If this is a simple operation applied to an IF_THEN_ELSE, try
     applying it to the arms of the IF_THEN_ELSE.  This often simplifies
     things.  Check for cases where both arms are testing the same
     condition.

Also see simplify_if_then_else inside combine.cc.
I don't think the first one could be done not using IF_THEN_ELSE.

Thanks,
Andrew Pinski

>
> Jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-13  7:31   ` Jeff Law
@ 2023-02-28 16:42     ` Maciej W. Rozycki
  2023-03-11 15:50       ` Jeff Law
  0 siblings, 1 reply; 31+ messages in thread
From: Maciej W. Rozycki @ 2023-02-28 16:42 UTC (permalink / raw)
  To: Jeff Law
  Cc: Philipp Tomsich, gcc-patches, Kito Cheng, Christoph Muellner,
	Palmer Dabbelt, Andrew Waterman, Vineet Gupta

On Mon, 13 Feb 2023, Jeff Law via Gcc-patches wrote:

> 3. The canaonical conditional-zero-or-value assumes the target can do a
> generic SEQ/SNE of two register values.  As you know, on RISC-V we have
> SEQZ/SNEZ.  So we've added another fallback path to handle that case in
> noce_emit_condzero.  You subtract the two values, then you can do an SEQZ/SNEZ
> on the result.

 NB these machine operations are identical to MIPSr6 SELEQZ and SELNEZ 
instructions (cf. ISA_HAS_SEL), so why can't we just duplicate what the 
MIPS backend does?  Or did the MIPS backend do something wrong here?

  Maciej

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions
  2023-02-28 16:42     ` Maciej W. Rozycki
@ 2023-03-11 15:50       ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-03-11 15:50 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Philipp Tomsich, gcc-patches, Kito Cheng, Christoph Muellner,
	Palmer Dabbelt, Andrew Waterman, Vineet Gupta



On 2/28/23 09:42, Maciej W. Rozycki wrote:
> On Mon, 13 Feb 2023, Jeff Law via Gcc-patches wrote:
> 
>> 3. The canaonical conditional-zero-or-value assumes the target can do a
>> generic SEQ/SNE of two register values.  As you know, on RISC-V we have
>> SEQZ/SNEZ.  So we've added another fallback path to handle that case in
>> noce_emit_condzero.  You subtract the two values, then you can do an SEQZ/SNEZ
>> on the result.
> 
>   NB these machine operations are identical to MIPSr6 SELEQZ and SELNEZ
> instructions (cf. ISA_HAS_SEL), so why can't we just duplicate what the
> MIPS backend does?  Or did the MIPS backend do something wrong here?
That's the form that Andrew (and subsequently I) both suggested using. 
Switching to that form may in turn make some of these other issues go away.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension
  2023-02-10 22:41 ` [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension Philipp Tomsich
@ 2023-04-20 17:44   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-20 17:44 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> This adds the RISC-V Zicond extension to the option parsing.
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc: Recognize "zicond"
> 	as part of an architecture string.
> 	* config/riscv/riscv-opts.h (MASK_ZICOND): Define.
> 	(TARGET_ZICOND): Define.
OK
jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion
  2023-02-10 22:41 ` [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion Philipp Tomsich
@ 2023-04-20 17:53   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-20 17:53 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> Adds a pattern to map the output of noce_try_store_flag_mask
> if-conversion in the combiner onto vt.maskc<n>; the input patterns
> supported are similar to the following:
>    (set (reg/v/f:DI 75 [ <retval> ])
>         (and:DI (neg:DI (ne:DI (reg:DI 82)
> 		       (const_int 0 [0])))
> 	       (reg/v/f:DI 75 [ <retval> ])))
> 
> To ensure that the combine-pass doesn't get confused about
> profitability, we recognize the idiom as requiring a single
> instruction when the Zicond extension is present.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_rtx_costs): Recongnize the idiom
> 	for conditional-zero as a single instruction for TARGET_ZICOND
> 	* config/riscv/riscv.md: Include zicond.md.
> 	* config/riscv/zicond.md: New file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-ne-03.c: New test.
> 	* gcc.target/riscv/zicond-ne-04.c: New test.
So as we've discussed earlier on the list.  Conceptually I think we've 
agreed that an if-then-else style of conditional zero is probably a 
better model.

So that will have some impact on this patch since it digs into the RTL 
looking for the (and (neg ...)) form.   But I don't think it changes 
anything conceptually in this patch, just the implementation details.

So I'm OK with this patch once it's updated for the updated form we want 
to be using.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond
  2023-02-10 22:41 ` [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond Philipp Tomsich
@ 2023-04-20 18:00   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-20 18:00 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> When if-conversion encounters sequences using immediates, the
> sequences can't trivially map back onto czero.eqz/czero.nezt (even if
> benefitial) due to czero.eqz/czero.nez not having immediate forms.
> 
> This adds a splitter to rewrite opportunities for Zicond that operate
> on an immediate by first putting the immediate into a register to
> enable the non-immediate czero.eqz/czero.nez instructions to operate
> on the value.
> 
> Consider code, such as
> 
>    long func2 (long a, long c)
>    {
>      if (c)
>        a = 2;
>      else
>        a = 5;
>      return a;
>    }
> 
> which will be converted to
> 
>    func2:
> 	seqz    a0,a2
> 	neg     a0,a0
> 	andi    a0,a0,3
> 	addi    a0,a0,2
> 	ret
> 
> Following this change, we generate
> 
> 	li      a0,3
> 	czero.nez a0,a0,a2
> 	addi    a0,a0,2
> 	ret
> 
> This commit also introduces a simple unit test for if-conversion with
> immediate (literal) values as the sources for simple sets in the THEN
> and ELSE blocks. The test checks that the conditional-zero instruction
> (czero.eqz/nez) is emitted as part of the resulting branchless
> instruction sequence.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/zicond.md: Support immediates for
> 	czero.eqz/czero.nez through a splitter.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-ifconv-imm.c: New test.
Same comment & resolution as with the #3 in this series.

A note though.  I've got Raphael looking at wiring this capability into 
the mov<mode>cc expander as well.  When complete that *may* make this 
patch largely obsolete.  But I don't think we necessarily need to wait 
for that to work to land this patch.

jeff


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez
  2023-02-10 22:41 ` [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez Philipp Tomsich
@ 2023-04-21 19:31   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-21 19:31 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> When if-conversion in noce_try_store_flag_mask starts the sequence off
> with an order-operator, our patterns for czero.eqz/nez will receive
> the result of the order-operator as a register argument; consequently,
> they can't know that the result will be either 1 or 0.
> 
> To convey this information (and make czero.eqz/nez applicable), we
> wrap the result of the order-operator in a eq/ne against (const_int 0).
> This commit adds the split pattern to handle these cases.
> 
> During if-conversion, if noce_try_store_flag_mask succeeds, we may see
>      if (cur < next) {
> 	next = 0;
>      }
> transformed into
>     27: r82:SI=ltu(r76:DI,r75:DI)
>        REG_DEAD r76:DI
>     28: r81:SI=r82:SI^0x1
>        REG_DEAD r82:SI
>     29: r80:DI=zero_extend(r81:SI)
>        REG_DEAD r81:SI
> 
> This currently escapes the combiner, as RISC-V does not have a pattern
> to apply the 'slt' instruction to 'geu' verbs.  By adding a pattern in
> this commit, we match such cases.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/predicates.md (anyge_operator): Define.
> 	(anygt_operator): Same.
> 	(anyle_operator): Same.
> 	(anylt_operator): Same.
> 	* config/riscv/riscv.md: Helpers for ge(u) & le(u).
> 	* config/riscv/zicond.md: Add split to wrap an an
> 	order-operator suitably for generating czero.eqz/nez
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-le-02.c: New test.
> 	* gcc.target/riscv/zicond-lt-03.c: New test.
Conceptually OK.  As has been noted, we need to switch to the 
if-then_else form rather than (and (neg)).    OK with that change.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez
  2023-02-10 22:41 ` [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez Philipp Tomsich
@ 2023-04-21 19:40   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-21 19:40 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> Users might use explicit arithmetic operations to create a mask and
> then and it, in a sequence like
>      cond = (bits >> SHIFT) & 1;
>      mask = ~(cond - 1);
>      val &= mask;
> which will present as a single-bit sign-extract.
> 
> Dependening on what combination of XVentanaCondOps and Zbs are
> available, this will map to the following sequences:
>   - bexti + czero,     if both Zbs and XVentanaCondOps are present
>   - andi + czero,      if only XVentanaCondOps is available and the
> 		      sign-extract is operating on bits 10:0 (bit 11
> 		      can't be reached, as the immediate is
> 		      sign-extended)
>   - slli + srli + and, otherwise.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/zicond.md: Recognize SIGN_EXTRACT of a
> 	single-bit followed by AND for Zicond.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-le-01.c: New test.
Conceptually OK.  In fact using bext to drive if conversions is 
something I think we've got in our queue of things to investigate here. 
So you may have just made Raphael's work easier ;-)

As with the other patches we just need to adjust to using the 
if-then-else form.   You've got a mention of XVentanaCondOps in the 
comments, you might want to change that to zicond.


jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion
  2023-02-10 22:41 ` [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion Philipp Tomsich
@ 2023-04-21 19:56   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-21 19:56 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> While the positive case "if ((bits >> SHAMT) & 1)" for SHAMT 0..10 can
> trigger conversion into efficient branchless sequences
>    - with Zbs (bexti + neg + and)
>    - with Zicond (andi + czero.nez)
> the inverted/negated case results in
>    andi a5,a0,1024
>    seqz a5,a5
>    neg a5,a5
>    and a5,a5,a1
> due to how the sequence presents to the combine pass.
> 
> This adds an additional splitter to reassociate the polarity reversed
> case into bexti + addi, if Zbs is present.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/zicond.md: Add split to reassociate
> 	"andi + seqz + neg" into "bexti + addi".
OK.
jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-02-10 22:41 ` [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension Philipp Tomsich
@ 2023-04-21 19:57   ` Jeff Law
  2023-04-25  9:53     ` Kito Cheng
  0 siblings, 1 reply; 31+ messages in thread
From: Jeff Law @ 2023-04-21 19:57 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> This adds the xventanacondops extension to the option parsing and as a
> default for the ventana-vt1 core:
> 
> gcc/Changelog:
> 
> 	* common/config/riscv/riscv-common.cc: Recognize
>            "xventanacondops" as part of an architecture string.
> 	* config/riscv/riscv-opts.h (MASK_XVENTANACONDOPS): Define.
> 	(TARGET_XVENTANACONDOPS): Define.
> 	* config/riscv/riscv.opt: Add "riscv_xventanacondops".
> 
> Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
OK
jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension
  2023-02-10 22:41 ` [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension Philipp Tomsich
@ 2023-04-21 19:58   ` Jeff Law
  0 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-21 19:58 UTC (permalink / raw)
  To: Philipp Tomsich, gcc-patches
  Cc: Kito Cheng, Christoph Muellner, Palmer Dabbelt, Andrew Waterman,
	Vineet Gupta



On 2/10/23 15:41, Philipp Tomsich wrote:
> The vendor-defined XVentanaCondOps extension adds two instructions
> with semantics identical to Zicond.
> 
> This plugs the 2 new instruction in using the canonical RTX, which
> also matches the combiner-input for noce_try_store_flag_mask and
> noce_try_store_flag, defined for conditional-zero.
> 
> For documentation on XVentanaCondOps, refer to:
>    https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.1/ventana-custom-extensions-v1.0.1.pdf
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_rtx_costs): Recognize idiom
> 	for conditional zero as a single instruction for TARGET_XVENTANACONDOPS.
> 	* config/riscv/riscv.md: Include xventanacondops.md.
> 	* config/riscv/zicond.md: Enable splitters for TARGET_XVENTANACONDOPS.
> 	* config/riscv/xventanacondops.md: New file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/xventanacondops-and-01.c: New test.
> 	* gcc.target/riscv/xventanacondops-and-02.c: New test.
> 	* gcc.target/riscv/xventanacondops-eq-01.c: New test.
> 	* gcc.target/riscv/xventanacondops-eq-02.c: New test.
> 	* gcc.target/riscv/xventanacondops-ifconv-imm.c: New test.
> 	* gcc.target/riscv/xventanacondops-le-01.c: New test.
> 	* gcc.target/riscv/xventanacondops-le-02.c: New test.
> 	* gcc.target/riscv/xventanacondops-lt-01.c: New test.
> 	* gcc.target/riscv/xventanacondops-lt-03.c: New test.
> 	* gcc.target/riscv/xventanacondops-ne-01.c: New test.
> 	* gcc.target/riscv/xventanacondops-ne-03.c: New test.
> 	* gcc.target/riscv/xventanacondops-ne-04.c: New test.
> 	* gcc.target/riscv/xventanacondops-xor-01.c: New test.
OK with the change to use if-then-else.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-04-21 19:57   ` Jeff Law
@ 2023-04-25  9:53     ` Kito Cheng
  2023-04-25 10:15       ` Philipp Tomsich
  2023-04-26  2:28       ` Jeff Law
  0 siblings, 2 replies; 31+ messages in thread
From: Kito Cheng @ 2023-04-25  9:53 UTC (permalink / raw)
  To: Jeff Law
  Cc: Philipp Tomsich, gcc-patches, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta

I am not sure if we should accept this on gcc trunk without binutils support?

On Sat, Apr 22, 2023 at 3:58 AM Jeff Law via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
>
> On 2/10/23 15:41, Philipp Tomsich wrote:
> > This adds the xventanacondops extension to the option parsing and as a
> > default for the ventana-vt1 core:
> >
> > gcc/Changelog:
> >
> >       * common/config/riscv/riscv-common.cc: Recognize
> >            "xventanacondops" as part of an architecture string.
> >       * config/riscv/riscv-opts.h (MASK_XVENTANACONDOPS): Define.
> >       (TARGET_XVENTANACONDOPS): Define.
> >       * config/riscv/riscv.opt: Add "riscv_xventanacondops".
> >
> > Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> OK
> jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-04-25  9:53     ` Kito Cheng
@ 2023-04-25 10:15       ` Philipp Tomsich
  2023-04-25 10:43         ` Kito Cheng
  2023-04-26  2:28       ` Jeff Law
  1 sibling, 1 reply; 31+ messages in thread
From: Philipp Tomsich @ 2023-04-25 10:15 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Jeff Law, gcc-patches, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta

[-- Attachment #1: Type: text/plain, Size: 1112 bytes --]

The binutils support is lingering on-list since Jan 2022:
   https://sourceware.org/pipermail/binutils/2022-January/119388.html

If we get an OK on that one, we will rebase, retest, and merge it.

Thanks,
Philipp.

On Tue, 25 Apr 2023 at 11:53, Kito Cheng <kito.cheng@gmail.com> wrote:

> I am not sure if we should accept this on gcc trunk without binutils
> support?
>
> On Sat, Apr 22, 2023 at 3:58 AM Jeff Law via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> >
> >
> > On 2/10/23 15:41, Philipp Tomsich wrote:
> > > This adds the xventanacondops extension to the option parsing and as a
> > > default for the ventana-vt1 core:
> > >
> > > gcc/Changelog:
> > >
> > >       * common/config/riscv/riscv-common.cc: Recognize
> > >            "xventanacondops" as part of an architecture string.
> > >       * config/riscv/riscv-opts.h (MASK_XVENTANACONDOPS): Define.
> > >       (TARGET_XVENTANACONDOPS): Define.
> > >       * config/riscv/riscv.opt: Add "riscv_xventanacondops".
> > >
> > > Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> > OK
> > jeff
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-04-25 10:15       ` Philipp Tomsich
@ 2023-04-25 10:43         ` Kito Cheng
  0 siblings, 0 replies; 31+ messages in thread
From: Kito Cheng @ 2023-04-25 10:43 UTC (permalink / raw)
  To: Philipp Tomsich
  Cc: Jeff Law, GCC Patches, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta

[-- Attachment #1: Type: text/plain, Size: 1323 bytes --]

I am ok if binutils patch get merged into trunk

Philipp Tomsich <philipp.tomsich@vrull.eu> 於 2023年4月25日 週二 18:15 寫道:

> The binutils support is lingering on-list since Jan 2022:
>    https://sourceware.org/pipermail/binutils/2022-January/119388.html
>
> If we get an OK on that one, we will rebase, retest, and merge it.
>
> Thanks,
> Philipp.
>
> On Tue, 25 Apr 2023 at 11:53, Kito Cheng <kito.cheng@gmail.com> wrote:
>
> > I am not sure if we should accept this on gcc trunk without binutils
> > support?
> >
> > On Sat, Apr 22, 2023 at 3:58 AM Jeff Law via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > >
> > >
> > > On 2/10/23 15:41, Philipp Tomsich wrote:
> > > > This adds the xventanacondops extension to the option parsing and as
> a
> > > > default for the ventana-vt1 core:
> > > >
> > > > gcc/Changelog:
> > > >
> > > >       * common/config/riscv/riscv-common.cc: Recognize
> > > >            "xventanacondops" as part of an architecture string.
> > > >       * config/riscv/riscv-opts.h (MASK_XVENTANACONDOPS): Define.
> > > >       (TARGET_XVENTANACONDOPS): Define.
> > > >       * config/riscv/riscv.opt: Add "riscv_xventanacondops".
> > > >
> > > > Signed-off-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
> > > OK
> > > jeff
> >
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension
  2023-04-25  9:53     ` Kito Cheng
  2023-04-25 10:15       ` Philipp Tomsich
@ 2023-04-26  2:28       ` Jeff Law
  1 sibling, 0 replies; 31+ messages in thread
From: Jeff Law @ 2023-04-26  2:28 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Philipp Tomsich, gcc-patches, Christoph Muellner, Palmer Dabbelt,
	Andrew Waterman, Vineet Gupta



On 4/25/23 03:53, Kito Cheng wrote:
> I am not sure if we should accept this on gcc trunk without binutils support?
Let's get the binutils bits in first.  I don't mind owning that review. 
It just hasn't been a priority due to the gcc-13 freeze.

jeff

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2023-04-26  2:28 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-10 22:41 [RFC PATCH v1 00/10] RISC-V: Support the Zicond (conditional-operations) extension Philipp Tomsich
2023-02-10 22:41 ` [RFC PATCH v1 01/10] docs: Document a canonical RTL for a conditional-zero insns Philipp Tomsich
2023-02-10 23:18   ` Andrew Pinski
2023-02-10 22:41 ` [RFC PATCH v1 02/10] RISC-V: Recognize Zicond (conditional operations) extension Philipp Tomsich
2023-04-20 17:44   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 03/10] RISC-V: Generate czero.eqz/nez on noce_try_store_flag_mask if-conversion Philipp Tomsich
2023-04-20 17:53   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 04/10] RISC-V: Support immediates in Zicond Philipp Tomsich
2023-04-20 18:00   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 05/10] RISC-V: Support noce_try_store_flag_mask as czero.eqz/czero.nez Philipp Tomsich
2023-04-21 19:31   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 06/10] RISC-V: Recognize sign-extract + and cases for czero.eqz/nez Philipp Tomsich
2023-04-21 19:40   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 07/10] RISC-V: Recognize bexti in negated if-conversion Philipp Tomsich
2023-04-21 19:56   ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 08/10] ifcvt: add if-conversion to conditional-zero instructions Philipp Tomsich
2023-02-10 23:07   ` Andrew Pinski
2023-02-13 17:32     ` Richard Sandiford
2023-02-13 18:43       ` Jeff Law
2023-02-13 18:53         ` Andrew Pinski
2023-02-13  7:31   ` Jeff Law
2023-02-28 16:42     ` Maciej W. Rozycki
2023-03-11 15:50       ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 09/10] RISC-V: Recognize xventanacondops extension Philipp Tomsich
2023-04-21 19:57   ` Jeff Law
2023-04-25  9:53     ` Kito Cheng
2023-04-25 10:15       ` Philipp Tomsich
2023-04-25 10:43         ` Kito Cheng
2023-04-26  2:28       ` Jeff Law
2023-02-10 22:41 ` [RFC PATCH v1 10/10] RISC-V: Support XVentanaCondOps extension Philipp Tomsich
2023-04-21 19:58   ` Jeff Law

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).