public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Recognize Zicond extension
@ 2023-07-19 10:11 Xiao Zeng
  2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
                   ` (5 more replies)
  0 siblings, 6 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

Hi all RISC-V folks:

This series of patches completes support for the riscv architecture's
Zicond standard extension instruction set.

Currently, Zicond is in a frozen state.

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

Prior to this, other community members have also done related work, as shown in: 
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611767.html
https://sourceware.org/pipermail/binutils/2023-January/125773.html

Xiao Zeng (5):
  [RISC-V] Recognize Zicond extension
  [RISC-V] Generate Zicond instruction for basic semantics
  [RISC-V] Generate Zicond instruction for select pattern with condition
    eq or neq to 0
  [RISC-V] Generate Zicond instruction for select pattern with condition
    eq or neq to non-zero
  [RISC-V] Generate Zicond instruction for conditional execution

 gcc/common/config/riscv/riscv-common.cc       |   3 +
 gcc/config/riscv/riscv-opts.h                 |   3 +
 gcc/config/riscv/riscv.cc                     | 141 +++++
 gcc/config/riscv/riscv.md                     |   3 +-
 gcc/config/riscv/zicond.md                    |  84 +++
 gcc/ifcvt.cc                                  | 251 ++++++++
 gcc/testsuite/gcc.target/riscv/attribute-20.c |   6 +
 gcc/testsuite/gcc.target/riscv/attribute-21.c |   6 +
 ...ionalArithmetic_compare_0_return_imm_reg.c | 553 +++++++++++++++++
 ...ionalArithmetic_compare_0_return_reg_reg.c | 585 ++++++++++++++++++
 ...nalArithmetic_compare_imm_return_imm_reg.c | 297 +++++++++
 ...nalArithmetic_compare_imm_return_reg_reg.c | 297 +++++++++
 ...nalArithmetic_compare_reg_return_imm_reg.c | 297 +++++++++
 ...nalArithmetic_compare_reg_return_reg_reg.c | 329 ++++++++++
 .../riscv/zicond-primitiveSemantics.c         |  49 ++
 .../zicond-primitiveSemantics_compare_imm.c   |  57 ++
 ...mitiveSemantics_compare_imm_return_0_imm.c |  73 +++
 ...tiveSemantics_compare_imm_return_imm_imm.c |  73 +++
 ...tiveSemantics_compare_imm_return_imm_reg.c |  65 ++
 ...tiveSemantics_compare_imm_return_reg_reg.c |  65 ++
 .../zicond-primitiveSemantics_compare_reg.c   |  65 ++
 ...mitiveSemantics_compare_reg_return_0_imm.c |  73 +++
 ...tiveSemantics_compare_reg_return_imm_imm.c |  73 +++
 ...tiveSemantics_compare_reg_return_imm_reg.c |  65 ++
 ...tiveSemantics_compare_reg_return_reg_reg.c |  77 +++
 .../zicond-primitiveSemantics_return_0_imm.c  |  65 ++
 ...zicond-primitiveSemantics_return_imm_imm.c |  73 +++
 ...zicond-primitiveSemantics_return_imm_reg.c |  65 ++
 ...zicond-primitiveSemantics_return_reg_reg.c |  65 ++
 29 files changed, 3857 insertions(+), 1 deletion(-)
 create mode 100644 gcc/config/riscv/zicond.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/attribute-20.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/attribute-21.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c

-- 
2.17.1


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

* [PATCH 1/5] [RISC-V] Recognize Zicond extension
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
@ 2023-07-19 10:11 ` Xiao Zeng
  2023-07-25 16:35   ` Jeff Law
  2023-07-26 21:11   ` Jeff Law
  2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

This patch is the minimal support for Zicond extension, include
the extension name, mask and target defination.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc: New extension.
	* config/riscv/riscv-opts.h (MASK_ZICOND): New mask.
	(TARGET_ZICOND): New target.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/attribute-20.c: New test.
	* gcc.target/riscv/attribute-21.c: New test.
---
 gcc/common/config/riscv/riscv-common.cc       | 3 +++
 gcc/config/riscv/riscv-opts.h                 | 3 +++
 gcc/testsuite/gcc.target/riscv/attribute-20.c | 6 ++++++
 gcc/testsuite/gcc.target/riscv/attribute-21.c | 6 ++++++
 4 files changed, 18 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/attribute-20.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/attribute-21.c

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 6091d8f281b..8460d83b0f1 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -183,6 +183,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},
@@ -1243,6 +1245,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 cfcf608ea62..cecaee7d200 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -236,6 +236,9 @@ enum riscv_entity
 #define TARGET_ZICBOM ((riscv_zicmo_subext & MASK_ZICBOM) != 0)
 #define TARGET_ZICBOP ((riscv_zicmo_subext & MASK_ZICBOP) != 0)
 
+#define MASK_ZICOND   (1 << 2)
+#define TARGET_ZICOND ((riscv_zi_subext & MASK_ZICOND) != 0)
+
 #define MASK_ZFHMIN   (1 << 0)
 #define MASK_ZFH      (1 << 1)
 #define MASK_ZVFHMIN  (1 << 2)
diff --git a/gcc/testsuite/gcc.target/riscv/attribute-20.c b/gcc/testsuite/gcc.target/riscv/attribute-20.c
new file mode 100644
index 00000000000..b69c36cf4f1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/attribute-20.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-mriscv-attribute -march=rv32i_zicond -mabi=ilp32" } */
+
+void foo(){}
+
+/* { dg-final { scan-assembler ".attribute arch, \"rv32i2p1_zicond1p0\"" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/attribute-21.c b/gcc/testsuite/gcc.target/riscv/attribute-21.c
new file mode 100644
index 00000000000..160312a0d48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/attribute-21.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-mriscv-attribute -march=rv64i_zicond -mabi=lp64" } */
+
+void foo(){}
+
+/* { dg-final { scan-assembler ".attribute arch, \"rv64i2p1_zicond1p0\"" } } */
-- 
2.17.1


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

* [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
  2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
@ 2023-07-19 10:11 ` Xiao Zeng
  2023-07-25 16:35   ` Jeff Law
                     ` (2 more replies)
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
                   ` (3 subsequent siblings)
  5 siblings, 3 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

This patch completes the recognition of the basic semantics
defined in the spec, namely:

Conditional zero, if condition is equal to zero
  rd = (rs2 == 0) ? 0 : rs1
Conditional zero, if condition is non zero
  rd = (rs2 != 0) ? 0 : rs1

gcc/ChangeLog:

	* config/riscv/riscv.md: Include zicond.md
	* config/riscv/zicond.md: New file.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-primitiveSemantics.c: New test.
---
 gcc/config/riscv/riscv.md                     |  1 +
 gcc/config/riscv/zicond.md                    | 84 +++++++++++++++++++
 .../riscv/zicond-primitiveSemantics.c         | 49 +++++++++++
 3 files changed, 134 insertions(+)
 create mode 100644 gcc/config/riscv/zicond.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index d63b584a4c1..6b8c2e8e268 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3317,3 +3317,4 @@
 (include "sifive-7.md")
 (include "thead.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..1cf28589c87
--- /dev/null
+++ b/gcc/config/riscv/zicond.md
@@ -0,0 +1,84 @@
+;; 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_code_attr nez [(eq "eqz") (ne "nez")])
+
+;; Zicond
+(define_insn "*czero.<eqz>.<GPR:mode><ANYI:mode>"
+  [(set (match_operand:GPR 0 "register_operand"                      "=r")
+        (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
+                                    (const_int 0))
+                          (match_operand:GPR 2 "register_operand"    "r")
+                          (const_int 0)))]
+  "TARGET_ZICOND"
+  "czero.<eqz>\t%0,%2,%1"
+)
+
+(define_insn "*czero.<nez>.<GPR:mode><ANYI:mode>"
+  [(set (match_operand:GPR 0 "register_operand"                     "=r")
+        (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
+                                    (const_int 0))
+                          (const_int 0)
+                          (match_operand:GPR 2 "register_operand"   "r")))]
+  "TARGET_ZICOND"
+  "czero.<nez>\t%0,%2,%1"
+)
+
+;; Special optimization under eq/ne in primitive semantics
+(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt1"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "1")
+                          (match_operand:GPR 3 "register_operand" "r")))]
+  "TARGET_ZICOND && operands[1] == operands[2]"
+  "czero.eqz\t%0,%3,%1"
+)
+
+(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt2"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "r")
+                          (match_operand:GPR 3 "register_operand" "1")))]
+  "TARGET_ZICOND && operands[1] == operands[3]"
+  "czero.nez\t%0,%2,%1"
+)
+
+(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt3"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "r")
+                          (match_operand:GPR 3 "register_operand" "1")))]
+  "TARGET_ZICOND && operands[1] == operands[3]"
+  "czero.eqz\t%0,%2,%1"
+)
+
+(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt4"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "1")
+                          (match_operand:GPR 3 "register_operand" "r")))]
+  "TARGET_ZICOND && operands[1] == operands[2]"
+  "czero.nez\t%0,%3,%1"
+)
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
new file mode 100644
index 00000000000..76c5019a992
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0"} } */
+
+long primitiveSemantics_00(long a, long b) { return a == 0 ? 0 : b; }
+
+long primitiveSemantics_01(long a, long b) { return a != 0 ? 0 : b; }
+
+long primitiveSemantics_02(long a, long b) { return a == 0 ? b : 0; }
+
+long primitiveSemantics_03(long a, long b) { return a != 0 ? b : 0; }
+
+long primitiveSemantics_04(long a, long b) {
+  if (a)
+    b = 0;
+  return b;
+}
+
+long primitiveSemantics_05(long a, long b) {
+  if (!a)
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_06(int a, int b) { return a == 0 ? 0 : b; }
+
+int primitiveSemantics_07(int a, int b) { return a != 0 ? 0 : b; }
+
+int primitiveSemantics_08(int a, int b) { return a == 0 ? b : 0; }
+
+int primitiveSemantics_09(int a, int b) { return a != 0 ? b : 0; }
+
+int primitiveSemantics_10(int a, int b) {
+  if (a)
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_11(int a, int b) {
+  if (!a)
+    b = 0;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
-- 
2.17.1


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

* [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
  2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
  2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
@ 2023-07-19 10:11 ` Xiao Zeng
  2023-07-25 17:32   ` Jeff Law
                     ` (3 more replies)
  2023-07-19 10:11 ` [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero Xiao Zeng
                   ` (2 subsequent siblings)
  5 siblings, 4 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

This patch completes the recognition of Zicond when the select pattern
with condition eq or neq to 0 (using equality as an example), namely:

1 rd = (rs2 == 0) ? non-imm : 0
2 rd = (rs2 == 0) ? non-imm : non-imm
3 rd = (rs2 == 0) ? reg : non-imm
4 rd = (rs2 == 0) ? reg : reg

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_rtx_costs): IF_THEN_ELSE costs in Zicond.
        (riscv_expand_conditional_move): Recognize Zicond.
        * config/riscv/riscv.md: Zicond patterns.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 125 ++++++++++++++++++
 gcc/config/riscv/riscv.md                     |   2 +-
 .../zicond-primitiveSemantics_return_0_imm.c  |  65 +++++++++
 ...zicond-primitiveSemantics_return_imm_imm.c |  73 ++++++++++
 ...zicond-primitiveSemantics_return_imm_reg.c |  65 +++++++++
 ...zicond-primitiveSemantics_return_reg_reg.c |  65 +++++++++
 6 files changed, 394 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 38d8eb2fcf5..7e6b24bd232 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	  *total = COSTS_N_INSNS (1);
 	  return true;
 	}
+      else if (TARGET_ZICOND && outer_code == SET &&
+               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
+               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
+               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
+                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
+               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
+                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))
+        {
+          *total = 0;
+          return true;
+        }
       else if (LABEL_REF_P (XEXP (x, 1)) && XEXP (x, 2) == pc_rtx)
 	{
 	  if (equality_operator (XEXP (x, 0), mode)
@@ -3501,6 +3512,120 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
 							  cond, cons, alt)));
       return true;
     }
+  else if (TARGET_ZICOND
+           && (code == EQ || code == NE)
+           && GET_MODE_CLASS (mode) == MODE_INT)
+    {
+      need_eq_ne_p = true;
+      /* 0 + imm  */
+      if (GET_CODE (cons) == CONST_INT && cons == const0_rtx
+          && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
+        {
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          alt = force_reg (mode, alt);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        cons, alt)));
+          return true;
+        }
+      /* imm + imm  */
+      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
+               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
+        {
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          alt = force_reg (mode, alt);
+          rtx temp1 = gen_reg_rtx (mode);
+          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
+          riscv_emit_binary(PLUS, temp1, alt, temp2);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        const0_rtx, alt)));
+          riscv_emit_binary(PLUS, dest, dest, cons);
+          return true;
+        }
+      /* imm + reg  */
+      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
+               && GET_CODE (alt) == REG)
+        {
+          /* Optimize for register value of 0.  */
+          if (op0 == alt && op1 == const0_rtx)
+            {
+              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+              cons = force_reg (mode, cons);
+              emit_insn (gen_rtx_SET (dest,
+                                      gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                            cons, alt)));
+              return true;
+            }
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          rtx temp1 = gen_reg_rtx (mode);
+          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
+          riscv_emit_binary(PLUS, temp1, alt, temp2);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        const0_rtx, alt)));
+          riscv_emit_binary(PLUS, dest, dest, cons);
+          return true;
+        }
+      /* imm + 0  */
+      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
+               && GET_CODE (alt) == CONST_INT && alt == const0_rtx)
+        {
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          cons = force_reg (mode, cons);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        cons, alt)));
+          return true;
+        }
+      /* reg + imm  */
+      else if (GET_CODE (cons) == REG
+               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
+        {
+          /* Optimize for register value of 0.  */
+          if (op0 == cons && op1 == const0_rtx)
+            {
+              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+              alt = force_reg (mode, alt);
+              emit_insn (gen_rtx_SET (dest,
+                                      gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                            cons, alt)));
+              return true;
+            }
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          rtx temp1 = gen_reg_rtx (mode);
+          rtx temp2 = GEN_INT(-1 * INTVAL (alt));
+          riscv_emit_binary(PLUS, temp1, cons, temp2);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        temp1, const0_rtx)));
+          riscv_emit_binary(PLUS, dest, dest, alt);
+          return true;
+        }
+      /* reg + reg  */
+      else if (GET_CODE (cons) == REG && GET_CODE (alt) == REG)
+        {
+          rtx reg1 = gen_reg_rtx (mode);
+          rtx reg2 = gen_reg_rtx (mode);
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE,
+                                      GET_MODE (op0), op0, op1);
+          emit_insn (gen_rtx_SET (reg2,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond2,
+                                                        const0_rtx, cons)));
+          emit_insn (gen_rtx_SET (reg1,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond1,
+                                                        const0_rtx, alt)));
+          riscv_emit_binary(IOR, dest, reg1, reg2);
+          return true;
+        }
+    }
 
   return false;
 }
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 6b8c2e8e268..b4147c7a79c 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2484,7 +2484,7 @@
 	(if_then_else:GPR (match_operand 1 "comparison_operator")
 			  (match_operand:GPR 2 "reg_or_0_operand")
 			  (match_operand:GPR 3 "sfb_alu_operand")))]
-  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
+  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
 {
   if (riscv_expand_conditional_move (operands[0], operands[1],
 				     operands[2], operands[3]))
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
new file mode 100644
index 00000000000..4948558a187
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0"} } */
+
+long primitiveSemantics_return_0_imm_00(long a, long b) {
+  return a == 0 ? 0 : 3;
+}
+
+long primitiveSemantics_return_0_imm_01(long a, long b) {
+  return a != 0 ? 0 : 3;
+}
+
+long primitiveSemantics_return_0_imm_02(long a, long b) {
+  return a == 0 ? 3 : 0;
+}
+
+long primitiveSemantics_return_0_imm_03(long a, long b) {
+  return a != 0 ? 3 : 0;
+}
+
+long primitiveSemantics_return_0_imm_04(long a, long b) {
+  if (a)
+    b = 0;
+  else
+    b = 3;
+  return b;
+}
+
+long primitiveSemantics_return_0_imm_05(long a, long b) {
+  if (!a)
+    b = 0;
+  else
+    b = 3;
+  return b;
+}
+
+int primitiveSemantics_return_0_imm_06(int a, int b) { return a == 0 ? 0 : 3; }
+
+int primitiveSemantics_return_0_imm_07(int a, int b) { return a != 0 ? 0 : 3; }
+
+int primitiveSemantics_return_0_imm_08(int a, int b) { return a == 0 ? 3 : 0; }
+
+int primitiveSemantics_return_0_imm_09(int a, int b) { return a != 0 ? 3 : 0; }
+
+int primitiveSemantics_return_0_imm_10(int a, int b) {
+  if (a)
+    b = 0;
+  else
+    b = 3;
+  return b;
+}
+
+int primitiveSemantics_return_0_imm_11(int a, int b) {
+  if (!a)
+    b = 0;
+  else
+    b = 3;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
new file mode 100644
index 00000000000..ebdca521373
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_imm_imm_00(long a, long b) {
+  return a == 0 ? 4 : 6;
+}
+
+long primitiveSemantics_return_imm_imm_01(long a, long b) {
+  return a != 0 ? 4 : 6;
+}
+
+long primitiveSemantics_return_imm_imm_02(long a, long b) {
+  return a == 0 ? 6 : 4;
+}
+
+long primitiveSemantics_return_imm_imm_03(long a, long b) {
+  return a != 0 ? 6 : 4;
+}
+
+long primitiveSemantics_return_imm_imm_04(long a, long b) {
+  if (a)
+    b = 4;
+  else
+    b = 6;
+  return b;
+}
+
+long primitiveSemantics_return_imm_imm_05(long a, long b) {
+  if (!a)
+    b = 4;
+  else
+    b = 6;
+  return b;
+}
+
+int primitiveSemantics_return_imm_imm_06(int a, int b) {
+  return a == 0 ? 4 : 6;
+}
+
+int primitiveSemantics_return_imm_imm_07(int a, int b) {
+  return a != 0 ? 4 : 6;
+}
+
+int primitiveSemantics_return_imm_imm_08(int a, int b) {
+  return a == 0 ? 6 : 4;
+}
+
+int primitiveSemantics_return_imm_imm_09(int a, int b) {
+  return a != 0 ? 6 : 4;
+}
+
+int primitiveSemantics_return_imm_imm_10(int a, int b) {
+  if (a)
+    b = 4;
+  else
+    b = 6;
+  return b;
+}
+
+int primitiveSemantics_return_imm_imm_11(int a, int b) {
+  if (!a)
+    b = 4;
+  else
+    b = 6;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
new file mode 100644
index 00000000000..12c351dbc16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_imm_reg_00(long a, long b) {
+  return a == 0 ? 1 : b;
+}
+
+long primitiveSemantics_return_imm_reg_01(long a, long b) {
+  return a != 0 ? 1 : b;
+}
+
+long primitiveSemantics_return_imm_reg_02(long a, long b) {
+  return a == 0 ? b : 1;
+}
+
+long primitiveSemantics_return_imm_reg_03(long a, long b) {
+  return a != 0 ? b : 1;
+}
+
+long primitiveSemantics_return_imm_reg_04(long a, long b) {
+  if (a)
+    b = 1;
+  return b;
+}
+
+long primitiveSemantics_return_imm_reg_05(long a, long b) {
+  if (!a)
+    b = 1;
+  return b;
+}
+
+int primitiveSemantics_return_imm_reg_06(int a, int b) {
+  return a == 0 ? 1 : b;
+}
+
+int primitiveSemantics_return_imm_reg_07(int a, int b) {
+  return a != 0 ? 1 : b;
+}
+
+int primitiveSemantics_return_imm_reg_08(int a, int b) {
+  return a == 0 ? b : 1;
+}
+
+int primitiveSemantics_return_imm_reg_09(int a, int b) {
+  return a != 0 ? b : 1;
+}
+
+int primitiveSemantics_return_imm_reg_10(int a, int b) {
+  if (a)
+    b = 1;
+  return b;
+}
+
+int primitiveSemantics_return_imm_reg_11(int a, int b) {
+  if (!a)
+    b = 1;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c
new file mode 100644
index 00000000000..4708afa645b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_reg_reg_00(long a, long b, long c) {
+  return a == 0 ? c : b;
+}
+
+long primitiveSemantics_return_reg_reg_01(long a, long b, long c) {
+  return a != 0 ? c : b;
+}
+
+long primitiveSemantics_return_reg_reg_02(long a, long b, long c) {
+  return a == 0 ? b : c;
+}
+
+long primitiveSemantics_return_reg_reg_03(long a, long b, long c) {
+  return a != 0 ? b : c;
+}
+
+long primitiveSemantics_return_reg_reg_04(long a, long b, long c) {
+  if (a)
+    b = c;
+  return b;
+}
+
+long primitiveSemantics_return_reg_reg_05(long a, long b, long c) {
+  if (!a)
+    b = c;
+  return b;
+}
+
+int primitiveSemantics_return_reg_reg_06(int a, int b, int c) {
+  return a == 0 ? c : b;
+}
+
+int primitiveSemantics_return_reg_reg_07(int a, int b, int c) {
+  return a != 0 ? c : b;
+}
+
+int primitiveSemantics_return_reg_reg_08(int a, int b, int c) {
+  return a == 0 ? b : c;
+}
+
+int primitiveSemantics_return_reg_reg_09(int a, int b, int c) {
+  return a != 0 ? b : c;
+}
+
+int primitiveSemantics_return_reg_reg_10(int a, int b, int c) {
+  if (a)
+    b = c;
+  return b;
+}
+
+int primitiveSemantics_return_reg_reg_11(int a, int b, int c) {
+  if (!a)
+    b = c;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 12 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 12 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
-- 
2.17.1


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

* [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
                   ` (2 preceding siblings ...)
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
@ 2023-07-19 10:11 ` Xiao Zeng
  2023-08-07 17:36   ` Jeff Law
  2023-07-19 10:11 ` [PATCH 5/5] [RISC-V] Generate Zicond instruction for conditional execution Xiao Zeng
  2023-07-25 17:51 ` [PATCH 0/5] Recognize Zicond extension Jeff Law
  5 siblings, 1 reply; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

This patch completes the recognition of Zicond when the select pattern with
condition eq or neq to non-zero (using equality as an example), namely:

1 rd = (rs2 == non-imm) ? 0 : rs1
2 rd = (rs2 == reg) ? 0 : rs1

At the same time, more Zicond non basic semantic test cases have been added.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize Zicond.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 16 ++++
 .../zicond-primitiveSemantics_compare_imm.c   | 57 ++++++++++++++
 ...mitiveSemantics_compare_imm_return_0_imm.c | 73 ++++++++++++++++++
 ...tiveSemantics_compare_imm_return_imm_imm.c | 73 ++++++++++++++++++
 ...tiveSemantics_compare_imm_return_imm_reg.c | 65 ++++++++++++++++
 ...tiveSemantics_compare_imm_return_reg_reg.c | 65 ++++++++++++++++
 .../zicond-primitiveSemantics_compare_reg.c   | 65 ++++++++++++++++
 ...mitiveSemantics_compare_reg_return_0_imm.c | 73 ++++++++++++++++++
 ...tiveSemantics_compare_reg_return_imm_imm.c | 73 ++++++++++++++++++
 ...tiveSemantics_compare_reg_return_imm_reg.c | 65 ++++++++++++++++
 ...tiveSemantics_compare_reg_return_reg_reg.c | 77 +++++++++++++++++++
 11 files changed, 702 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 7e6b24bd232..9450457e613 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3625,6 +3625,22 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
           riscv_emit_binary(IOR, dest, reg1, reg2);
           return true;
         }
+      /* For complex semantics of comparison value.
+         reg + 0 or 0 + reg  */
+      else if ((GET_CODE (cons) == REG &&
+	        GET_CODE (alt) == CONST_INT &&
+                alt == const0_rtx)
+               || (GET_CODE (alt) == REG &&
+                   GET_CODE (cons) == CONST_INT &&
+                   cons == const0_rtx))
+        {
+          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
+          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+          emit_insn (gen_rtx_SET (dest,
+                                  gen_rtx_IF_THEN_ELSE (mode, cond,
+                                                        cons, alt)));
+          return true;
+        }
     }
 
   return false;
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c
new file mode 100644
index 00000000000..6de50039c31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0"} } */
+
+long primitiveSemantics_compare_imm_00(long a, long b) {
+  return a == 2 ? 0 : b;
+}
+
+long primitiveSemantics_compare_imm_01(long a, long b) {
+  return a != 2 ? 0 : b;
+}
+
+long primitiveSemantics_compare_imm_02(long a, long b) {
+  return a == 2 ? b : 0;
+}
+
+long primitiveSemantics_compare_imm_03(long a, long b) {
+  return a != 2 ? b : 0;
+}
+
+long primitiveSemantics_compare_imm_04(long a, long b) {
+  if (a == 2)
+    b = 0;
+  return b;
+}
+
+long primitiveSemantics_compare_imm_05(long a, long b) {
+  if (!(a == 2))
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_06(int a, int b) { return a == 2 ? 0 : b; }
+
+int primitiveSemantics_compare_imm_07(int a, int b) { return a != 2 ? 0 : b; }
+
+int primitiveSemantics_compare_imm_08(int a, int b) { return a == 2 ? b : 0; }
+
+int primitiveSemantics_compare_imm_09(int a, int b) { return a != 2 ? b : 0; }
+
+int primitiveSemantics_compare_imm_10(int a, int b) {
+  if ((a == 2))
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_11(int a, int b) {
+  if (!(a == 2))
+    b = 0;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c
new file mode 100644
index 00000000000..b1e7359e802
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_0_imm.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_imm_return_0_imm_00(long a, long b) {
+  return a == 2 ? 0 : 5;
+}
+
+long primitiveSemantics_compare_imm_return_0_imm_01(long a, long b) {
+  return a != 2 ? 0 : 5;
+}
+
+long primitiveSemantics_compare_imm_return_0_imm_02(long a, long b) {
+  return a == 2 ? 5 : 0;
+}
+
+long primitiveSemantics_compare_imm_return_0_imm_03(long a, long b) {
+  return a != 2 ? 5 : 0;
+}
+
+long primitiveSemantics_compare_imm_return_0_imm_04(long a, long b) {
+  if (a == 2)
+    b = 0;
+  else
+    b = 5;
+  return b;
+}
+
+long primitiveSemantics_compare_imm_return_0_imm_05(long a, long b) {
+  if (!(a == 2))
+    b = 0;
+  else
+    b = 5;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_06(int a, int b) {
+  return a == 2 ? 0 : 5;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_07(int a, int b) {
+  return a != 2 ? 0 : 5;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_08(int a, int b) {
+  return a == 2 ? 5 : 0;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_09(int a, int b) {
+  return a != 2 ? 5 : 0;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_10(int a, int b) {
+  if ((a == 2))
+    b = 0;
+  else
+    b = 5;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_0_imm_11(int a, int b) {
+  if (!(a == 2))
+    b = 0;
+  else
+    b = 5;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c
new file mode 100644
index 00000000000..bc503e6eafb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_imm.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_imm_return_imm_imm_00(long a, long b) {
+  return a == 2 ? 7 : 4;
+}
+
+long primitiveSemantics_compare_imm_return_imm_imm_01(long a, long b) {
+  return a != 2 ? 7 : 4;
+}
+
+long primitiveSemantics_compare_imm_return_imm_imm_02(long a, long b) {
+  return a == 2 ? 7 : 4;
+}
+
+long primitiveSemantics_compare_imm_return_imm_imm_03(long a, long b) {
+  return a != 2 ? 7 : 4;
+}
+
+long primitiveSemantics_compare_imm_return_imm_imm_04(long a, long b) {
+  if (a == 2)
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+long primitiveSemantics_compare_imm_return_imm_imm_05(long a, long b) {
+  if (!(a == 2))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_06(int a, int b) {
+  return a == 2 ? 7 : 4;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_07(int a, int b) {
+  return a != 2 ? 7 : 4;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_08(int a, int b) {
+  return a == 2 ? 7 : 4;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_09(int a, int b) {
+  return a != 2 ? 7 : 4;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_10(int a, int b) {
+  if ((a == 2))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_imm_11(int a, int b) {
+  if (!(a == 2))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c
new file mode 100644
index 00000000000..2bcad7a51d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_imm_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_imm_return_imm_reg_00(long a, long b) {
+  return a == 2 ? 3 : b;
+}
+
+long primitiveSemantics_compare_imm_return_imm_reg_01(long a, long b) {
+  return a != 2 ? 3 : b;
+}
+
+long primitiveSemantics_compare_imm_return_imm_reg_02(long a, long b) {
+  return a == 2 ? b : 3;
+}
+
+long primitiveSemantics_compare_imm_return_imm_reg_03(long a, long b) {
+  return a != 2 ? b : 3;
+}
+
+long primitiveSemantics_compare_imm_return_imm_reg_04(long a, long b) {
+  if (a == 2)
+    b = 3;
+  return b;
+}
+
+long primitiveSemantics_compare_imm_return_imm_reg_05(long a, long b) {
+  if (!(a == 2))
+    b = 3;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_06(int a, int b) {
+  return a == 2 ? 3 : b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_07(int a, int b) {
+  return a != 2 ? 3 : b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_08(int a, int b) {
+  return a == 2 ? b : 3;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_09(int a, int b) {
+  return a != 2 ? b : 3;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_10(int a, int b) {
+  if ((a == 2))
+    b = 3;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_imm_reg_11(int a, int b) {
+  if (!(a == 2))
+    b = 3;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c
new file mode 100644
index 00000000000..e5d12992dc7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_imm_return_reg_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_imm_return_reg_reg_00(long a, long b, long c) {
+  return a == 2 ? c : b;
+}
+
+long primitiveSemantics_compare_imm_return_reg_reg_01(long a, long b, long c) {
+  return a != 2 ? c : b;
+}
+
+long primitiveSemantics_compare_imm_return_reg_reg_02(long a, long b, long c) {
+  return a == 2 ? b : c;
+}
+
+long primitiveSemantics_compare_imm_return_reg_reg_03(long a, long b, long c) {
+  return a != 2 ? b : c;
+}
+
+long primitiveSemantics_compare_imm_return_reg_reg_04(long a, long b, long c) {
+  if (a == 2)
+    b = c;
+  return b;
+}
+
+long primitiveSemantics_compare_imm_return_reg_reg_05(long a, long b, long c) {
+  if (!(a == 2))
+    b = c;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_06(int a, int b, int c) {
+  return a == 2 ? c : b;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_07(int a, int b, int c) {
+  return a != 2 ? c : b;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_08(int a, int b, int c) {
+  return a == 2 ? b : c;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_09(int a, int b, int c) {
+  return a != 2 ? b : c;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_10(int a, int b, int c) {
+  if ((a == 2))
+    b = c;
+  return b;
+}
+
+int primitiveSemantics_compare_imm_return_reg_reg_11(int a, int b, int c) {
+  if (!(a == 2))
+    b = c;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 12 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 12 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c
new file mode 100644
index 00000000000..072ae2a26ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0"} } */
+
+long primitiveSemantics_compare_reg_00(long a, long b, long c) {
+  return a == c ? 0 : b;
+}
+
+long primitiveSemantics_compare_reg_01(long a, long b, long c) {
+  return a != c ? 0 : b;
+}
+
+long primitiveSemantics_compare_reg_02(long a, long b, long c) {
+  return a == c ? b : 0;
+}
+
+long primitiveSemantics_compare_reg_03(long a, long b, long c) {
+  return a != c ? b : 0;
+}
+
+long primitiveSemantics_compare_reg_04(long a, long b, long c) {
+  if (a == c)
+    b = 0;
+  return b;
+}
+
+long primitiveSemantics_compare_reg_05(long a, long b, long c) {
+  if (!(a == c))
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_06(int a, int b, int c) {
+  return a == c ? 0 : b;
+}
+
+int primitiveSemantics_compare_reg_07(int a, int b, int c) {
+  return a != c ? 0 : b;
+}
+
+int primitiveSemantics_compare_reg_08(int a, int b, int c) {
+  return a == c ? b : 0;
+}
+
+int primitiveSemantics_compare_reg_09(int a, int b, int c) {
+  return a != c ? b : 0;
+}
+
+int primitiveSemantics_compare_reg_10(int a, int b, int c) {
+  if ((a == c))
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_11(int a, int b, int c) {
+  if (!(a == c))
+    b = 0;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c
new file mode 100644
index 00000000000..66c7bcb9067
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_0_imm.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_reg_return_0_imm_00(long a, long b, long c) {
+  return a == c ? 0 : 9;
+}
+
+long primitiveSemantics_compare_reg_return_0_imm_01(long a, long b, long c) {
+  return a != c ? 0 : 9;
+}
+
+long primitiveSemantics_compare_reg_return_0_imm_02(long a, long b, long c) {
+  return a == c ? 9 : 0;
+}
+
+long primitiveSemantics_compare_reg_return_0_imm_03(long a, long b, long c) {
+  return a != c ? 9 : 0;
+}
+
+long primitiveSemantics_compare_reg_return_0_imm_04(long a, long b, long c) {
+  if (a == c)
+    b = 0;
+  else
+    b = 9;
+  return b;
+}
+
+long primitiveSemantics_compare_reg_return_0_imm_05(long a, long b, long c) {
+  if (!(a == c))
+    b = 0;
+  else
+    b = 9;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_06(int a, int b, int c) {
+  return a == c ? 0 : 9;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_07(int a, int b, int c) {
+  return a != c ? 0 : 9;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_08(int a, int b, int c) {
+  return a == c ? 9 : 0;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_09(int a, int b, int c) {
+  return a != c ? 9 : 0;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_10(int a, int b, int c) {
+  if ((a == c))
+    b = 0;
+  else
+    b = 9;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_0_imm_11(int a, int b, int c) {
+  if (!(a == c))
+    b = 0;
+  else
+    b = 9;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c
new file mode 100644
index 00000000000..055ca4833e9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_imm.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_reg_return_imm_imm_00(long a, long b, long c) {
+  return a == c ? 7 : 4;
+}
+
+long primitiveSemantics_compare_reg_return_imm_imm_01(long a, long b, long c) {
+  return a != c ? 7 : 4;
+}
+
+long primitiveSemantics_compare_reg_return_imm_imm_02(long a, long b, long c) {
+  return a == c ? 7 : 4;
+}
+
+long primitiveSemantics_compare_reg_return_imm_imm_03(long a, long b, long c) {
+  return a != c ? 7 : 4;
+}
+
+long primitiveSemantics_compare_reg_return_imm_imm_04(long a, long b, long c) {
+  if (a == c)
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+long primitiveSemantics_compare_reg_return_imm_imm_05(long a, long b, long c) {
+  if (!(a == c))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_06(int a, int b, int c) {
+  return a == c ? 7 : 4;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_07(int a, int b, int c) {
+  return a != c ? 7 : 4;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_08(int a, int b, int c) {
+  return a == c ? 7 : 4;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_09(int a, int b, int c) {
+  return a != c ? 7 : 4;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_10(int a, int b, int c) {
+  if ((a == c))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_imm_11(int a, int b, int c) {
+  if (!(a == c))
+    b = 7;
+  else
+    b = 4;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c
new file mode 100644
index 00000000000..85a68bd946f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_imm_reg.c
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_reg_return_imm_reg_00(long a, long b, long c) {
+  return a == c ? 10 : b;
+}
+
+long primitiveSemantics_compare_reg_return_imm_reg_01(long a, long b, long c) {
+  return a != c ? 10 : b;
+}
+
+long primitiveSemantics_compare_reg_return_imm_reg_02(long a, long b, long c) {
+  return a == c ? b : 10;
+}
+
+long primitiveSemantics_compare_reg_return_imm_reg_03(long a, long b, long c) {
+  return a != c ? b : 10;
+}
+
+long primitiveSemantics_compare_reg_return_imm_reg_04(long a, long b, long c) {
+  if (a == c)
+    b = 10;
+  return b;
+}
+
+long primitiveSemantics_compare_reg_return_imm_reg_05(long a, long b, long c) {
+  if (!(a == c))
+    b = 10;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_06(int a, int b, int c) {
+  return a == c ? 10 : b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_07(int a, int b, int c) {
+  return a != c ? 10 : b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_08(int a, int b, int c) {
+  return a == c ? b : 10;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_09(int a, int b, int c) {
+  return a != c ? b : 10;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_10(int a, int b, int c) {
+  if ((a == c))
+    b = 10;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_imm_reg_11(int a, int b, int c) {
+  if (!(a == c))
+    b = 10;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c
new file mode 100644
index 00000000000..d6d5d9e7bfa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_compare_reg_return_reg_reg.c
@@ -0,0 +1,77 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_compare_reg_return_reg_reg_00(long a, long b, long c,
+                                                      long d) {
+  return a == c ? d : b;
+}
+
+long primitiveSemantics_compare_reg_return_reg_reg_01(long a, long b, long c,
+                                                      long d) {
+  return a != c ? d : b;
+}
+
+long primitiveSemantics_compare_reg_return_reg_reg_02(long a, long b, long c,
+                                                      long d) {
+  return a == c ? b : d;
+}
+
+long primitiveSemantics_compare_reg_return_reg_reg_03(long a, long b, long c,
+                                                      long d) {
+  return a != c ? b : d;
+}
+
+long primitiveSemantics_compare_reg_return_reg_reg_04(long a, long b, long c,
+                                                      long d) {
+  if (a == c)
+    b = d;
+  return b;
+}
+
+long primitiveSemantics_compare_reg_return_reg_reg_05(long a, long b, long c,
+                                                      long d) {
+  if (!(a == c))
+    b = d;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_06(int a, int b, int c,
+                                                     int d) {
+  return a == c ? d : b;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_07(int a, int b, int c,
+                                                     int d) {
+  return a != c ? d : b;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_08(int a, int b, int c,
+                                                     int d) {
+  return a == c ? b : d;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_09(int a, int b, int c,
+                                                     int d) {
+  return a != c ? b : d;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_10(int a, int b, int c,
+                                                     int d) {
+  if ((a == c))
+    b = d;
+  return b;
+}
+
+int primitiveSemantics_compare_reg_return_reg_reg_11(int a, int b, int c,
+                                                     int d) {
+  if (!(a == c))
+    b = d;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 12 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 12 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
-- 
2.17.1


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

* [PATCH 5/5] [RISC-V] Generate Zicond instruction for conditional execution
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
                   ` (3 preceding siblings ...)
  2023-07-19 10:11 ` [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero Xiao Zeng
@ 2023-07-19 10:11 ` Xiao Zeng
  2023-07-25 17:51 ` [PATCH 0/5] Recognize Zicond extension Jeff Law
  5 siblings, 0 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-19 10:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Xiao Zeng

This patch completes the recognition of conditional execution
(using equality as an example), namely:

1 rd = (rc == 0) ? (rs1 arith_op rs2) : rs1

Here, arith_op represents the arithmetic operation symbol, which has 8
possibilities: + - | ^ << >>(Shift Right Arithmetic) >>(Shift Right Logical) &

At the same time, more Zicond non basic conditional execution test cases have
also been added, namely:

2 rd = (rc == 0) ? (rs1 arith_op non-imm) : rs1
3 rd = (rc == non-imm) ? (rs1 arith_op rs2) : rs1
4 rd = (rc == non-imm) ? (rs1 arith_op non-imm) : rs1
5 rd = (rc == reg) ? (rs1 arith_op rs2) : rs1
6 rd = (rc == reg) ? (rs1 arith_op non-imm) : rs1

gcc/ChangeLog:

	* ifcvt.cc (noce_emit_condzero_arith): Helper function for noce_emit_condzero_arith.
	(noce_try_condzero_arith): Recognize Zicond patterns.
	(noce_process_if_block): Add noce_try_condzero_arith function.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c: New test.
	* gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c: New test.
	* gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c: New test.
	* gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c: New test.
---
 gcc/ifcvt.cc                                  | 251 ++++++++
 ...ionalArithmetic_compare_0_return_imm_reg.c | 553 +++++++++++++++++
 ...ionalArithmetic_compare_0_return_reg_reg.c | 585 ++++++++++++++++++
 ...nalArithmetic_compare_imm_return_imm_reg.c | 297 +++++++++
 ...nalArithmetic_compare_imm_return_reg_reg.c | 297 +++++++++
 ...nalArithmetic_compare_reg_return_imm_reg.c | 297 +++++++++
 ...nalArithmetic_compare_reg_return_reg_reg.c | 329 ++++++++++
 7 files changed, 2609 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 0b180b4568f..0261d2f1673 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -781,12 +781,15 @@ static int noce_try_store_flag_constants (struct noce_if_info *);
 static int noce_try_store_flag_mask (struct noce_if_info *);
 static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
 			    rtx, rtx, rtx, rtx = NULL, rtx = NULL);
+static rtx noce_emit_condzero_arith (struct noce_if_info *, rtx, enum rtx_code, rtx,
+                                     rtx, rtx, rtx);
 static int noce_try_cmove (struct noce_if_info *);
 static int noce_try_cmove_arith (struct noce_if_info *);
 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 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.  */
@@ -1830,6 +1833,60 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
     return NULL_RTX;
 }
 
+/* Helper function for noce_emit_condzero_arith.  */
+
+static rtx
+noce_emit_condzero_arith (struct noce_if_info *if_info, rtx x, enum rtx_code code,
+                          rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
+{
+  rtx cond = NULL;
+
+  /* Standard form of conditional comparison.  */
+  if (GET_CODE(cmp_a) == REG && cmp_b == const0_rtx)
+    cond = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
+
+  /* Register and non-zero immediate comparison.  */
+  else if (GET_CODE(cmp_a) == REG && GET_CODE(cmp_b) == CONST_INT &&
+           cmp_b != const0_rtx)
+    {
+      rtx temp1 = gen_reg_rtx (GET_MODE(cmp_a));
+      rtx temp2 = GEN_INT(-1 * INTVAL (cmp_b));
+      rtx src = gen_rtx_fmt_ee (PLUS, GET_MODE (cmp_a), cmp_a, temp2);
+      emit_insn (gen_rtx_SET (temp1, src));
+      cond = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), temp1, const0_rtx);
+    }
+
+  /* Register and Register comparison.  */
+  else if (GET_CODE(cmp_a) == REG && GET_CODE(cmp_b) == REG)
+    {
+      rtx temp1 = gen_reg_rtx (GET_MODE(cmp_a));
+      rtx src = gen_rtx_fmt_ee (MINUS, GET_MODE (cmp_a), cmp_a, cmp_b);
+      emit_insn (gen_rtx_SET (temp1, src));
+      cond = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), temp1, const0_rtx);
+    }
+  else
+    return NULL_RTX;
+
+  rtx if_then_else = gen_rtx_IF_THEN_ELSE (GET_MODE (x), cond, vtrue, vfalse);
+  rtx set = gen_rtx_SET (x, if_then_else);
+
+  start_sequence ();
+  rtx_insn *insn = emit_insn (set);
+
+  if (recog_memoized (insn) >= 0)
+    {
+      rtx_insn *seq = get_insns ();
+      end_sequence ();
+      emit_insn (seq);
+
+      return x;
+    }
+
+  end_sequence ();
+
+  return NULL_RTX;
+}
+
 /* Try only simple constants and registers here.  More complex cases
    are handled in noce_try_cmove_arith after noce_try_store_flag_arith
    has had a go at it.  */
@@ -2879,6 +2936,197 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   return TRUE;
 }
 
+/* Convert "if (cond) x = x arith_code y; return x;" 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 first_pattern = NULL;
+  rtx last_pattern = NULL;
+  rtx else_pattern = NULL;
+  rtx *arith, *ref_arith_op0, *ref_arith_op1;
+  rtx arith_op0, arith_op1;
+  rtx_code arith_code;
+  rtx_code cond_code = GET_CODE (if_info->cond);
+
+  machine_mode arith_mode = GET_MODE (if_info->a);
+  machine_mode cmp_mode = GET_MODE (XEXP(if_info->cond, 0));
+  if (GET_MODE_CLASS (arith_mode) != MODE_INT ||
+      GET_MODE_CLASS (cmp_mode) != MODE_INT)
+    return FALSE;
+
+  /* we shall create new pseudos.  */
+  if (reload_completed)
+    return FALSE;
+
+  /* Check for cond_code.  */
+  if (cond_code != EQ && cond_code != NE)
+    return FALSE;
+
+  /* Check for else_bb.  */
+  if (if_info->else_bb &&
+      !(count_bb_insns(if_info->else_bb) == 1 &&
+        !JUMP_P (BB_END (if_info->then_bb)) &&
+        (else_pattern = single_set (first_active_insn (if_info->else_bb))) &&
+        GET_CODE (else_pattern) == SET &&
+        rtx_equal_p (if_info->x, XEXP(else_pattern, 0))))
+    return FALSE;
+
+  /* count_bb_insns ignores JUMP_INSN.  */
+  if (JUMP_P (BB_END (if_info->then_bb)))
+    return FALSE;
+
+  if (count_bb_insns(if_info->then_bb) > 2)
+    return FALSE;
+
+  /* Optimize for sign-extension.  */
+  if (count_bb_insns(if_info->then_bb) == 2)
+    {
+      last_pattern = copy_rtx (PATTERN (last_active_insn (if_info->then_bb,
+                                                          FALSE)));
+      /* Just processing SET insn, not including other situations
+         in the single_set function.  */
+      if (GET_CODE (last_pattern) != SET)
+        return FALSE;
+
+      rtx_code last_code = GET_CODE (XEXP (last_pattern, 1));
+
+      if (last_code != SIGN_EXTEND && last_code != REG)
+        return FALSE;
+    }
+
+  first_pattern = copy_rtx (PATTERN (first_active_insn (if_info->then_bb)));
+  if (GET_CODE (first_pattern) != SET)
+    return FALSE;
+
+  arith = &XEXP (first_pattern, 1);
+  arith_code = GET_CODE (*arith);
+
+  if (arith_code == SIGN_EXTEND)
+    {
+      arith = &XEXP (*arith, 0);
+      arith_code = GET_CODE (*arith);
+    }
+  /* When shift right logical a non-zero immediate to unsigned integer,
+     zero_extend and sign_extend are equal.
+     In risc-v, using zero_extend to represent shift right logical is
+     a non-canonical form, as shown in riscv.md.  */
+  else if (arith_code == ZERO_EXTEND)
+    {
+      rtx *temp = arith;
+      arith = &XEXP (*arith, 0);
+      arith_code = GET_CODE (*arith);
+      if (arith_code != LSHIFTRT)
+        return FALSE;
+      /* Modify the code to sign_extend for easy subsequent recognition.  */
+      PUT_CODE(*temp, SIGN_EXTEND);
+    }
+
+  if (arith_code != PLUS && arith_code != MINUS && arith_code != IOR &&
+      arith_code != XOR && arith_code != AND && arith_code != ASHIFTRT &&
+      arith_code != LSHIFTRT && arith_code != ASHIFT)
+    return FALSE;
+
+  /* Obtain the arithmetic calculation components: arith_op0 and arith_op1.  */
+  arith_op0 = XEXP (*arith, 0);
+  arith_op1 = XEXP (*arith, 1);
+  ref_arith_op0 = &XEXP (*arith, 0);
+  ref_arith_op1 = &XEXP (*arith, 1);
+
+  if (GET_CODE (arith_op0) == SUBREG)
+    arith_op0 = SUBREG_REG(arith_op0);
+  if (GET_CODE (arith_op1) == SUBREG)
+    arith_op1 = SUBREG_REG(arith_op1);
+
+  /* The arithmetic calculation pattern that can only be processed
+     in insn pattern are as follows:
+     (set (reg/v:DI 137 [ rs1 ])
+        (ashiftrt:DI (reg/v:DI 137 [ rs1 ])
+            (subreg:QI (reg/v:DI 138 [ rs2 ]) 0)))  */
+  if (!else_pattern && !rtx_equal_p (if_info->x, arith_op0))
+    return FALSE;
+
+  /* If else_bb is not empty.  */
+  if (else_pattern && !rtx_equal_p (if_info->x, XEXP(first_pattern, 0)) &&
+      !rtx_equal_p (arith_op0, XEXP(else_pattern, 1)))
+    return FALSE;
+
+  start_sequence ();
+
+  if (arith_code == AND)
+    {
+      rtx reg1 = gen_reg_rtx (arith_mode);
+      rtx temp = gen_rtx_fmt_ee (arith_code, arith_mode, arith_op0, arith_op1);
+      emit_insn (gen_rtx_SET (reg1, temp));
+
+      rtx reg2 = gen_reg_rtx (arith_mode);
+      target = noce_emit_condzero_arith (if_info, reg2, cond_code,
+                                         XEXP (if_info->cond, 0),
+                                         XEXP (if_info->cond, 1),
+                                         const0_rtx, arith_op0);
+      if (!target)
+        {
+          end_sequence ();
+          return FALSE;
+        }
+      rtx ior = gen_rtx_fmt_ee (IOR, arith_mode, reg1, target);
+      emit_insn (gen_rtx_SET (if_info->x, ior));
+    }
+  else
+    {
+      /* In CONST_INT case, force arith_op1 to register.  */
+      if (GET_CODE(arith_op1) == CONST_INT)
+        {
+          rtx reg = gen_reg_rtx (arith_mode);
+          emit_insn (gen_rtx_SET (reg, arith_op1));
+          arith_op1 = reg;
+        }
+
+      /* Apply for a reg as the return register for condezero.  */
+      rtx reg = gen_reg_rtx (arith_mode);
+      target = noce_emit_condzero_arith (if_info, reg, cond_code,
+                                         XEXP (if_info->cond, 0),
+                                         XEXP (if_info->cond, 1),
+                                         arith_op1, const0_rtx);
+      if (!target)
+        {
+          end_sequence ();
+          return FALSE;
+        }
+
+      /* Update arithmetic operand in first_pattern.  */
+
+      /* Shift a register.  */
+      if (arith_code == ASHIFT || arith_code == ASHIFTRT ||
+          arith_code == LSHIFTRT)
+        *ref_arith_op1 = gen_rtx_SUBREG (E_QImode, target, 0);
+      else if (GET_CODE (*ref_arith_op0) == SUBREG)
+        *ref_arith_op1 = gen_rtx_SUBREG (GET_MODE (*ref_arith_op0), target, 0);
+      else
+	*ref_arith_op1 = target;
+
+      emit_insn (first_pattern);
+
+      /* Adding last_pattern to the insn chain.  */
+      if (last_pattern)
+        emit_insn (last_pattern);
+    }
+
+  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;
+}
 
 /* Optimize away "if (x & C) x |= C" and similar bit manipulation
    transformations.  */
@@ -3973,6 +4221,9 @@ noce_process_if_block (struct noce_if_info *if_info)
 	goto success;
       if (noce_try_store_flag_mask (if_info))
 	goto success;
+      if (HAVE_conditional_move
+          && 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-conditionalArithmetic_compare_0_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_imm_reg.c
new file mode 100644
index 00000000000..282e8a8e492
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_imm_reg.c
@@ -0,0 +1,553 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_0_return_imm_reg_00(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_01(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_02(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_03(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_04(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_05(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_06(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_07(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_08(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_09(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_10(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_11(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_12(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_13(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_14(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_15(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_16(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_17(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_18(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_19(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_20(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_21(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_22(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_23(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_24(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_25(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_26(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_27(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_28(long rd, long rs1,
+                                                       long rc) {
+  if (rc == 0)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_29(long rd, long rs1,
+                                                       long rc) {
+  if (rc != 0)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_30(long rd, long rs1,
+                                                       long rc) {
+  if (rc)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_imm_reg_31(long rd, long rs1,
+                                                       long rc) {
+  if (!rc)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_32(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_33(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_34(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_35(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_36(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_37(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_38(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_39(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_40(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_41(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_42(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_43(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_44(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_45(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_46(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_47(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_48(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_49(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_50(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_51(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_52(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_53(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_54(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_55(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_56(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_57(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_58(int rd, int rs1, int rc) {
+  if (rc)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_59(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_60(int rd, int rs1, int rc) {
+  if (rc == 0)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_61(int rd, int rs1, int rc) {
+  if (rc != 0)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_62(int rd, int rs1, int rc) {
+  if (rc)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_imm_reg_63(int rd, int rs1, int rc) {
+  if (!rc)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 32 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 32 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c
new file mode 100644
index 00000000000..15efcf538e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_0_return_reg_reg.c
@@ -0,0 +1,585 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_0_return_reg_reg_00(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_01(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_02(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_03(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_04(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_05(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_06(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_07(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_08(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_09(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_10(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_11(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_12(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_13(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_14(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_15(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_16(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_17(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_18(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_19(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_20(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_21(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_22(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_23(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_24(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_25(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_26(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_27(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_28(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc == 0)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_29(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc != 0)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_30(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (rc)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_0_return_reg_reg_31(long rd, long rs1,
+                                                       long rs2, long rc) {
+  if (!rc)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_32(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_33(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_34(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_35(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_36(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_37(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_38(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_39(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_40(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_41(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_42(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_43(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_44(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_45(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_46(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_47(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_48(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_49(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_50(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_51(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_52(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_53(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_54(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_55(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_56(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_57(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_58(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_59(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_60(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc == 0)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_61(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc != 0)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_62(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (rc)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_0_return_reg_reg_63(int rd, int rs1, int rs2,
+                                                      int rc) {
+  if (!rc)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 32 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 32 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c
new file mode 100644
index 00000000000..6647640acf8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_imm_reg.c
@@ -0,0 +1,297 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_imm_return_imm_reg_00(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_01(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_02(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_03(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_04(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_05(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_06(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_07(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_08(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_09(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_10(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_11(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_12(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_13(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_14(long rd, long rs1,
+                                                         long rc) {
+  if (rc == 10)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_imm_reg_15(long rd, long rs1,
+                                                         long rc) {
+  if (rc != 10)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_16(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_17(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_18(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_19(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_20(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_21(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_22(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_23(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_24(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_25(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_26(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_27(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_28(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_29(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_30(int rd, int rs1,
+                                                        int rc) {
+  if (rc == 10)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_imm_reg_31(int rd, int rs1,
+                                                        int rc) {
+  if (rc != 10)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 16 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 16 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c
new file mode 100644
index 00000000000..859639c1676
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_imm_return_reg_reg.c
@@ -0,0 +1,297 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_imm_return_reg_reg_00(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_01(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_02(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_03(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_04(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_05(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_06(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_07(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_08(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_09(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_10(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_11(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_12(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_13(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_14(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc == 10)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_imm_return_reg_reg_15(long rd, long rs1,
+                                                         long rs2, long rc) {
+  if (rc != 10)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_16(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_17(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_18(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_19(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_20(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_21(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_22(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_23(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_24(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_25(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_26(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_27(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_28(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_29(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_30(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc == 10)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_imm_return_reg_reg_31(int rd, int rs1,
+                                                        int rs2, int rc) {
+  if (rc != 10)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 16 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 16 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c
new file mode 100644
index 00000000000..7affe1d9baa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_imm_reg.c
@@ -0,0 +1,297 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_reg_return_imm_reg_00(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_01(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_02(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_03(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_04(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_05(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_06(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_07(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_08(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_09(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_10(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_11(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_12(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_13(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = ((unsigned long)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_14(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_imm_reg_15(long rd, long rs1,
+                                                         long rc1, long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_16(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_17(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 + 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_18(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_19(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 - 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_20(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_21(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 | 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_22(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_23(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 ^ 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_24(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_25(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 << 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_26(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_27(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_28(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_29(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = ((unsigned int)rs1) >> 2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_30(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_imm_reg_31(int rd, int rs1,
+                                                        int rc1, int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 & 20;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 16 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 16 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c
new file mode 100644
index 00000000000..8b0959e534b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-conditionalArithmetic_compare_reg_return_reg_reg.c
@@ -0,0 +1,329 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os"} } */
+
+long conditionalArithmetic_compare_reg_return_reg_reg_00(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_01(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_02(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_03(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_04(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_05(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_06(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_07(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_08(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_09(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_10(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_11(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_12(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_13(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = ((unsigned long)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_14(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 == rc2)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+long conditionalArithmetic_compare_reg_return_reg_reg_15(long rd, long rs1,
+                                                         long rs2, long rc1,
+                                                         long rc2) {
+  if (rc1 != rc2)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_16(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_17(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 + rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_18(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_19(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 - rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_20(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_21(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 | rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_22(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_23(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 ^ rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_24(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_25(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 << rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_26(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_27(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_28(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_29(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = ((unsigned int)rs1) >> rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_30(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 == rc2)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+int conditionalArithmetic_compare_reg_return_reg_reg_31(int rd, int rs1,
+                                                        int rs2, int rc1,
+                                                        int rc2) {
+  if (rc1 != rc2)
+    rd = rs1 & rs2;
+  else
+    rd = rs1;
+  return rd;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 16 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 16 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
-- 
2.17.1


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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
@ 2023-07-25 16:35   ` Jeff Law
  2023-07-26 17:53   ` Jeff Law
  2023-07-26 21:14   ` Jeff Law
  2 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-07-25 16:35 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of the basic semantics
> defined in the spec, namely:
> 
> Conditional zero, if condition is equal to zero
>    rd = (rs2 == 0) ? 0 : rs1
> Conditional zero, if condition is non zero
>    rd = (rs2 != 0) ? 0 : rs1
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.md: Include zicond.md
> 	* config/riscv/zicond.md: New file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-primitiveSemantics.c: New test.
> ---
>   gcc/config/riscv/riscv.md                     |  1 +
>   gcc/config/riscv/zicond.md                    | 84 +++++++++++++++++++
>   .../riscv/zicond-primitiveSemantics.c         | 49 +++++++++++
>   3 files changed, 134 insertions(+)
>   create mode 100644 gcc/config/riscv/zicond.md
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
> 
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index d63b584a4c1..6b8c2e8e268 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -3317,3 +3317,4 @@
>   (include "sifive-7.md")
>   (include "thead.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..1cf28589c87
> --- /dev/null
> +++ b/gcc/config/riscv/zicond.md
> @@ -0,0 +1,84 @@
> +;; 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_code_attr nez [(eq "eqz") (ne "nez")])
> +
> +
> +;; Special optimization under eq/ne in primitive semantics
> +(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt1"
> +  [(set (match_operand:GPR 0 "register_operand"                   "=r")
> +        (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
> +                              (const_int 0))
> +                          (match_operand:GPR 2 "register_operand" "1")
> +                          (match_operand:GPR 3 "register_operand" "r")))]
> +  "TARGET_ZICOND && operands[1] == operands[2]"
> +  "czero.eqz\t%0,%3,%1"
Interesting.  We didn't have this pattern internally, though it's 
clever.  I'm curious how often it triggered.

Why did you need the operands[1] == operands[2] condition.   I would 
hazard a guess the idea was to reject cases that weren't going to be 
profitable if LRA/reload needed to insert copies to satisfy the matching 
constraint?

It may have been better to replace operand 2 with (match_dup 1).  If 
that isn't viable, then the right check in the condition would have been
REGNO (operands[1]) == REGNO (operands[2]).

You need to be very careful comparing REG expressions for equality like 
you did.  It probably works in this case, but it's pretty fragile in 
general.  The problem while you can compare two pseudos using pointer 
equality, you can't necessarily do that for hard registers.

What happens under the hood is you can have two distinct pseudos which 
get allocated to the same hard reg.  At assignment time we just replace 
the underlying register # without going back and fixing all the REG 
expressions.  Meaning that you can have:


(reg:XX 12) and (reg:XX 12)

Which are at distinct memory locations.  Meaning that while the RTX 
expresssions look the same, they will fail the pointer equality check.

So again, it probably works on your example, but I'd rather look for 
ways to bullet proof this better.  The (match_dup) approach is probably 
the most preferred.

Similarly for the other 3 patterns that have pointer equality tests for 
two operands in the insn condition.


Jeff

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

* Re: [PATCH 1/5] [RISC-V] Recognize Zicond extension
  2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
@ 2023-07-25 16:35   ` Jeff Law
  2023-07-26 21:11   ` Jeff Law
  1 sibling, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-07-25 16:35 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch is the minimal support for Zicond extension, include
> the extension name, mask and target defination.
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc: New extension.
> 	* config/riscv/riscv-opts.h (MASK_ZICOND): New mask.
> 	(TARGET_ZICOND): New target.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/attribute-20.c: New test.
> 	* gcc.target/riscv/attribute-21.c: New test.
This is OK.  Though I don't think we should install until the follow-on 
patches are ready to go.

jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
@ 2023-07-25 17:32   ` Jeff Law
  2023-07-25 17:55   ` Andreas Schwab
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-07-25 17:32 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of Zicond when the select pattern
> with condition eq or neq to 0 (using equality as an example), namely:
> 
> 1 rd = (rs2 == 0) ? non-imm : 0
> 2 rd = (rs2 == 0) ? non-imm : non-imm
> 3 rd = (rs2 == 0) ? reg : non-imm
> 4 rd = (rs2 == 0) ? reg : reg
> 
> gcc/ChangeLog:
> 
>          * config/riscv/riscv.cc (riscv_rtx_costs): IF_THEN_ELSE costs in Zicond.
>          (riscv_expand_conditional_move): Recognize Zicond.
>          * config/riscv/riscv.md: Zicond patterns.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test.
> 	* gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test.
> 	* gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test.
> 	* gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test.
> ---
>   gcc/config/riscv/riscv.cc                     | 125 ++++++++++++++++++
>   gcc/config/riscv/riscv.md                     |   2 +-
>   .../zicond-primitiveSemantics_return_0_imm.c  |  65 +++++++++
>   ...zicond-primitiveSemantics_return_imm_imm.c |  73 ++++++++++
>   ...zicond-primitiveSemantics_return_imm_reg.c |  65 +++++++++
>   ...zicond-primitiveSemantics_return_reg_reg.c |  65 +++++++++
>   6 files changed, 394 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c
> 
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 38d8eb2fcf5..7e6b24bd232 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>   	  *total = COSTS_N_INSNS (1);
>   	  return true;
>   	}
> +      else if (TARGET_ZICOND && outer_code == SET &&
> +               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
> +               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
> +                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
> +                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))
> +        {
> +          *total = 0;
> +          return true;
> +        }
So why *total = 0.  I would have expected *total = COSTS_N_INSNS (1).


I'm not entirely sure the changes to riscv_expand_conditional_move are 
desirable -- these are likely better done in the generic if-conversion 
pass.


> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 6b8c2e8e268..b4147c7a79c 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -2484,7 +2484,7 @@
>   	(if_then_else:GPR (match_operand 1 "comparison_operator")
>   			  (match_operand:GPR 2 "reg_or_0_operand")
>   			  (match_operand:GPR 3 "sfb_alu_operand")))]
> -  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
> +  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
>   {
>     if (riscv_expand_conditional_move (operands[0], operands[1],
>   				     operands[2], operands[3]))
We had to do more than just slap on a TARGET_ZICOND.  I'm a bit 
surprised this worked as-is.  Though we also have bits to handle 
conditions other than eq/ne by first emitting an sCC style insn which 
might be adding complication or cases you hadn't encountered.


Jeff


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

* Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
                   ` (4 preceding siblings ...)
  2023-07-19 10:11 ` [PATCH 5/5] [RISC-V] Generate Zicond instruction for conditional execution Xiao Zeng
@ 2023-07-25 17:51 ` Jeff Law
  2023-07-27  8:43   ` Xiao Zeng
  5 siblings, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-25 17:51 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> Hi all RISC-V folks:
> 
> This series of patches completes support for the riscv architecture's
> Zicond standard extension instruction set.
> 
> Currently, Zicond is in a frozen state.
> 
> See the Zicond specification for details:
> https://github.com/riscv/riscv-zicond/releases/download/v1.0-rc2/riscv-zicond-v1.0-rc2.pdf
> 
> Prior to this, other community members have also done related work, as shown in:
> https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611767.html
> https://sourceware.org/pipermail/binutils/2023-January/125773.html
> 
> Xiao Zeng (5):
>    [RISC-V] Recognize Zicond extension
>    [RISC-V] Generate Zicond instruction for basic semantics
>    [RISC-V] Generate Zicond instruction for select pattern with condition
>      eq or neq to 0
>    [RISC-V] Generate Zicond instruction for select pattern with condition
>      eq or neq to non-zero
>    [RISC-V] Generate Zicond instruction for conditional execution
[ ... ]
So what I'm thinking for the overall kit is to stage it in a bit 
differently given we have some bits which clearly can go forward as-is 
or with very minor changes and others that are going to need some 
iteration/refinement.

So I'm going to suggest a few changes so that bits which are non 
controversial can move forward immediately.

1/5 looked fine as-is.

I would split 2/5.  The first two patterns you added are 
non-controversial and could go in immediately.  The other 4 patterns 
(which require some operand matching) will likely need at least one 
round of iteration and should be a distinct patch.


I would split 3/5 as well.  3a would be the costing which I think just 
needs to use COSTS_N_INSNS (1) rather than 0 for the cost of a 
conditional move and could then move forward immediately.  The bits to 
wire everything up into the conditional move pattern would be a distinct 
patch.  We did something similar internally in Ventana and I'd like to 
take the time to make sure the issues we ran into are addressed in your 
version then do an evaluation of the two approaches.

I think patch 4 is probably going to need some work too.  I *think* what 
we did internally at Ventana will work better (utilizing scc for a 
non-trivial condition).

Let's defer patch #5 initially as well.  It's going to get tangled up in 
a whole bunch of changes I think we need to make to ifcvt.cc.

The point being that with the bits from #1, #2 and #3 we can get some 
initial support in immediately.  eswincomputing and ventana can both 
reduce our divergence from the trunk and work together on the rest of 
the bits.

Does that work for you?

jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
  2023-07-25 17:32   ` Jeff Law
@ 2023-07-25 17:55   ` Andreas Schwab
  2023-07-27  5:44     ` Xiao Zeng
  2023-07-28 15:09     ` Jeff Law
  2023-07-28 20:59   ` Jeff Law
  2023-08-02  6:34   ` Jeff Law
  3 siblings, 2 replies; 32+ messages in thread
From: Andreas Schwab @ 2023-07-25 17:55 UTC (permalink / raw)
  To: Xiao Zeng
  Cc: gcc-patches, jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain

On Jul 19 2023, Xiao Zeng wrote:

> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 38d8eb2fcf5..7e6b24bd232 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>  	  *total = COSTS_N_INSNS (1);
>  	  return true;
>  	}
> +      else if (TARGET_ZICOND && outer_code == SET &&
> +               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
> +               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
> +                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
> +                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))

Line breaks before the operator, not after.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
  2023-07-25 16:35   ` Jeff Law
@ 2023-07-26 17:53   ` Jeff Law
  2023-08-01 11:18     ` Richard Sandiford
  2023-07-26 21:14   ` Jeff Law
  2 siblings, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-26 17:53 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of the basic semantics
> defined in the spec, namely:
> 
> Conditional zero, if condition is equal to zero
>    rd = (rs2 == 0) ? 0 : rs1
> Conditional zero, if condition is non zero
>    rd = (rs2 != 0) ? 0 : rs1
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.md: Include zicond.md
> 	* config/riscv/zicond.md: New file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-primitiveSemantics.c: New test.
So I played with this a bit today.  I originally thought that using 
match_dup was the right way to go for those 4 secondary patterns.  But 
after further pondering it's not ideal.

match_dup will require pointer equality within the RTL structure.  That 
could inhibit detection in two cases.  First, SUBREGs.   SUBREGs are not 
shared.  So we'd never match if we had a SUBREG expression.

Second, post register allocation we can have the same looking RTX, but 
it may not be pointer equal.

The SUBREG issue also means that we don't want to use a REGNO (x) == 
REGNO (y) style check because those macros are only valid on REG 
expressions.  We could strip the SUBREG, but that's usually awkward to 
do in a pattern's condition.

The net result is we probably should use rtx_equal_p which I was hoping 
to avoid.  I'm testing with that change to the 4 secondary patterns 
right now.  Assuming that passes (and I have no reason to think it 
won't) then I'll go ahead and commit #1 and #2 from this series which is 
all I have time for today.



Jeff

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

* Re: [PATCH 1/5] [RISC-V] Recognize Zicond extension
  2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
  2023-07-25 16:35   ` Jeff Law
@ 2023-07-26 21:11   ` Jeff Law
  1 sibling, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-07-26 21:11 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch is the minimal support for Zicond extension, include
> the extension name, mask and target defination.
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc: New extension.
> 	* config/riscv/riscv-opts.h (MASK_ZICOND): New mask.
> 	(TARGET_ZICOND): New target.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/attribute-20.c: New test.
> 	* gcc.target/riscv/attribute-21.c: New test.
I've pushed this to the trunk.
jeff

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
  2023-07-25 16:35   ` Jeff Law
  2023-07-26 17:53   ` Jeff Law
@ 2023-07-26 21:14   ` Jeff Law
  2 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-07-26 21:14 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

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



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of the basic semantics
> defined in the spec, namely:
> 
> Conditional zero, if condition is equal to zero
>    rd = (rs2 == 0) ? 0 : rs1
> Conditional zero, if condition is non zero
>    rd = (rs2 != 0) ? 0 : rs1
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.md: Include zicond.md
> 	* config/riscv/zicond.md: New file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zicond-primitiveSemantics.c: New test.
So as I mentioned earlier today, adjusting the insn condition to use 
rtx_equal_p seems to be the right way to go.  Attached is a V2 of this 
patch that implements that.  It was trivial enough to do that there's no 
need to break this patch down further.

I've pushed V2 to the trunk.

Thanks,
Jeff

[-- Attachment #2: P --]
[-- Type: text/plain, Size: 6868 bytes --]

commit 74290c664d1d4c067a996253fe505555ec671668
Author: Xiao Zeng <zengxiao@eswincomputing.com>
Date:   Wed Jul 26 11:59:59 2023 -0600

    [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
    
    This patch completes the recognition of the basic semantics
    defined in the spec, namely:
    
    Conditional zero, if condition is equal to zero
      rd = (rs2 == 0) ? 0 : rs1
    Conditional zero, if condition is non zero
      rd = (rs2 != 0) ? 0 : rs1
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.md: Include zicond.md
            * config/riscv/zicond.md: New file.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/zicond-primitiveSemantics.c: New test.
    
            Co-authored-by: Philipp Tomsich <philipp.tomsich@vrull.eu>
            Co-authored-by: Raphael Zinsly <rzinsly@ventanamicro.com>
            Co-authored-by: Jeff Law <jlaw@ventanamicro.com>

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 24515bcf706..8d8fc93bb14 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -3319,3 +3319,4 @@ (define_expand "msubhisi4"
 (include "sifive-7.md")
 (include "thead.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..723a22422e1
--- /dev/null
+++ b/gcc/config/riscv/zicond.md
@@ -0,0 +1,84 @@
+;; 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_code_attr nez [(eq "eqz") (ne "nez")])
+
+;; Zicond
+(define_insn "*czero.<eqz>.<GPR:mode><ANYI:mode>"
+  [(set (match_operand:GPR 0 "register_operand"                      "=r")
+        (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
+                                    (const_int 0))
+                          (match_operand:GPR 2 "register_operand"    "r")
+                          (const_int 0)))]
+  "TARGET_ZICOND"
+  "czero.<eqz>\t%0,%2,%1"
+)
+
+(define_insn "*czero.<nez>.<GPR:mode><ANYI:mode>"
+  [(set (match_operand:GPR 0 "register_operand"                     "=r")
+        (if_then_else:GPR (eq_or_ne (match_operand:ANYI 1 "register_operand" "r")
+                                    (const_int 0))
+                          (const_int 0)
+                          (match_operand:GPR 2 "register_operand"   "r")))]
+  "TARGET_ZICOND"
+  "czero.<nez>\t%0,%2,%1"
+)
+
+;; Special optimization under eq/ne in primitive semantics
+(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt1"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "1")
+                          (match_operand:GPR 3 "register_operand" "r")))]
+  "TARGET_ZICOND && rtx_equal_p (operands[1], operands[2])"
+  "czero.eqz\t%0,%3,%1"
+)
+
+(define_insn "*czero.eqz.<GPR:mode><ANYI:mode>.opt2"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (eq (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "r")
+                          (match_operand:GPR 3 "register_operand" "1")))]
+  "TARGET_ZICOND && rtx_equal_p (operands[1],  operands[3])"
+  "czero.nez\t%0,%2,%1"
+)
+
+(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt3"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "r")
+                          (match_operand:GPR 3 "register_operand" "1")))]
+  "TARGET_ZICOND && rtx_equal_p (operands[1], operands[3])"
+  "czero.eqz\t%0,%2,%1"
+)
+
+(define_insn "*czero.nez.<GPR:mode><ANYI:mode>.opt4"
+  [(set (match_operand:GPR 0 "register_operand"                   "=r")
+        (if_then_else:GPR (ne (match_operand:ANYI 1 "register_operand" "r")
+                              (const_int 0))
+                          (match_operand:GPR 2 "register_operand" "1")
+                          (match_operand:GPR 3 "register_operand" "r")))]
+  "TARGET_ZICOND && rtx_equal_p (operands[1], operands[2])"
+  "czero.nez\t%0,%3,%1"
+)
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
new file mode 100644
index 00000000000..76c5019a992
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0"} } */
+
+long primitiveSemantics_00(long a, long b) { return a == 0 ? 0 : b; }
+
+long primitiveSemantics_01(long a, long b) { return a != 0 ? 0 : b; }
+
+long primitiveSemantics_02(long a, long b) { return a == 0 ? b : 0; }
+
+long primitiveSemantics_03(long a, long b) { return a != 0 ? b : 0; }
+
+long primitiveSemantics_04(long a, long b) {
+  if (a)
+    b = 0;
+  return b;
+}
+
+long primitiveSemantics_05(long a, long b) {
+  if (!a)
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_06(int a, int b) { return a == 0 ? 0 : b; }
+
+int primitiveSemantics_07(int a, int b) { return a != 0 ? 0 : b; }
+
+int primitiveSemantics_08(int a, int b) { return a == 0 ? b : 0; }
+
+int primitiveSemantics_09(int a, int b) { return a != 0 ? b : 0; }
+
+int primitiveSemantics_10(int a, int b) {
+  if (a)
+    b = 0;
+  return b;
+}
+
+int primitiveSemantics_11(int a, int b) {
+  if (!a)
+    b = 0;
+  return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */

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

* Re: Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-25 17:55   ` Andreas Schwab
@ 2023-07-27  5:44     ` Xiao Zeng
  2023-07-28 15:09     ` Jeff Law
  1 sibling, 0 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-27  5:44 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: gcc-patches, jeffreyalaw, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain

On Wed, Jul 26, 2023 at 01:55:00 AM Andreas Schwab <schwab@linux-m68k.org> wrote:
>
>On Jul 19 2023, Xiao Zeng wrote:
>
>> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>> index 38d8eb2fcf5..7e6b24bd232 100644
>> --- a/gcc/config/riscv/riscv.cc
>> +++ b/gcc/config/riscv/riscv.cc
>> @@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>>    *total = COSTS_N_INSNS (1);
>>    return true;
>>  }
>> +      else if (TARGET_ZICOND && outer_code == SET &&
>> +               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
>> +               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>> +                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>> +                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))
>
>Line breaks before the operator, not after.
>
>--
>Andreas Schwab, schwab@linux-m68k.org
>GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
>"And now for something completely different." 

Thank you for pointing out the code format issue. I will fix it in the future patch.

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

* Re: Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-25 17:51 ` [PATCH 0/5] Recognize Zicond extension Jeff Law
@ 2023-07-27  8:43   ` Xiao Zeng
  2023-07-27 14:43     ` Jeff Law
  0 siblings, 1 reply; 32+ messages in thread
From: Xiao Zeng @ 2023-07-27  8:43 UTC (permalink / raw)
  To: jeffreyalaw, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

On Wed, Jul 26, 2023 at 01:51:00 AM  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 7/19/23 04:11, Xiao Zeng wrote:
>> Hi all RISC-V folks:
>>
>> This series of patches completes support for the riscv architecture's
>> Zicond standard extension instruction set.
>>
>> Currently, Zicond is in a frozen state.
>>
>> See the Zicond specification for details:
>> https://github.com/riscv/riscv-zicond/releases/download/v1.0-rc2/riscv-zicond-v1.0-rc2.pdf
>>
>> Prior to this, other community members have also done related work, as shown in:
>> https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611767.html
>> https://sourceware.org/pipermail/binutils/2023-January/125773.html
>>
>> Xiao Zeng (5):
>>    [RISC-V] Recognize Zicond extension
>>    [RISC-V] Generate Zicond instruction for basic semantics
>>    [RISC-V] Generate Zicond instruction for select pattern with condition
>>      eq or neq to 0
>>    [RISC-V] Generate Zicond instruction for select pattern with condition
>>      eq or neq to non-zero
>>    [RISC-V] Generate Zicond instruction for conditional execution
>[ ... ]
>So what I'm thinking for the overall kit is to stage it in a bit
>differently given we have some bits which clearly can go forward as-is
>or with very minor changes and others that are going to need some
>iteration/refinement.
>
>So I'm going to suggest a few changes so that bits which are non
>controversial can move forward immediately.
>
>1/5 looked fine as-is.
>
>I would split 2/5.  The first two patterns you added are
>non-controversial and could go in immediately.  The other 4 patterns
>(which require some operand matching) will likely need at least one
>round of iteration and should be a distinct patch.
>
>
>I would split 3/5 as well.  3a would be the costing which I think just
>needs to use COSTS_N_INSNS (1) rather than 0 for the cost of a
>conditional move and could then move forward immediately.  The bits to
>wire everything up into the conditional move pattern would be a distinct
>patch.  We did something similar internally in Ventana and I'd like to
>take the time to make sure the issues we ran into are addressed in your
>version then do an evaluation of the two approaches.
>
>I think patch 4 is probably going to need some work too.  I *think* what
>we did internally at Ventana will work better (utilizing scc for a
>non-trivial condition).
>
>Let's defer patch #5 initially as well.  It's going to get tangled up in
>a whole bunch of changes I think we need to make to ifcvt.cc.
>
>The point being that with the bits from #1, #2 and #3 we can get some
>initial support in immediately.  eswincomputing and ventana can both
>reduce our divergence from the trunk and work together on the rest of
>the bits.
>
>Does that work for you?
>
>jeff 

1 Thanks Jeff for your code review feedback.

2. According to your opinions, I have modified the code, but out of caution
for upstream, I conducted a complete regression tests on patch V2, which took
some time. I was unable to reply to emails and upload patch V2 in a timely manner.

3 After you and other maintainers made minor modifications to my patch[1/5] 
and patch[2/5], it has been merged into the master, so I will no longer upload patch V2.

4 patch[1/5] and patch[2/5], which have been merged into the master, have only
completed basic support for Zicond, and further optimization work needs to be
completed. These further optimization reactions are reflected in my patch[3/5]
patch[4/5] and patch[5/5].

5 As you mentioned in your previous email https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625427.html
"eswincomputing and ventana can both reduce our divergence from the trunk
and work together on the rest of the bits...". I will reorganize patch[3/5] patch[4/5]
and patch[5/5], provide more detailed explanations, and submit them as an alternative
solution for further optimization of Zicond.

Does that work for you?

Xiao Zeng

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

* Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-27  8:43   ` Xiao Zeng
@ 2023-07-27 14:43     ` Jeff Law
  2023-07-28  6:34       ` Xiao Zeng
  0 siblings, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-27 14:43 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/27/23 02:43, Xiao Zeng wrote:

> 
> 2. According to your opinions, I have modified the code, but out of caution
> for upstream, I conducted a complete regression tests on patch V2, which took
> some time. I was unable to reply to emails and upload patch V2 in a timely manner.
Sorry to have wasted your time -- zicond/xventanacondops has lingered 
for quite a while and I had a bit of free time yesterday.  I felt it was 
most useful to try and move this stuff forward.



> 
> 3 After you and other maintainers made minor modifications to my patch[1/5]
> and patch[2/5], it has been merged into the master, so I will no longer upload patch V2.
Agreed.

> 
> 4 patch[1/5] and patch[2/5], which have been merged into the master, have only
> completed basic support for Zicond, and further optimization work needs to be
> completed. These further optimization reactions are reflected in my patch[3/5]
> patch[4/5] and patch[5/5].
Agreed.

> 
> 5 As you mentioned in your previous email https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625427.html
> "eswincomputing and ventana can both reduce our divergence from the trunk
> and work together on the rest of the bits...". I will reorganize patch[3/5] patch[4/5]
> and patch[5/5], provide more detailed explanations, and submit them as an alternative
> solution for further optimization of Zicond.
> 
> Does that work for you?
I'm going to look at 3/5 today pretty closely.  Exposing zicond to 
mov<node>cc is something we had implemented inside Ventana and I want to 
compare/contrast your work with ours.

What I like about yours is it keeps all the logic in riscv.cc rather 
than scattering it across riscv.cc and riscv.md.  What I like about the 
internal Ventana bits is its ability to support arbitrary comparisons by 
utilizing sCC if the original is not an eq/ne comparison.

Ideally we'll be able to get the best of both.

Jeff


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

* Re: Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-27 14:43     ` Jeff Law
@ 2023-07-28  6:34       ` Xiao Zeng
  2023-07-28 15:03         ` Jeff Law
  2023-08-03  2:59         ` Jeff Law
  0 siblings, 2 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-28  6:34 UTC (permalink / raw)
  To: jeffreyalaw, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

On Thu, Jul 27, 2023 at 10:43:00 PM  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 7/27/23 02:43, Xiao Zeng wrote:
>
>>
>> 2. According to your opinions, I have modified the code, but out of caution
>> for upstream, I conducted a complete regression tests on patch V2, which took
>> some time. I was unable to reply to emails and upload patch V2 in a timely manner.
>Sorry to have wasted your time 

It's okay
I am very willing to accept opinions from the gcc community.

>-- zicond/xventanacondops has lingered
>for quite a while and I had a bit of free time yesterday.  I felt it was
>most useful to try and move this stuff forward.
>
>
>
>>
>> 3 After you and other maintainers made minor modifications to my patch[1/5]
>> and patch[2/5], it has been merged into the master, so I will no longer upload patch V2.
>Agreed.
>
>>
>> 4 patch[1/5] and patch[2/5], which have been merged into the master, have only
>> completed basic support for Zicond, and further optimization work needs to be
>> completed. These further optimization reactions are reflected in my patch[3/5]
>> patch[4/5] and patch[5/5].
>Agreed.
>
>>
>> 5 As you mentioned in your previous email https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625427.html
>> "eswincomputing and ventana can both reduce our divergence from the trunk
>> and work together on the rest of the bits...". I will reorganize patch[3/5] patch[4/5]
>> and patch[5/5], provide more detailed explanations, and submit them as an alternative
>> solution for further optimization of Zicond.
>>
>> Does that work for you?
>I'm going to look at 3/5 today pretty closely.  Exposing zicond to
>mov<node>cc is something we had implemented inside Ventana and I want to
>compare/contrast your work with ours. 

What a coincidence!

>
>What I like about yours is it keeps all the logic in riscv.cc rather
>than scattering it across riscv.cc and riscv.md.  

Yes, when I use enough test cases, I cannot find a concise way to optimize
all test cases. When I enumerated all possible cases in the mov<mode>cc
function of the RISC-V backend, I found a method that satisfied me, which
is the method in patch [3/5].

>What I like about the
>internal Ventana bits is its ability to support arbitrary comparisons by
>utilizing sCC if the original is not an eq/ne comparison.
> 

If it's just for the Zicond instruction set, is it necessary to make judgments
outside of eq/ne? After all, it does not support comparison actions other
than eq/ne. Of course, it is also possible to use a special technique to use
Zicond in non eq/ne comparisons.

>Ideally we'll be able to get the best of both. 

Of course, it is best to unify all situations in one framework.

>
>Jeff

Now that the code on the master has preliminary support for
Zicond, I will still submit the optimization patches for Zicond to
the community for the convenience of finding the ideal method.

Thanks
Xiao Zeng

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

* Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-28  6:34       ` Xiao Zeng
@ 2023-07-28 15:03         ` Jeff Law
  2023-07-29 10:01           ` Xiao Zeng
  2023-08-03  2:59         ` Jeff Law
  1 sibling, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-28 15:03 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/28/23 00:34, Xiao Zeng wrote:

>>>
>>> Does that work for you?
>> I'm going to look at 3/5 today pretty closely.  Exposing zicond to
>> mov<node>cc is something we had implemented inside Ventana and I want to
>> compare/contrast your work with ours.
> 
> What a coincidence!
Zicond is a direct descendant of xventanacondops.  The only notable 
difference is in their encodings.

> 
>>
>> What I like about yours is it keeps all the logic in riscv.cc rather
>> than scattering it across riscv.cc and riscv.md.
> 
> Yes, when I use enough test cases, I cannot find a concise way to optimize
> all test cases. When I enumerated all possible cases in the mov<mode>cc
> function of the RISC-V backend, I found a method that satisfied me, which
> is the method in patch [3/5].
I got pulled away to another task yesterday, so didn't get as far as I 
wanted.   The biggest inight from yesterday was determining that some of 
the cases you're handling in riscv_expand_conditional_move were things 
we were doing inside ifcvt.cc.

The difference is likely because the initial work on zicond here was 
primarily driven by changes to ifcvt.  It was only after evaluating that 
initial implementation that we started to the effort to use zicond at 
RTL expansion time.

I could make a case for either approach, but the more I ponder them the 
more I'm inclined to go with something like yours.  We want to capture 
the cases implementable as a conditional move as early as possible in 
the RTL pipeline rather than relying on ifcvt to catch it later.  It 
also avoids polluting ifcvt with transformations that are only likely 
needed on risc-v.


>>
> 
> If it's just for the Zicond instruction set, is it necessary to make judgments
> outside of eq/ne? After all, it does not support comparison actions other
> than eq/ne. Of course, it is also possible to use a special technique to use
> Zicond in non eq/ne comparisons.
It's not necessary, but it's definitely helpful to cover the other 
conditions.  In fact, we can even cover a variety of fp conditions by 
utilizing the sCC type insns.


So what I'm looking at for patch #3 is to split out the costing bits 
into its own patch which can go forward immediately.  THen continue 
evaluating the best way to handle unifying the expander/canonicalization 
code.  Your testcases in patch #3 are particularly helpful to make sure 
we're not missing cases.

Jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-25 17:55   ` Andreas Schwab
  2023-07-27  5:44     ` Xiao Zeng
@ 2023-07-28 15:09     ` Jeff Law
  2023-07-29  9:48       ` Xiao Zeng
  1 sibling, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-28 15:09 UTC (permalink / raw)
  To: Andreas Schwab, Xiao Zeng
  Cc: gcc-patches, research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/25/23 11:55, Andreas Schwab wrote:
> On Jul 19 2023, Xiao Zeng wrote:
> 
>> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>> index 38d8eb2fcf5..7e6b24bd232 100644
>> --- a/gcc/config/riscv/riscv.cc
>> +++ b/gcc/config/riscv/riscv.cc
>> @@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>>   	  *total = COSTS_N_INSNS (1);
>>   	  return true;
>>   	}
>> +      else if (TARGET_ZICOND && outer_code == SET &&
>> +               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
>> +               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>> +                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>> +                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))
> 
> Line breaks before the operator, not after.
Also note that && GET_CODE (XEXP (x, 2)) && that appears twice.

That just verifies the code isn't RTX_UNKNOWN which I suspect isn't what 
the author intended.  It probably needs to be adjusted for SUBREGs and 
the pointer equality issues with REGs after reload.

I'll take care of these goofs since the costing ought to be able to move 
forward independently of the improvements Xiao made to generating 
conditional move sequences.

Jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
  2023-07-25 17:32   ` Jeff Law
  2023-07-25 17:55   ` Andreas Schwab
@ 2023-07-28 20:59   ` Jeff Law
  2023-07-29  9:14     ` Xiao Zeng
  2023-08-02  6:34   ` Jeff Law
  3 siblings, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-07-28 20:59 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:

> +  else if (TARGET_ZICOND
> +           && (code == EQ || code == NE)
> +           && GET_MODE_CLASS (mode) == MODE_INT)
> +    {
> +      need_eq_ne_p = true;
> +      /* 0 + imm  */
> +      if (GET_CODE (cons) == CONST_INT && cons == const0_rtx
> +          && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
> +        {
> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +          alt = force_reg (mode, alt);
> +          emit_insn (gen_rtx_SET (dest,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                        cons, alt)));
> +          return true;
> +        }
> +      /* imm + imm  */
> +      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
> +               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
> +        {
> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +          alt = force_reg (mode, alt);
> +          rtx temp1 = gen_reg_rtx (mode);
> +          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
> +          riscv_emit_binary(PLUS, temp1, alt, temp2);
So in this sequence you're just computing a constant since both ALT and 
CONS are constants.  It's better to just form the constant directly, 
then force that into a register because it'll make the costing more 
correct, particularly if the resulting constant needs more than one 
instruction to synthesize.

And a nit.  There should always be a space between a function name and 
its argument list.



> +          emit_insn (gen_rtx_SET (dest,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                        const0_rtx, alt)));
> +          riscv_emit_binary(PLUS, dest, dest, cons);
> +          return true;
I don't see how this can be correct from a code generation standpoint. 
You compute ALT-CONS into TEMP1 earlier.  But you never use TEMP1 after 
that.  I think you meant to use TEMP1 instead of ALT as the false arm if 
the IF-THEN-ELSE you constructed.

In general you should be using CONST0_RTX (mode) rather than const0_rtx.

> +        }
> +      /* imm + reg  */
> +      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
> +               && GET_CODE (alt) == REG)
> +        {
> +          /* Optimize for register value of 0.  */
> +          if (op0 == alt && op1 == const0_rtx)
> +            {
> +              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +              cons = force_reg (mode, cons);
> +              emit_insn (gen_rtx_SET (dest,
> +                                      gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                            cons, alt)));
> +              return true;
> +            }
> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +          rtx temp1 = gen_reg_rtx (mode);
> +          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
> +          riscv_emit_binary(PLUS, temp1, alt, temp2);
Here you have to be careful if CONS is -2048.  You negate it resulting 
in +2048 which can't be used in an addi.  This will cause the entire 
sequence to fail due to an unrecognized insn.  It would be better to 
handle that scenario directly so the generated sequence is still valid.

By generating recognizable code in that case we let the costing model 
determine if the conditional move sequence is better than the branching 
sequence.


> +          emit_insn (gen_rtx_SET (dest,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                        const0_rtx, alt)));
I think we have the same problem with the use of ALT here rather than 
TEMP1 that we had in the previous case.



> +      /* reg + imm  */
> +      else if (GET_CODE (cons) == REG
> +               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
> +        {
> +          /* Optimize for register value of 0.  */
> +          if (op0 == cons && op1 == const0_rtx)
> +            {
> +              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +              alt = force_reg (mode, alt);
> +              emit_insn (gen_rtx_SET (dest,
> +                                      gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                            cons, alt)));
> +              return true;
> +            }
> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +          rtx temp1 = gen_reg_rtx (mode);
> +          rtx temp2 = GEN_INT(-1 * INTVAL (alt));
> +          riscv_emit_binary(PLUS, temp1, cons, temp2);
> +          emit_insn (gen_rtx_SET (dest,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
> +                                                        temp1, const0_rtx)));
> +          riscv_emit_binary(PLUS, dest, dest, alt);
> +          return true;
This has basically the same issues as the imm + reg case.


> +        }
> +      /* reg + reg  */
> +      else if (GET_CODE (cons) == REG && GET_CODE (alt) == REG)
> +        {
> +          rtx reg1 = gen_reg_rtx (mode);
> +          rtx reg2 = gen_reg_rtx (mode);
> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
> +          rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
> +          rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE,
> +                                      GET_MODE (op0), op0, op1);
> +          emit_insn (gen_rtx_SET (reg2,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond2,
> +                                                        const0_rtx, cons)));
> +          emit_insn (gen_rtx_SET (reg1,
> +                                  gen_rtx_IF_THEN_ELSE (mode, cond1,
> +                                                        const0_rtx, alt)));
> +          riscv_emit_binary(IOR, dest, reg1, reg2);
> +          return true;
This probably should detect the case where alt or cons is the same as 
op0.  Otherwise I would expect the costing model to reject some cases 
that are actually profitable.


> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 6b8c2e8e268..b4147c7a79c 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -2484,7 +2484,7 @@
>   	(if_then_else:GPR (match_operand 1 "comparison_operator")
>   			  (match_operand:GPR 2 "reg_or_0_operand")
>   			  (match_operand:GPR 3 "sfb_alu_operand")))
> -  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
> +  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
Note the predicate for operand2 will reject all constants except 0.

Anyway, I'm still cleaning this up and adding the bits from Ventana 
which handle the relational conditions as well as FP conditionals.

Jeff

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

* Re: Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-28 20:59   ` Jeff Law
@ 2023-07-29  9:14     ` Xiao Zeng
  2023-08-03  4:59       ` Jeff Law
  0 siblings, 1 reply; 32+ messages in thread
From: Xiao Zeng @ 2023-07-29  9:14 UTC (permalink / raw)
  To: jeffreyalaw, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

On Sat, Jul 29, 2023 at 04:59:00 AM  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 7/19/23 04:11, Xiao Zeng wrote:
>
>> +  else if (TARGET_ZICOND
>> +           && (code == EQ || code == NE)
>> +           && GET_MODE_CLASS (mode) == MODE_INT)
>> +    {
>> +      need_eq_ne_p = true;
>> +      /* 0 + imm  */
>> +      if (GET_CODE (cons) == CONST_INT && cons == const0_rtx
>> +          && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
>> +        {
>> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
>> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +          alt = force_reg (mode, alt);
>> +          emit_insn (gen_rtx_SET (dest,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                        cons, alt)));
>> +          return true;
>> +        }
>> +      /* imm + imm  */
>> +      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
>> +               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
>> +        {
>> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
>> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +          alt = force_reg (mode, alt);
>> +          rtx temp1 = gen_reg_rtx (mode);
>> +          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
>> +          riscv_emit_binary(PLUS, temp1, alt, temp2);
>So in this sequence you're just computing a constant since both ALT and
>CONS are constants.  It's better to just form the constant directly,
>then force that into a register because it'll make the costing more
>correct, particularly if the resulting constant needs more than one
>instruction to synthesize. 

Fixed

>
>And a nit.  There should always be a space between a function name and
>its argument list. 

Fixed

>
>
>
>> +          emit_insn (gen_rtx_SET (dest,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                        const0_rtx, alt)));
>> +          riscv_emit_binary(PLUS, dest, dest, cons);
>> +          return true;
>I don't see how this can be correct from a code generation standpoint.
>You compute ALT-CONS into TEMP1 earlier.  But you never use TEMP1 after
>that.  I think you meant to use TEMP1 instead of ALT as the false arm if
>the IF-THEN-ELSE you constructed. 

Fixed

>
>In general you should be using CONST0_RTX (mode) rather than const0_rtx.
> 

Fixed

>> +        }
>> +      /* imm + reg  */
>> +      else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx
>> +               && GET_CODE (alt) == REG)
>> +        {
>> +          /* Optimize for register value of 0.  */
>> +          if (op0 == alt && op1 == const0_rtx)
>> +            {
>> +              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +              cons = force_reg (mode, cons);
>> +              emit_insn (gen_rtx_SET (dest,
>> +                                      gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                            cons, alt)));
>> +              return true;
>> +            }
>> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
>> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +          rtx temp1 = gen_reg_rtx (mode);
>> +          rtx temp2 = GEN_INT(-1 * INTVAL (cons));
>> +          riscv_emit_binary(PLUS, temp1, alt, temp2);
>Here you have to be careful if CONS is -2048.  You negate it resulting
>in +2048 which can't be used in an addi.  This will cause the entire
>sequence to fail due to an unrecognized insn.  It would be better to
>handle that scenario directly so the generated sequence is still valid.
>
>By generating recognizable code in that case we let the costing model
>determine if the conditional move sequence is better than the branching
>sequence. 

Thank you for pointing out this special situation, it has been fixed

>
>
>> +          emit_insn (gen_rtx_SET (dest,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                        const0_rtx, alt)));
>I think we have the same problem with the use of ALT here rather than
>TEMP1 that we had in the previous case. 

Fixed

>
>
>
>> +      /* reg + imm  */
>> +      else if (GET_CODE (cons) == REG
>> +               && GET_CODE (alt) == CONST_INT && alt != const0_rtx)
>> +        {
>> +          /* Optimize for register value of 0.  */
>> +          if (op0 == cons && op1 == const0_rtx)
>> +            {
>> +              rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +              alt = force_reg (mode, alt);
>> +              emit_insn (gen_rtx_SET (dest,
>> +                                      gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                            cons, alt)));
>> +              return true;
>> +            }
>> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
>> +          rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +          rtx temp1 = gen_reg_rtx (mode);
>> +          rtx temp2 = GEN_INT(-1 * INTVAL (alt));
>> +          riscv_emit_binary(PLUS, temp1, cons, temp2);
>> +          emit_insn (gen_rtx_SET (dest,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond,
>> +                                                        temp1, const0_rtx)));
>> +          riscv_emit_binary(PLUS, dest, dest, alt);
>> +          return true;
>This has basically the same issues as the imm + reg case. 

Fixed

>
>
>> +        }
>> +      /* reg + reg  */
>> +      else if (GET_CODE (cons) == REG && GET_CODE (alt) == REG)
>> +        {
>> +          rtx reg1 = gen_reg_rtx (mode);
>> +          rtx reg2 = gen_reg_rtx (mode);
>> +          riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
>> +          rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
>> +          rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE,
>> +                                      GET_MODE (op0), op0, op1);
>> +          emit_insn (gen_rtx_SET (reg2,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond2,
>> +                                                        const0_rtx, cons)));
>> +          emit_insn (gen_rtx_SET (reg1,
>> +                                  gen_rtx_IF_THEN_ELSE (mode, cond1,
>> +                                                        const0_rtx, alt)));
>> +          riscv_emit_binary(IOR, dest, reg1, reg2);
>> +          return true;
>This probably should detect the case where alt or cons is the same as
>op0.  Otherwise I would expect the costing model to reject some cases
>that are actually profitable.
> 

Fixed

>
>> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
>> index 6b8c2e8e268..b4147c7a79c 100644
>> --- a/gcc/config/riscv/riscv.md
>> +++ b/gcc/config/riscv/riscv.md
>> @@ -2484,7 +2484,7 @@
>>   (if_then_else:GPR (match_operand 1 "comparison_operator")
>>     (match_operand:GPR 2 "reg_or_0_operand")
>>     (match_operand:GPR 3 "sfb_alu_operand")))
>> -  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
>> +  "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
>Note the predicate for operand2 will reject all constants except 0.
>
>Anyway, I'm still cleaning this up and adding the bits from Ventana
>which handle the relational conditions as well as FP conditionals.
>
>Jeff 

1 Thank you for Jeff's code review comments. I have made the modifications
and submitted the V2-patch[3/5].

2 For the calculation method of cost, I hope to submit a separate patch[cost]
after the V2-patch[3/5] merged into master, which will focus on explaining
the reasons for calculating cost in the same way as in patch[4/5].

3 At the same time, I realized that for Zicond's series of patches, it would be
better to split them into separate patches and submit them to the community
code review. Therefore, I plan to submit: 
V2-patch[3/5]
patch[cost]
V2-patch[4/5] 
V2-patch[5/5]
I will only submit subsequent patches after the previous patch enters the master.

4. In V2-patch[3/5], Zicond's cost calculation is not involved, therefore, all test
cases are skipped with "- O0" and "- Os". I will remove the "- Os" constraint from
the test case in patch[cost].

5 The address for V2-patch[3/5] is: https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625781.html

Thanks
Xiao Zeng

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

* Re: Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-28 15:09     ` Jeff Law
@ 2023-07-29  9:48       ` Xiao Zeng
  0 siblings, 0 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-29  9:48 UTC (permalink / raw)
  To: jeffreyalaw, Andreas Schwab
  Cc: gcc-patches, research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

On Fri, Jul 28, 2023 at 11:09:00 PM  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 7/25/23 11:55, Andreas Schwab wrote:
>> On Jul 19 2023, Xiao Zeng wrote:
>>
>>> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
>>> index 38d8eb2fcf5..7e6b24bd232 100644
>>> --- a/gcc/config/riscv/riscv.cc
>>> +++ b/gcc/config/riscv/riscv.cc
>>> @@ -2448,6 +2448,17 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
>>>     *total = COSTS_N_INSNS (1);
>>>     return true;
>>>   }
>>> +      else if (TARGET_ZICOND && outer_code == SET &&
>>> +               ((GET_CODE (XEXP (x, 1)) == REG && XEXP (x, 2) == const0_rtx) ||
>>> +               (GET_CODE (XEXP (x, 2)) == REG && XEXP (x, 1) == const0_rtx) ||
>>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>>> +                XEXP (x, 1) == XEXP (XEXP (x, 0), 0)) ||
>>> +               (GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 2)) &&
>>> +                XEXP (x, 2) == XEXP (XEXP (x, 0), 0))))
>>
>> Line breaks before the operator, not after.
>Also note that && GET_CODE (XEXP (x, 2)) && that appears twice. 

This is an error that I will fix in patch[cost] and provide a detailed explanation.

>
>That just verifies the code isn't RTX_UNKNOWN which I suspect isn't what
>the author intended.  It probably needs to be adjusted for SUBREGs and
>the pointer equality issues with REGs after reload.
>
>I'll take care of these goofs since the costing ought to be able to move
>forward independently of the improvements Xiao made to generating
>conditional move sequences.
>
>Jeff 

After V2-patch[3/5] is accepted, a patch[cost] will be submitted to provide detailed
explanation of this issue. Of course, as Jeff mentioned, some issues will also be fixed.

Thanks
Xiao Zeng

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

* Re: Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-28 15:03         ` Jeff Law
@ 2023-07-29 10:01           ` Xiao Zeng
  0 siblings, 0 replies; 32+ messages in thread
From: Xiao Zeng @ 2023-07-29 10:01 UTC (permalink / raw)
  To: jeffreyalaw, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

On Fri, Jul 28, 2023 at 11:03:00 PM  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 7/28/23 00:34, Xiao Zeng wrote:
>
>>>>
>>>> Does that work for you?
>>> I'm going to look at 3/5 today pretty closely.  Exposing zicond to
>>> mov<node>cc is something we had implemented inside Ventana and I want to
>>> compare/contrast your work with ours.
>>
>> What a coincidence!
>Zicond is a direct descendant of xventanacondops.  The only notable
>difference is in their encodings. 
It explains the matter.

>
>>
>>>
>>> What I like about yours is it keeps all the logic in riscv.cc rather
>>> than scattering it across riscv.cc and riscv.md.
>>
>> Yes, when I use enough test cases, I cannot find a concise way to optimize
>> all test cases. When I enumerated all possible cases in the mov<mode>cc
>> function of the RISC-V backend, I found a method that satisfied me, which
>> is the method in patch [3/5].
>I got pulled away to another task yesterday, so didn't get as far as I
>wanted.   The biggest inight from yesterday was determining that some of
>the cases you're handling in riscv_expand_conditional_move were things
>we were doing inside ifcvt.cc.
>
>The difference is likely because the initial work on zicond here was
>primarily driven by changes to ifcvt.  It was only after evaluating that
>initial implementation that we started to the effort to use zicond at
>RTL expansion time.
>
>I could make a case for either approach, but the more I ponder them the
>more I'm inclined to go with something like yours.  

>We want to capture
>the cases implementable as a conditional move as early as possible in
>the RTL pipeline rather than relying on ifcvt to catch it later.  It
>also avoids polluting ifcvt with transformations that are only likely
>needed on risc-v. 
That's why I did this optimization in riscv.cc riscv_expand_conditional_move.

>
>
>>>
>>
>> If it's just for the Zicond instruction set, is it necessary to make judgments
>> outside of eq/ne? After all, it does not support comparison actions other
>> than eq/ne. Of course, it is also possible to use a special technique to use
>> Zicond in non eq/ne comparisons.
>It's not necessary, but it's definitely helpful to cover the other
>conditions.  In fact, we can even cover a variety of fp conditions by
>utilizing the sCC type insns. 
It would be great if we could do this.

>
>
>So what I'm looking at for patch #3 is to split out the costing bits
>into its own patch which can go forward immediately.  
As you expected, V2-patch[3/5] has arrived,
and its address is: https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625781.html

>THen continue
>evaluating the best way to handle unifying the expander/canonicalization
>code.
That's nice.
  
>Your testcases in patch #3 are particularly helpful to make sure
>we're not missing cases. 
Yes, I have always believed that test cases can be redundant, but they cannot
be omitted. As we all know, the compiler will always make some magical changes
without our knowledge, which may not be what we expect. And test cases
can help us stay away from this risk.

>
>Jeff 

Thanks
Xiao Zeng

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-07-26 17:53   ` Jeff Law
@ 2023-08-01 11:18     ` Richard Sandiford
  2023-08-02  6:22       ` Jeff Law
  0 siblings, 1 reply; 32+ messages in thread
From: Richard Sandiford @ 2023-08-01 11:18 UTC (permalink / raw)
  To: Jeff Law via Gcc-patches
  Cc: Xiao Zeng, Jeff Law, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain

Jeff Law via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> On 7/19/23 04:11, Xiao Zeng wrote:
>> This patch completes the recognition of the basic semantics
>> defined in the spec, namely:
>> 
>> Conditional zero, if condition is equal to zero
>>    rd = (rs2 == 0) ? 0 : rs1
>> Conditional zero, if condition is non zero
>>    rd = (rs2 != 0) ? 0 : rs1
>> 
>> gcc/ChangeLog:
>> 
>> 	* config/riscv/riscv.md: Include zicond.md
>> 	* config/riscv/zicond.md: New file.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> 	* gcc.target/riscv/zicond-primitiveSemantics.c: New test.
> So I played with this a bit today.  I originally thought that using 
> match_dup was the right way to go for those 4 secondary patterns.  But 
> after further pondering it's not ideal.
>
> match_dup will require pointer equality within the RTL structure.  That 
> could inhibit detection in two cases.  First, SUBREGs.   SUBREGs are not 
> shared.  So we'd never match if we had a SUBREG expression.
>
> Second, post register allocation we can have the same looking RTX, but 
> it may not be pointer equal.

Where were you seeing the requirement for pointer equality?  genrecog.cc
at least uses rtx_equal_p, and I think it has to.  E.g. some patterns
use (match_dup ...) to match output and input mems, and mem rtxes
shouldn't be shared.

I'd always understood using matching constraints against other inputs
to be a no-no, since the RA doesn't (and can't reasonably be expected to)
make two non-identical inputs match.  So AIUI, using "1" won't lead to
different code generation compared to "r".  Both are relying on the RA
happening to do the right thing.  But "1" would presumably trigger an
ICE if something goes wrong.

Thanks,
Richard

> The SUBREG issue also means that we don't want to use a REGNO (x) == 
> REGNO (y) style check because those macros are only valid on REG 
> expressions.  We could strip the SUBREG, but that's usually awkward to 
> do in a pattern's condition.
>
> The net result is we probably should use rtx_equal_p which I was hoping 
> to avoid.  I'm testing with that change to the 4 secondary patterns 
> right now.  Assuming that passes (and I have no reason to think it 
> won't) then I'll go ahead and commit #1 and #2 from this series which is 
> all I have time for today.
>
>
>
> Jeff

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-08-01 11:18     ` Richard Sandiford
@ 2023-08-02  6:22       ` Jeff Law
  2023-08-02 10:05         ` Richard Sandiford
  0 siblings, 1 reply; 32+ messages in thread
From: Jeff Law @ 2023-08-02  6:22 UTC (permalink / raw)
  To: Jeff Law via Gcc-patches, Xiao Zeng, research_trasio, kito.cheng,
	zhengyu, eri-sw-toolchain, richard.sandiford



On 8/1/23 05:18, Richard Sandiford wrote:
> 
> Where were you seeing the requirement for pointer equality?  genrecog.cc
> at least uses rtx_equal_p, and I think it has to.  E.g. some patterns
> use (match_dup ...) to match output and input mems, and mem rtxes
> shouldn't be shared.
It's a general concern due to the way we handle transforming pseudos 
into hard registers after allocation is complete.   We can end up with 
two REG expressions that will compare equal according to rtx_equal_p, 
but which are not pointer equal.

For this kit I think the worst that would happen would be a failure to 
optimize cases post-reload.  But it's still good RTL hygene IMHO.



> 
> I'd always understood using matching constraints against other inputs
> to be a no-no, since the RA doesn't (and can't reasonably be expected to)
> make two non-identical inputs match.  So AIUI, using "1" won't lead to
> different code generation compared to "r".  Both are relying on the RA
> happening to do the right thing.  But "1" would presumably trigger an
> ICE if something goes wrong.
Yea, I think you're right.  The constraint isn't terribly important for 
these patterns -- the condition is really the enforcement mechanism.

Jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
                     ` (2 preceding siblings ...)
  2023-07-28 20:59   ` Jeff Law
@ 2023-08-02  6:34   ` Jeff Law
  3 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-08-02  6:34 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain

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



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of Zicond when the select pattern
> with condition eq or neq to 0 (using equality as an example), namely:
[ ... ]
I've committed the attached patch which implements a simple cost model 
for using Zicond to implement conditional moves.

I've changed it to give the proper cost (COSTS_N_INSNS (1) and removed 
the extraneous GET_CODE (object) tests adjusted the ChangeLog a bit and 
pushed it to the trunk.

Thanks!

Jeff

[-- Attachment #2: P --]
[-- Type: text/plain, Size: 1852 bytes --]

commit 5b501863ac7da57858fdd464dfb7a776143f22a2
Author: Xiao Zeng <zengxiao@eswincomputing.com>
Date:   Wed Aug 2 00:17:12 2023 -0600

    [PATCH 3/5] [RISC-V] Cost model for Zicond.
    
    This patch implements a reasonable cost model for using Zicond to
    implement conditional moves.  Essentially the Zicond insns are always
    COSTS_N_INSNS (1).
    
    Note there is still a problem with the costing model in general that
    results in failure to if-convert as often as we should.  In simplest
    terms the insn costing model sums the cost of the SET_SRC and the
    cost of the SET_DEST.  Thus the conditional move is considered twice
    as costly as it should be.  That will have to be addressed separately.
    
    gcc/
            * config/riscv/riscv.cc (riscv_rtx_costs): Add costing for
            using Zicond to implement some conditional moves.

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 8c474503080..785e09c76ce 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2518,6 +2518,20 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
 	  *total = COSTS_N_INSNS (1);
 	  return true;
 	}
+      else if (TARGET_ZICOND
+	       && outer_code == SET
+	       && ((GET_CODE (XEXP (x, 1)) == REG
+		    && XEXP (x, 2) == CONST0_RTX (GET_MODE (XEXP (x, 1))))
+		   || (GET_CODE (XEXP (x, 2)) == REG
+		       && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 2))))
+		   || (GET_CODE (XEXP (x, 1)) == REG
+		       && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 0), 0)))
+		   || (GET_CODE (XEXP (x, 1)) == REG
+		       && rtx_equal_p (XEXP (x, 2), XEXP (XEXP (x, 0), 0)))))
+	{
+	  *total = COSTS_N_INSNS (1);
+	  return true;
+	}
       else if (LABEL_REF_P (XEXP (x, 1)) && XEXP (x, 2) == pc_rtx)
 	{
 	  if (equality_operator (XEXP (x, 0), mode)

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-08-02  6:22       ` Jeff Law
@ 2023-08-02 10:05         ` Richard Sandiford
  2023-08-02 16:56           ` Jeff Law
  0 siblings, 1 reply; 32+ messages in thread
From: Richard Sandiford @ 2023-08-02 10:05 UTC (permalink / raw)
  To: Jeff Law via Gcc-patches
  Cc: Xiao Zeng, research_trasio, kito.cheng, zhengyu,
	eri-sw-toolchain, Jeff Law

Jeff Law via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> On 8/1/23 05:18, Richard Sandiford wrote:
>> 
>> Where were you seeing the requirement for pointer equality?  genrecog.cc
>> at least uses rtx_equal_p, and I think it has to.  E.g. some patterns
>> use (match_dup ...) to match output and input mems, and mem rtxes
>> shouldn't be shared.
> It's a general concern due to the way we handle transforming pseudos 
> into hard registers after allocation is complete.   We can end up with 
> two REG expressions that will compare equal according to rtx_equal_p, 
> but which are not pointer equal.

But isn't that OK?  I don't think there's a requirement for match_dup
pointer equality either before or after RA.  Or at least, there
shouldn't be.  If something happens to rely on pointer equality
for match_dups then I think we should fix it.

So IMO, like you said originally, match_dup would be the right way to
handle this kind of pattern.

The reason I'm interested is that AArch64 makes pretty extensive use
of match_dup for this purpose.  E.g.:

(define_insn "aarch64_<su>abd<mode><vczle><vczbe>"
  [(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
	(minus:VDQ_BHSI
	  (USMAX:VDQ_BHSI
	    (match_operand:VDQ_BHSI 1 "register_operand" "w")
	    (match_operand:VDQ_BHSI 2 "register_operand" "w"))
	  (<max_opp>:VDQ_BHSI
	    (match_dup 1)
	    (match_dup 2))))]

So if this isn't working correctly for subregs (or for anythine else),
then I'd be keen to do something about it :)

I don't want to labour the point though.

Thanks,
Richard

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

* Re: [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics
  2023-08-02 10:05         ` Richard Sandiford
@ 2023-08-02 16:56           ` Jeff Law
  0 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-08-02 16:56 UTC (permalink / raw)
  To: Jeff Law via Gcc-patches, Xiao Zeng, research_trasio, kito.cheng,
	zhengyu, eri-sw-toolchain, richard.sandiford



On 8/2/23 04:05, Richard Sandiford wrote:
> Jeff Law via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>> On 8/1/23 05:18, Richard Sandiford wrote:
>>>
>>> Where were you seeing the requirement for pointer equality?  genrecog.cc
>>> at least uses rtx_equal_p, and I think it has to.  E.g. some patterns
>>> use (match_dup ...) to match output and input mems, and mem rtxes
>>> shouldn't be shared.
>> It's a general concern due to the way we handle transforming pseudos
>> into hard registers after allocation is complete.   We can end up with
>> two REG expressions that will compare equal according to rtx_equal_p,
>> but which are not pointer equal.
> 
> But isn't that OK?  I don't think there's a requirement for match_dup
> pointer equality either before or after RA.  Or at least, there
> shouldn't be.  If something happens to rely on pointer equality
> for match_dups then I think we should fix it.


> 
> So IMO, like you said originally, match_dup would be the right way to
> handle this kind of pattern.
I'd assumed that match_dup required pointer equality.  If it doesn't, 
then great, we can adjust the pattern to use match_dup.  I'm about to 
submit some bits to simplify/correct a bit of zicond.md, then I can do 
some testing with match_dup in place now that things seem to be more 
stable on the code generation correctness side.


> 
> I don't want to labour the point though.
No worries about that on my end!  I probably don't say it enough, but 
when you raise an issue, it's worth the time to make sure I understand 
your point thoroughly.

In this case I'd assumed that match_dup relied on pointer equality which 
doesn't seem to be the case.  30+ years into this codebase and I'm still 
learning new stuff!

Jeff

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

* Re: [PATCH 0/5] Recognize Zicond extension
  2023-07-28  6:34       ` Xiao Zeng
  2023-07-28 15:03         ` Jeff Law
@ 2023-08-03  2:59         ` Jeff Law
  1 sibling, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-08-03  2:59 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/28/23 00:34, Xiao Zeng wrote:

> 
>>
>> What I like about yours is it keeps all the logic in riscv.cc rather
>> than scattering it across riscv.cc and riscv.md.
> 
> Yes, when I use enough test cases, I cannot find a concise way to optimize
> all test cases. When I enumerated all possible cases in the mov<mode>cc
> function of the RISC-V backend, I found a method that satisfied me, which
> is the method in patch [3/5].
I continue to work with the riscv_expand_conditional_move improvements.

Given the deeper problems we have with costing, I'm considering starting 
to push some of the riscv_expand_conditional_move work you've done 
without the testcases since those testcases depend on fixing the costing 
problems.

The expansion changes still have value without the costing changes. 
When we expand a COND_EXPR from gimple, we will attempt to use the 
conditional move pattern first, without regard for costing.

> 
> If it's just for the Zicond instruction set, is it necessary to make judgments
> outside of eq/ne? After all, it does not support comparison actions other
> than eq/ne. Of course, it is also possible to use a special technique to use
> Zicond in non eq/ne comparisons.
It's not necessary, but it's certainly helpful to utilize sCC insns in 
conjuction with zicond to if-convert other conditional branches.  It's 
conceptually pretty simple.

If the incoming code is not EQ/NE or we're not comparing a register 
against 0, then we can emit an scc insn to get the comparison result 
into a temporary, then use the standard zicond expansions.

Jeff

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

* Re: [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
  2023-07-29  9:14     ` Xiao Zeng
@ 2023-08-03  4:59       ` Jeff Law
  0 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-08-03  4:59 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/29/23 03:14, Xiao Zeng wrote:

> 
> 1 Thank you for Jeff's code review comments. I have made the modifications
> and submitted the V2-patch[3/5].
Yea.  I'm adjusting my tree based on those updates.  For testing I've 
actually got my compiler generating zicond by default and qemu allowing 
zicond by default.  I can then run the execute.exp tests which validate 
code correctness to a reasonable degree.


> 
> 2 For the calculation method of cost, I hope to submit a separate patch[cost]
> after the V2-patch[3/5] merged into master, which will focus on explaining
> the reasons for calculating cost in the same way as in patch[4/5].
I think the costing problem is going to require its own little 
subproject.  GCC's approach to costing is a bit crazy with multiple APIs 
that behave differently and in some cases do some rather surprising 
things.  It's a long standing design flaw.

The point being that I think we'll probably move forward with the 
functional bits, perhaps initially without the basic functionality 
tests.  That allows folks to start utilizing the core functionality 
while we audit and likely adjust the risc-v cost hook implementation.


> 
> 4. In V2-patch[3/5], Zicond's cost calculation is not involved, therefore, all test
> cases are skipped with "- O0" and "- Os". I will remove the "- Os" constraint from
> the test case in patch[cost].
We may need to avoid for -Og as well.  I've got that change here 
locally, but I wanted to go back and review that as well.

jeff

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

* Re: [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero
  2023-07-19 10:11 ` [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero Xiao Zeng
@ 2023-08-07 17:36   ` Jeff Law
  0 siblings, 0 replies; 32+ messages in thread
From: Jeff Law @ 2023-08-07 17:36 UTC (permalink / raw)
  To: Xiao Zeng, gcc-patches
  Cc: research_trasio, kito.cheng, zhengyu, eri-sw-toolchain



On 7/19/23 04:11, Xiao Zeng wrote:
> This patch completes the recognition of Zicond when the select pattern with
> condition eq or neq to non-zero (using equality as an example), namely:
> 
> 1 rd = (rs2 == non-imm) ? 0 : rs1
> 2 rd = (rs2 == reg) ? 0 : rs1
> 
> At the same time, more Zicond non basic semantic test cases have been added.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize Zicond.
I think this is handled by the changes from Raphael I just committed. 
But I do think we should take the testsuite work to verify the cases all 
work as expected.

Given the testcases from 3/5 are also on hold pending fixing the costing 
issues, I'm thinking to roll all the testsuite changes into a distinct 
patch, with the failing tests xfailed until we fix the costing work. 
But I definitely don't want to lose the tests.

jeff

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

end of thread, other threads:[~2023-08-07 17:36 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-19 10:11 [PATCH 0/5] Recognize Zicond extension Xiao Zeng
2023-07-19 10:11 ` [PATCH 1/5] [RISC-V] " Xiao Zeng
2023-07-25 16:35   ` Jeff Law
2023-07-26 21:11   ` Jeff Law
2023-07-19 10:11 ` [PATCH 2/5] [RISC-V] Generate Zicond instruction for basic semantics Xiao Zeng
2023-07-25 16:35   ` Jeff Law
2023-07-26 17:53   ` Jeff Law
2023-08-01 11:18     ` Richard Sandiford
2023-08-02  6:22       ` Jeff Law
2023-08-02 10:05         ` Richard Sandiford
2023-08-02 16:56           ` Jeff Law
2023-07-26 21:14   ` Jeff Law
2023-07-19 10:11 ` [PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0 Xiao Zeng
2023-07-25 17:32   ` Jeff Law
2023-07-25 17:55   ` Andreas Schwab
2023-07-27  5:44     ` Xiao Zeng
2023-07-28 15:09     ` Jeff Law
2023-07-29  9:48       ` Xiao Zeng
2023-07-28 20:59   ` Jeff Law
2023-07-29  9:14     ` Xiao Zeng
2023-08-03  4:59       ` Jeff Law
2023-08-02  6:34   ` Jeff Law
2023-07-19 10:11 ` [PATCH 4/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to non-zero Xiao Zeng
2023-08-07 17:36   ` Jeff Law
2023-07-19 10:11 ` [PATCH 5/5] [RISC-V] Generate Zicond instruction for conditional execution Xiao Zeng
2023-07-25 17:51 ` [PATCH 0/5] Recognize Zicond extension Jeff Law
2023-07-27  8:43   ` Xiao Zeng
2023-07-27 14:43     ` Jeff Law
2023-07-28  6:34       ` Xiao Zeng
2023-07-28 15:03         ` Jeff Law
2023-07-29 10:01           ` Xiao Zeng
2023-08-03  2:59         ` 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).