public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB
@ 2023-11-28  2:32 Fei Gao
  2023-11-28  2:32 ` [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns Fei Gao
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Fei Gao @ 2023-11-28  2:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, zengxiao, Fei Gao

Move Zicond md files ahead of SFB to recognize Zicond first.

Take the following case for example.

CFLAGS: -mtune=sifive-7-series -march=rv64gc_zicond -mabi=lp64d

long primitiveSemantics_00(long a, long b) { return a == 0 ? 0 : b; }

before patch:
primitiveSemantics_00:
	bne	a0,zero,1f	# movcc
	mv	a1,zero
1:
	mv	a0,a1
	ret

after patch:
primitiveSemantics_00:
	czero.eqz	a0,a1,a0
	ret

Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>

gcc/ChangeLog:

        * config/riscv/riscv.md (*mov<GPR:mode><X:mode>cc):move to sfb.md
        * config/riscv/sfb.md: New file.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/zicond-sfb-primitiveSemantics.c: New test.
---
 gcc/config/riscv/riscv.md                     | 19 +------
 gcc/config/riscv/sfb.md                       | 37 ++++++++++++++
 .../riscv/zicond-sfb-primitiveSemantics.c     | 50 +++++++++++++++++++
 3 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 gcc/config/riscv/sfb.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 935eeb7fd8e..d020988446f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2711,24 +2711,6 @@
   DONE;
 })
 
-;; Patterns for implementations that optimize short forward branches.
-
-(define_insn "*mov<GPR:mode><X:mode>cc"
-  [(set (match_operand:GPR 0 "register_operand" "=r,r")
-	(if_then_else:GPR
-	 (match_operator 5 "ordered_comparison_operator"
-		[(match_operand:X 1 "register_operand" "r,r")
-		 (match_operand:X 2 "reg_or_0_operand" "rJ,rJ")])
-	 (match_operand:GPR 3 "register_operand" "0,0")
-	 (match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
-  "TARGET_SFB_ALU"
-  "@
-   b%C5\t%1,%z2,1f\t# movcc\;mv\t%0,%z4\n1:
-   b%C5\t%1,%z2,1f\t# movcc\;li\t%0,%4\n1:"
-  [(set_attr "length" "8")
-   (set_attr "type" "sfb_alu")
-   (set_attr "mode" "<GPR:MODE>")])
-
 ;; Used to implement built-in functions.
 (define_expand "condjump"
   [(set (pc)
@@ -3748,5 +3730,6 @@
 (include "generic-ooo.md")
 (include "vector.md")
 (include "zicond.md")
+(include "sfb.md")
 (include "zc.md")
 (include "corev.md")
diff --git a/gcc/config/riscv/sfb.md b/gcc/config/riscv/sfb.md
new file mode 100644
index 00000000000..52af4b17d46
--- /dev/null
+++ b/gcc/config/riscv/sfb.md
@@ -0,0 +1,37 @@
+;; Machine description for short forward branches(SFB).
+;; Copyright (C) 2023 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/>.
+
+
+;; Patterns for implementations that optimize short forward branches.
+
+(define_insn "*mov<GPR:mode><X:mode>cc"
+  [(set (match_operand:GPR 0 "register_operand" "=r,r")
+	(if_then_else:GPR
+	 (match_operator 5 "ordered_comparison_operator"
+		[(match_operand:X 1 "register_operand" "r,r")
+		 (match_operand:X 2 "reg_or_0_operand" "rJ,rJ")])
+	 (match_operand:GPR 3 "register_operand" "0,0")
+	 (match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
+  "TARGET_SFB_ALU"
+  "@
+   b%C5\t%1,%z2,1f\t# movcc\;mv\t%0,%z4\n1:
+   b%C5\t%1,%z2,1f\t# movcc\;li\t%0,%4\n1:"
+  [(set_attr "length" "8")
+   (set_attr "type" "sfb_alu")
+   (set_attr "mode" "<GPR:MODE>")])
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c b/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c
new file mode 100644
index 00000000000..2c60656d5eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-mtune=sifive-7-series -march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-mtune=sifive-7-series -march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og"} } */
+
+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 {\mczero\.eqz\M} 6 } } */
+/* { dg-final { scan-assembler-times {\mczero\.nez\M} 6 } } */
+/* { dg-final { scan-assembler-not {\mbeq\M} } } */
+/* { dg-final { scan-assembler-not {\mbne\M} } } */
+/* { dg-final { scan-assembler-not {\mmovcc\M} } } */
-- 
2.17.1


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

* [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns
  2023-11-28  2:32 [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Fei Gao
@ 2023-11-28  2:32 ` Fei Gao
  2023-11-29  5:26   ` Jeff Law
  2023-11-28  2:32 ` [PATCH 3/4] [ifcvt] optimize x=c ? (y op const_int) " Fei Gao
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Fei Gao @ 2023-11-28  2:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, zengxiao, Fei Gao

op=[PLUS, MINUS, IOR, XOR, ASHIFT, ASHIFTRT, LSHIFTRT, ROTATE, ROTATERT]

SIGN_EXTEND, ZERO_EXTEND and SUBREG has been considered
to support SImode in 64-bit machine.

Conditional op, if zero
rd = (rc == 0) ? (rs1 op rs2) : rs1
-->
czero.nez rd, rs2, rc
op rd, rs1, rd

Conditional op, if non-zero
rd = (rc != 0) ? (rs1 op rs2) : rs1
-->
czero.eqz rd, rs2, rc
op rd, rs1, rd

Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>

gcc/ChangeLog:

        * ifcvt.cc (noce_try_cond_zero_arith):handler for condtional zero based ifcvt
        (noce_emit_czero): helper for noce_try_cond_zero_arith
        (noce_cond_zero_binary_op_supported): check supported OPs for condtional zero based ifcvt
        (get_base_reg): get base reg of a subreg or the reg itself
        (noce_bbs_ok_for_cond_zero_arith): check if BBs are OK for condtional zero based ifcvt
        (noce_process_if_block): add noce_try_cond_zero_arith

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/zicond_ifcvt_opt.c: New test.
---
 gcc/ifcvt.cc                                  | 210 ++++++
 .../gcc.target/riscv/zicond_ifcvt_opt.c       | 682 ++++++++++++++++++
 2 files changed, 892 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index a0af553b9ff..8f6a0e7f5fe 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
 static bool noce_try_minmax (struct noce_if_info *);
 static bool noce_try_abs (struct noce_if_info *);
 static bool noce_try_sign_mask (struct noce_if_info *);
+static int noce_try_cond_zero_arith (struct noce_if_info *);
 
 /* Return the comparison code for reversed condition for IF_INFO,
    or UNKNOWN if reversing the condition is not possible.  */
@@ -1831,6 +1832,40 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
     return NULL_RTX;
 }
 
+/*  Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
+    IF_INFO describes the if-conversion scenario under consideration.
+    CZERO_CODE selects the condition (EQ/NE).
+    NON_ZERO_OP is the nonzero operand of the conditional move
+    TARGET is the desired output register.  */
+
+static rtx
+noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
+		 rtx non_zero_op, rtx target)
+{
+  machine_mode mode = GET_MODE (target);
+  rtx cond_op0 = XEXP (if_info->cond, 0);
+  rtx czero_cond
+    = gen_rtx_fmt_ee (czero_code, GET_MODE (cond_op0), cond_op0, const0_rtx);
+  rtx if_then_else
+    = gen_rtx_IF_THEN_ELSE (mode, czero_cond, const0_rtx, non_zero_op);
+  rtx set = gen_rtx_SET (target, 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 target;
+    }
+
+  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.  */
@@ -2880,6 +2915,178 @@ noce_try_sign_mask (struct noce_if_info *if_info)
   return true;
 }
 
+/*  Check if OP is supported by conditional zero based if conversion,
+    returning TRUE if satisfied otherwise FALSE.
+
+    OP is the operation to check.  */
+
+static bool
+noce_cond_zero_binary_op_supported (rtx op)
+{
+  enum rtx_code opcode = GET_CODE (op);
+
+  /* Strip SIGN_EXTEND or ZERO_EXTEND if any.  */
+  if (opcode == SIGN_EXTEND || opcode == ZERO_EXTEND)
+    opcode = GET_CODE (XEXP (op, 0));
+
+  if (opcode == PLUS || opcode == MINUS || opcode == IOR || opcode == XOR
+      || opcode == ASHIFT || opcode == ASHIFTRT || opcode == LSHIFTRT
+      || opcode == ROTATE || opcode == ROTATERT)
+    return true;
+
+  return false;
+}
+
+/*  Helper function to return REG itself or inner expression of a SUBREG,
+    otherwise NULL_RTX for other RTX_CODE.  */
+
+static rtx
+get_base_reg (rtx exp)
+{
+  if (REG_P (exp))
+    return exp;
+  else if (SUBREG_P (exp))
+    return SUBREG_REG (exp);
+
+  return NULL_RTX;
+}
+
+/*  Check if IF-BB and THEN-BB satisfy the condition for conditional zero
+    based if conversion, returning TRUE if satisfied otherwise FALSE.
+
+    IF_INFO describes the if-conversion scenario under consideration.
+    COMMON_PTR points to the common REG of canonicalized IF_INFO->A and
+    IF_INFO->B.
+    CZERO_CODE_PTR points to the comparison code to use in czero RTX.
+    A_PTR points to the A expression of canonicalized IF_INFO->A.
+    TO_REPLACE points to the RTX to be replaced by czero RTX destnation.  */
+
+static bool
+noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
+				 enum rtx_code *czero_code_ptr, rtx *a_ptr,
+				 rtx **to_replace)
+{
+  rtx common = NULL_RTX;
+  rtx cond = if_info->cond;
+  rtx a = copy_rtx (if_info->a);
+  rtx b = copy_rtx (if_info->b);
+  rtx bin_op1 = NULL_RTX;
+  enum rtx_code czero_code = UNKNOWN;
+  bool reverse = false;
+  rtx op0, op1, bin_exp;
+
+  if (!noce_simple_bbs (if_info))
+    return false;
+
+  /* COND must be EQ or NE comparision of a reg and 0.  */
+  if (GET_CODE (cond) != NE && GET_CODE (cond) != EQ)
+    return false;
+  if (!REG_P (XEXP (cond, 0)) || !rtx_equal_p (XEXP (cond, 1), const0_rtx))
+    return false;
+
+  /* Canonicalize x = y : (y op z) to x = (y op z) : y.  */
+  if (REG_P (a) && noce_cond_zero_binary_op_supported (b))
+    {
+      std::swap (a, b);
+      reverse = !reverse;
+    }
+
+  /* Check if x = (y op z) : y is supported by czero based ifcvt.  */
+  if (!(noce_cond_zero_binary_op_supported (a) && REG_P (b)))
+    return false;
+
+  /* Strip sign_extend if any.  */
+  if (GET_CODE (a) == SIGN_EXTEND || GET_CODE (a) == ZERO_EXTEND)
+    bin_exp = XEXP (a, 0);
+  else
+    bin_exp = a;
+
+  /* Canonicalize x = (z op y) : y to x = (y op z) : y */
+  op1 = get_base_reg (XEXP (bin_exp, 1));
+  if (op1 && rtx_equal_p (op1, b) && COMMUTATIVE_ARITH_P (bin_exp))
+    std::swap (XEXP (bin_exp, 0), XEXP (bin_exp, 1));
+
+  op0 = get_base_reg (XEXP (bin_exp, 0));
+  if (op0 && rtx_equal_p (op0, b))
+    {
+      common = b;
+      bin_op1 = XEXP (bin_exp, 1);
+      czero_code = reverse
+		     ? noce_reversed_cond_code (if_info)
+		     : GET_CODE (cond);
+    }
+  else
+    return false;
+
+  if (czero_code == UNKNOWN)
+    return false;
+
+  if (CONST_INT_P (bin_op1) || REG_P (bin_op1))
+    *to_replace = &XEXP (bin_exp, 1);
+  else if (SUBREG_P (bin_op1))
+    *to_replace = &SUBREG_REG (XEXP (bin_exp, 1));
+  else
+    return false;
+
+  *common_ptr = common;
+  *czero_code_ptr = czero_code;
+  *a_ptr = a;
+
+  return true;
+}
+
+/*  Try to covert if-then-else with conditional zero,
+    returning TURE on success or FALSE on failure.
+    IF_INFO describes the if-conversion scenario under consideration.  */
+
+static int
+noce_try_cond_zero_arith (struct noce_if_info *if_info)
+{
+  rtx target, a;
+  rtx_insn *seq;
+  machine_mode mode = GET_MODE (if_info->x);
+  rtx common = NULL_RTX;
+  enum rtx_code czero_code = UNKNOWN;
+  rtx non_zero_op = NULL_RTX;
+  rtx *to_replace = NULL;
+
+  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
+					&to_replace))
+    return false;
+
+  /* Disallow CONST_INT currently for simplicity*/
+  if (to_replace == NULL || !REG_P (*to_replace))
+    return false;
+
+  non_zero_op = *to_replace;
+
+  start_sequence ();
+
+  /* If x is used in both input and out like x = c ? x + z : x,
+     use a new reg to avoid modifying x  */
+  if (common && rtx_equal_p (common, if_info->x))
+    target = gen_reg_rtx (mode);
+  else
+    target = if_info->x;
+
+  target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
+  if (!target || !to_replace)
+    {
+      end_sequence ();
+      return false;
+    }
+
+  *to_replace = target;
+  emit_insn (gen_rtx_SET (if_info->x, a));
+
+  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_cond_zero_arith";
+  return true;
+}
 
 /* Optimize away "if (x & C) x |= C" and similar bit manipulation
    transformations.  */
@@ -3975,6 +4182,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_cond_zero_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_ifcvt_opt.c b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
new file mode 100644
index 00000000000..9357f26d978
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
@@ -0,0 +1,682 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbb_zicond -mabi=lp64d -O2 " } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-O3" "-Oz" "-flto"} } */
+
+long
+test_ADD_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x + z;
+
+  return x;
+}
+
+long
+test_ADD_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y + z;
+  return x;
+}
+
+long
+test_ADD_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x + z;
+  return x;
+}
+
+long
+test_ADD_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x + z;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y + z;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x + z;
+  return x;
+}
+
+long
+test_SUB_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y - z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x - z;
+
+  return x;
+}
+
+long
+test_SUB_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y - z;
+  return x;
+}
+
+long
+test_SUB_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x - z;
+  return x;
+}
+
+long
+test_SUB_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y - z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x - z;
+
+  return x;
+}
+
+long
+test_SUB_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y - z;
+  return x;
+}
+
+long
+test_SUB_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x - z;
+  return x;
+}
+
+long
+test_IOR_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y | z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x | z;
+
+  return x;
+}
+
+long
+test_IOR_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y | z;
+  return x;
+}
+
+long
+test_IOR_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x | z;
+  return x;
+}
+
+long
+test_IOR_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y | z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x | z;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y | z;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x | z;
+  return x;
+}
+
+long
+test_XOR_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y ^ z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x ^ z;
+
+  return x;
+}
+
+long
+test_XOR_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y ^ z;
+  return x;
+}
+
+long
+test_XOR_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x ^ z;
+  return x;
+}
+
+long
+test_XOR_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y ^ z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x ^ z;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y ^ z;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x ^ z;
+  return x;
+}
+
+long
+test_ADD_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z + x;
+
+  return x;
+}
+
+long
+test_ADD_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z + y;
+  return x;
+}
+
+long
+test_ADD_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z + x;
+  return x;
+}
+
+long
+test_ADD_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z + x;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z + y;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z + x;
+  return x;
+}
+
+long
+test_IOR_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z | x;
+
+  return x;
+}
+
+long
+test_IOR_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z | y;
+  return x;
+}
+
+long
+test_IOR_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z | x;
+  return x;
+}
+
+long
+test_IOR_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z | x;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z | y;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z | x;
+  return x;
+}
+
+long
+test_XOR_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z ^ x;
+
+  return x;
+}
+
+long
+test_XOR_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z ^ y;
+  return x;
+}
+
+long
+test_XOR_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z ^ x;
+  return x;
+}
+
+long
+test_XOR_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z ^ x;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z ^ y;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z ^ x;
+  return x;
+}
+
+long
+test_ShiftLeft_eqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y << z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ShiftR_eqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_ShiftR_logical_eqz (unsigned long x, unsigned long y, unsigned long z,
+			 unsigned long c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateL_eqz (unsigned long x, unsigned long y, unsigned long z,
+		  unsigned long c)
+{
+  if (c)
+    x = (y << z) | (y >> (64 - z));
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateR_eqz (unsigned long x, unsigned long y, unsigned long z,
+		  unsigned long c)
+{
+  if (c)
+    x = (y >> z) | (y << (64 - z));
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ADD_ceqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftLeft_eqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y << z;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftR_eqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_ShiftR_logical_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+			     unsigned int c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateL_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+		      unsigned int c)
+{
+  if (c)
+    x = (y << z) | (y >> (32 - z));
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateR_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+		      unsigned int c)
+{
+  if (c)
+    x = (y >> z) | (y << (32 - z));
+  else
+    x = y;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times {czero\.eqz} 39 } } */
+/* { dg-final { scan-assembler-times {czero\.nez} 28 } } */
-- 
2.17.1


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

* [PATCH 3/4] [ifcvt] optimize x=c ? (y op const_int) : y by RISC-V Zicond like insns
  2023-11-28  2:32 [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Fei Gao
  2023-11-28  2:32 ` [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns Fei Gao
@ 2023-11-28  2:32 ` Fei Gao
  2023-11-28  2:32 ` [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y Fei Gao
  2023-11-28  3:09 ` [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Kito Cheng
  3 siblings, 0 replies; 11+ messages in thread
From: Fei Gao @ 2023-11-28  2:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, zengxiao, Fei Gao

op=[PLUS, MINUS, IOR, XOR, ASHIFT, ASHIFTRT, LSHIFTRT, ROTATE, ROTATERT]

Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>

gcc/ChangeLog:

        * ifcvt.cc (noce_cond_zero_shift_op_supported): check if OP is shift like operation
        (noce_cond_zero_binary_op_supported): restructure & call noce_cond_zero_shift_op_supported
        (noce_bbs_ok_for_cond_zero_arith): add bin_exp_ptr interface
        (noce_try_cond_zero_arith): add support for x=c ? (y op const_int)

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/zicond_ifcvt_opt.c: add TCs for x=c ? (y op const_int) : y
---
 gcc/ifcvt.cc                                  |  53 +-
 .../gcc.target/riscv/zicond_ifcvt_opt.c       | 675 +++++++++++++++++-
 2 files changed, 716 insertions(+), 12 deletions(-)

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 8f6a0e7f5fe..4cc6a125ff0 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -2920,6 +2920,16 @@ noce_try_sign_mask (struct noce_if_info *if_info)
 
     OP is the operation to check.  */
 
+static bool
+noce_cond_zero_shift_op_supported (enum rtx_code op)
+{
+  if (op == ASHIFT || op == ASHIFTRT || op == LSHIFTRT || op == ROTATE
+      || op == ROTATERT)
+    return true;
+
+  return false;
+}
+
 static bool
 noce_cond_zero_binary_op_supported (rtx op)
 {
@@ -2930,8 +2940,7 @@ noce_cond_zero_binary_op_supported (rtx op)
     opcode = GET_CODE (XEXP (op, 0));
 
   if (opcode == PLUS || opcode == MINUS || opcode == IOR || opcode == XOR
-      || opcode == ASHIFT || opcode == ASHIFTRT || opcode == LSHIFTRT
-      || opcode == ROTATE || opcode == ROTATERT)
+      || noce_cond_zero_shift_op_supported (opcode))
     return true;
 
   return false;
@@ -2963,6 +2972,7 @@ get_base_reg (rtx exp)
 
 static bool
 noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
+				 rtx *bin_exp_ptr,
 				 enum rtx_code *czero_code_ptr, rtx *a_ptr,
 				 rtx **to_replace)
 {
@@ -3029,6 +3039,7 @@ noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr,
     return false;
 
   *common_ptr = common;
+  *bin_exp_ptr = bin_exp;
   *czero_code_ptr = czero_code;
   *a_ptr = a;
 
@@ -3047,20 +3058,28 @@ noce_try_cond_zero_arith (struct noce_if_info *if_info)
   machine_mode mode = GET_MODE (if_info->x);
   rtx common = NULL_RTX;
   enum rtx_code czero_code = UNKNOWN;
+  rtx bin_exp = NULL_RTX;
+  enum rtx_code bin_code = UNKNOWN;
+  rtx bin_op0 = NULL_RTX;
   rtx non_zero_op = NULL_RTX;
   rtx *to_replace = NULL;
 
-  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
-					&to_replace))
+  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &bin_exp, &czero_code,
+					&a, &to_replace))
     return false;
 
-  /* Disallow CONST_INT currently for simplicity*/
-  if (to_replace == NULL || !REG_P (*to_replace))
-    return false;
+  start_sequence ();
 
-  non_zero_op = *to_replace;
+  bin_code = GET_CODE (bin_exp);
+  bin_op0 = XEXP (bin_exp, 0);
 
-  start_sequence ();
+  if (CONST_INT_P (*to_replace))
+    {
+      non_zero_op = gen_reg_rtx (mode);
+      noce_emit_move_insn (non_zero_op, *to_replace);
+    }
+  else
+    non_zero_op = *to_replace;
 
   /* If x is used in both input and out like x = c ? x + z : x,
      use a new reg to avoid modifying x  */
@@ -3076,7 +3095,21 @@ noce_try_cond_zero_arith (struct noce_if_info *if_info)
       return false;
     }
 
-  *to_replace = target;
+  if (CONST_INT_P (*to_replace))
+    {
+      if (noce_cond_zero_shift_op_supported (bin_code))
+	{
+	  *to_replace = gen_rtx_SUBREG (E_QImode, target, 0);
+	  if (GET_CODE (a) == ZERO_EXTEND && bin_code == LSHIFTRT)
+	    PUT_CODE (a, SIGN_EXTEND);
+	}
+      else if (SUBREG_P (bin_op0))
+	*to_replace = gen_rtx_SUBREG (GET_MODE (bin_op0), target, 0);
+      else
+	*to_replace = target;
+    }
+  else
+    *to_replace = target;
   emit_insn (gen_rtx_SET (if_info->x, a));
 
   seq = end_ifcvt_sequence (if_info);
diff --git a/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
index 9357f26d978..c6b0518968b 100644
--- a/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
+++ b/gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
@@ -678,5 +678,676 @@ test_RotateR_eqz_int (unsigned int x, unsigned int y, unsigned int z,
   return x;
 }
 
-/* { dg-final { scan-assembler-times {czero\.eqz} 39 } } */
-/* { dg-final { scan-assembler-times {czero\.nez} 28 } } */
+long
+test_ADD_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x + 11;
+
+  return x;
+}
+
+long
+test_ADD_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y + 11;
+  return x;
+}
+
+long
+test_ADD_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x + 11;
+  return x;
+}
+
+long
+test_ADD_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x + 11;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y + 11;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x + 11;
+  return x;
+}
+
+long
+test_SUB_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y - 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x - 11;
+
+  return x;
+}
+
+long
+test_SUB_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y - 11;
+  return x;
+}
+
+long
+test_SUB_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x - 11;
+  return x;
+}
+
+long
+test_SUB_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y - 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x - 11;
+
+  return x;
+}
+
+long
+test_SUB_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y - 11;
+  return x;
+}
+
+long
+test_SUB_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x - 11;
+  return x;
+}
+
+long
+test_IOR_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y | 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x | 11;
+
+  return x;
+}
+
+long
+test_IOR_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y | 11;
+  return x;
+}
+
+long
+test_IOR_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x | 11;
+  return x;
+}
+
+long
+test_IOR_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y | 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x | 11;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y | 11;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x | 11;
+  return x;
+}
+
+long
+test_XOR_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y ^ 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x ^ 11;
+
+  return x;
+}
+
+long
+test_XOR_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y ^ 11;
+  return x;
+}
+
+long
+test_XOR_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x ^ 11;
+  return x;
+}
+
+long
+test_XOR_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y ^ 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x ^ 11;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y ^ 11;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x ^ 11;
+  return x;
+}
+
+long
+test_ADD_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 + x;
+
+  return x;
+}
+
+long
+test_ADD_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 + y;
+  return x;
+}
+
+long
+test_ADD_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 + x;
+  return x;
+}
+
+long
+test_ADD_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 + x;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 + y;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 + x;
+  return x;
+}
+
+long
+test_IOR_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 | x;
+
+  return x;
+}
+
+long
+test_IOR_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 | y;
+  return x;
+}
+
+long
+test_IOR_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 | x;
+  return x;
+}
+
+long
+test_IOR_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 | x;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 | y;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 | x;
+  return x;
+}
+
+long
+test_XOR_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 ^ x;
+
+  return x;
+}
+
+long
+test_XOR_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 ^ y;
+  return x;
+}
+
+long
+test_XOR_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 ^ x;
+  return x;
+}
+
+long
+test_XOR_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 ^ x;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 ^ y;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 ^ x;
+  return x;
+}
+
+long
+test_ShiftLeft_eqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y << 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ShiftR_eqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_ShiftR_logical_eqz_imm (unsigned long x, unsigned long y, unsigned long z,
+			     unsigned long c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateL_eqz_imm (unsigned long x, unsigned long y, unsigned long c)
+{
+  if (c)
+    x = (y << 11) | (y >> (64 - 11));
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateR_eqz_imm (unsigned long x, unsigned long y, unsigned long c)
+{
+  if (c)
+    x = (y >> 11) | (y << (64 - 11));
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ADD_ceqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftLeft_eqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y << 11;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftR_eqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_ShiftR_logical_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateL_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = (y << 11) | (y >> (32 - 11));
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateR_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = (y >> 11) | (y << (32 - 11));
+  else
+    x = y;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times {czero\.eqz} 78 } } */
+/* { dg-final { scan-assembler-times {czero\.nez} 56 } } */
-- 
2.17.1


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

* [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y.
  2023-11-28  2:32 [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Fei Gao
  2023-11-28  2:32 ` [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns Fei Gao
  2023-11-28  2:32 ` [PATCH 3/4] [ifcvt] optimize x=c ? (y op const_int) " Fei Gao
@ 2023-11-28  2:32 ` Fei Gao
  2023-11-28  5:00   ` Jeff Law
  2023-11-28  3:09 ` [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Kito Cheng
  3 siblings, 1 reply; 11+ messages in thread
From: Fei Gao @ 2023-11-28  2:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, palmer, jeffreyalaw, zengxiao, Fei Gao

In x=c ? (y op CONST) : y cases, Zicond based czero ifcvt generates
more true dependency in code sequence than SFB based movcc. So exit
noce_try_cond_zero_arith in such cases to have a better code sequence
generated by noce_try_cmove_arith.

Take the following case for example.

CFLAGS: -mtune=sifive-7-series -march=rv64gc_zbb_zicond -mabi=lp64d -O2

unsigned int
test_RotateR_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
{
  if (c)
    x = (y >> 11) | (y << (32 - 11));
  else
    x = y;
  return x;
}

before patch:
	li	a5,11
	czero.eqz	a2,a5,a2
	rorw	a0,a1,a2
	ret

after patch:
	roriw	a0,a1,11
	bne	a2,zero,1f	# movcc
	mv	a0,a1
1:
	ret

Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_have_sfb): hook implementation
        (TARGET_HAVE_SFB): define hook in riscv
        * doc/tm.texi: add TARGET_HAVE_SFB
        * doc/tm.texi.in: add TARGET_HAVE_SFB
        * ifcvt.cc (noce_try_cond_zero_arith): prefer SFB for x=c ? (y op CONST) : y
        * target.def:add TARGET_HAVE_SFB

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/zicond_sfb_ifcvt_opt.c: New test.
---
 gcc/config/riscv/riscv.cc                     |   12 +
 gcc/doc/tm.texi                               |    4 +
 gcc/doc/tm.texi.in                            |    2 +
 gcc/ifcvt.cc                                  |    4 +-
 gcc/target.def                                |    7 +
 .../gcc.target/riscv/zicond_sfb_ifcvt_opt.c   | 1354 +++++++++++++++++
 6 files changed, 1382 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_sfb_ifcvt_opt.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d0efb939bf2..91fb4ebd653 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -10191,6 +10191,14 @@ riscv_vectorize_related_mode (machine_mode vector_mode, scalar_mode element_mode
   return default_vectorize_related_mode (vector_mode, element_mode, nunits);
 }
 
+/* Implement TARGET_HAVE_SFB.  */
+
+bool
+riscv_have_sfb (void)
+{
+  return TARGET_SFB_ALU;
+}
+
 /* Implement TARGET_VECTORIZE_VEC_PERM_CONST.  */
 
 static bool
@@ -10536,6 +10544,10 @@ extract_base_offset_in_addr (rtx mem, rtx *base, rtx *offset)
 #define TARGET_DEFAULT_TARGET_FLAGS (MASK_BIG_ENDIAN)
 #endif
 
+#undef TARGET_HAVE_SFB
+#define TARGET_HAVE_SFB \
+        riscv_have_sfb
+
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P riscv_vector_mode_supported_p
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 645559ea084..9b4e3f71569 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -12149,6 +12149,10 @@ This target hook is required only when the target has several different
 modes and they have different conditional execution capability, such as ARM.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_HAVE_SFB (void)
+This target hook returns true if the target supports Short Forward Branch.
+@end deftypefn
+
 @deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, rtx_code @var{code}, tree @var{op0}, tree @var{op1})
 This function prepares to emit a comparison insn for the first compare in a
  sequence of conditional comparisions.  It returns an appropriate comparison
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 4ddc8507ed9..6dac432605f 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7843,6 +7843,8 @@ lists.
 
 @hook TARGET_HAVE_CONDITIONAL_EXECUTION
 
+@hook TARGET_HAVE_SFB
+
 @hook TARGET_GEN_CCMP_FIRST
 
 @hook TARGET_GEN_CCMP_NEXT
diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index 4cc6a125ff0..c0f42a7ab1f 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -3068,10 +3068,12 @@ noce_try_cond_zero_arith (struct noce_if_info *if_info)
 					&a, &to_replace))
     return false;
 
-  start_sequence ();
+  if (targetm.have_sfb () && CONST_INT_P (*to_replace))
+    return false;
 
   bin_code = GET_CODE (bin_exp);
   bin_op0 = XEXP (bin_exp, 0);
+  start_sequence ();
 
   if (CONST_INT_P (*to_replace))
     {
diff --git a/gcc/target.def b/gcc/target.def
index 475c55c22c1..6d9b71e165b 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2726,6 +2726,13 @@ modes and they have different conditional execution capability, such as ARM.",
  bool, (void),
  default_have_conditional_execution)
 
+/* Return true if the target supports SFB.  */
+DEFHOOK
+(have_sfb,
+ "This target hook returns true if the target supports Short Forward Branch.",
+ bool, (void),
+ hook_bool_void_false)
+
 DEFHOOK
 (gen_ccmp_first,
  "This function prepares to emit a comparison insn for the first compare in a\n\
diff --git a/gcc/testsuite/gcc.target/riscv/zicond_sfb_ifcvt_opt.c b/gcc/testsuite/gcc.target/riscv/zicond_sfb_ifcvt_opt.c
new file mode 100644
index 00000000000..a9cad788956
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zicond_sfb_ifcvt_opt.c
@@ -0,0 +1,1354 @@
+/* { dg-do compile } */
+/* { dg-options "-mtune=sifive-7-series -march=rv64gc_zbb_zicond -mabi=lp64d -O2 " } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-O3" "-Oz" "-flto"} } */
+
+long
+test_ADD_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x + z;
+
+  return x;
+}
+
+long
+test_ADD_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y + z;
+  return x;
+}
+
+long
+test_ADD_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x + z;
+  return x;
+}
+
+long
+test_ADD_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x + z;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y + z;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x + z;
+  return x;
+}
+
+long
+test_SUB_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y - z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x - z;
+
+  return x;
+}
+
+long
+test_SUB_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y - z;
+  return x;
+}
+
+long
+test_SUB_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x - z;
+  return x;
+}
+
+long
+test_SUB_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y - z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x - z;
+
+  return x;
+}
+
+long
+test_SUB_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y - z;
+  return x;
+}
+
+long
+test_SUB_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x - z;
+  return x;
+}
+
+long
+test_IOR_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y | z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x | z;
+
+  return x;
+}
+
+long
+test_IOR_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y | z;
+  return x;
+}
+
+long
+test_IOR_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x | z;
+  return x;
+}
+
+long
+test_IOR_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y | z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x | z;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y | z;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x | z;
+  return x;
+}
+
+long
+test_XOR_ceqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y ^ z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x (long x, long z, long c)
+{
+  if (c)
+    x = x ^ z;
+
+  return x;
+}
+
+long
+test_XOR_nez (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y ^ z;
+  return x;
+}
+
+long
+test_XOR_nez_x (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x ^ z;
+  return x;
+}
+
+long
+test_XOR_nez_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y ^ z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2 (long x, long z, long c)
+{
+  if (!c)
+    x = x ^ z;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2 (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y ^ z;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2 (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x ^ z;
+  return x;
+}
+
+long
+test_ADD_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z + x;
+
+  return x;
+}
+
+long
+test_ADD_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z + y;
+  return x;
+}
+
+long
+test_ADD_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z + x;
+  return x;
+}
+
+long
+test_ADD_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z + x;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z + y;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z + x;
+  return x;
+}
+
+long
+test_IOR_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z | x;
+
+  return x;
+}
+
+long
+test_IOR_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z | y;
+  return x;
+}
+
+long
+test_IOR_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z | x;
+  return x;
+}
+
+long
+test_IOR_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z | x;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z | y;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z | x;
+  return x;
+}
+
+long
+test_XOR_ceqz_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = z ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    x = z ^ x;
+
+  return x;
+}
+
+long
+test_XOR_nez_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = z ^ y;
+  return x;
+}
+
+long
+test_XOR_nez_x_reverse_bin_oprands (long x, long z, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = z ^ x;
+  return x;
+}
+
+long
+test_XOR_nez_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = z ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    x = z ^ x;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_reverse_bin_oprands (long x, long y, long z, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = z ^ y;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_reverse_bin_oprands (long x, long z, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = z ^ x;
+  return x;
+}
+
+long
+test_ShiftLeft_eqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y << z;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ShiftR_eqz (long x, long y, long z, long c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_ShiftR_logical_eqz (unsigned long x, unsigned long y, unsigned long z,
+			 unsigned long c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateL_eqz (unsigned long x, unsigned long y, unsigned long z,
+		  unsigned long c)
+{
+  if (c)
+    x = (y << z) | (y >> (64 - z));
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateR_eqz (unsigned long x, unsigned long y, unsigned long z,
+		  unsigned long c)
+{
+  if (c)
+    x = (y >> z) | (y << (64 - z));
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ADD_ceqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y + z;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftLeft_eqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y << z;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftR_eqz_int (int x, int y, int z, int c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_ShiftR_logical_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+			     unsigned int c)
+{
+  if (c)
+    x = y >> z;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateL_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+		      unsigned int c)
+{
+  if (c)
+    x = (y << z) | (y >> (32 - z));
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateR_eqz_int (unsigned int x, unsigned int y, unsigned int z,
+		      unsigned int c)
+{
+  if (c)
+    x = (y >> z) | (y << (32 - z));
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x + 11;
+
+  return x;
+}
+
+long
+test_ADD_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y + 11;
+  return x;
+}
+
+long
+test_ADD_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x + 11;
+  return x;
+}
+
+long
+test_ADD_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x + 11;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y + 11;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x + 11;
+  return x;
+}
+
+long
+test_SUB_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y - 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x - 11;
+
+  return x;
+}
+
+long
+test_SUB_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y - 11;
+  return x;
+}
+
+long
+test_SUB_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x - 11;
+  return x;
+}
+
+long
+test_SUB_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y - 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_SUB_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x - 11;
+
+  return x;
+}
+
+long
+test_SUB_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y - 11;
+  return x;
+}
+
+long
+test_SUB_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x - 11;
+  return x;
+}
+
+long
+test_IOR_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y | 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x | 11;
+
+  return x;
+}
+
+long
+test_IOR_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y | 11;
+  return x;
+}
+
+long
+test_IOR_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x | 11;
+  return x;
+}
+
+long
+test_IOR_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y | 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x | 11;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y | 11;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x | 11;
+  return x;
+}
+
+long
+test_XOR_ceqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y ^ 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_imm (long x, long c)
+{
+  if (c)
+    x = x ^ 11;
+
+  return x;
+}
+
+long
+test_XOR_nez_imm (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = y ^ 11;
+  return x;
+}
+
+long
+test_XOR_nez_x_imm (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = x ^ 11;
+  return x;
+}
+
+long
+test_XOR_nez_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y ^ 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_imm (long x, long c)
+{
+  if (!c)
+    x = x ^ 11;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_imm (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = y ^ 11;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_imm (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = x ^ 11;
+  return x;
+}
+
+long
+test_ADD_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 + x;
+
+  return x;
+}
+
+long
+test_ADD_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 + y;
+  return x;
+}
+
+long
+test_ADD_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 + x;
+  return x;
+}
+
+long
+test_ADD_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 + y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ADD_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 + x;
+
+  return x;
+}
+
+long
+test_ADD_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 + y;
+  return x;
+}
+
+long
+test_ADD_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 + x;
+  return x;
+}
+
+long
+test_IOR_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 | x;
+
+  return x;
+}
+
+long
+test_IOR_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 | y;
+  return x;
+}
+
+long
+test_IOR_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 | x;
+  return x;
+}
+
+long
+test_IOR_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 | y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_IOR_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 | x;
+
+  return x;
+}
+
+long
+test_IOR_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 | y;
+  return x;
+}
+
+long
+test_IOR_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 | x;
+  return x;
+}
+
+long
+test_XOR_ceqz_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = 11 ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_ceqz_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    x = 11 ^ x;
+
+  return x;
+}
+
+long
+test_XOR_nez_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (c)
+    x = y;
+  else
+    x = 11 ^ y;
+  return x;
+}
+
+long
+test_XOR_nez_x_imm_reverse_bin_oprands (long x, long c)
+{
+  if (c)
+    {
+    }
+  else
+    x = 11 ^ x;
+  return x;
+}
+
+long
+test_XOR_nez_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = 11 ^ y;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_XOR_nez_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    x = 11 ^ x;
+
+  return x;
+}
+
+long
+test_XOR_eqz_2_imm_reverse_bin_oprands (long x, long y, long c)
+{
+  if (!c)
+    x = y;
+  else
+    x = 11 ^ y;
+  return x;
+}
+
+long
+test_XOR_eqz_x_2_imm_reverse_bin_oprands (long x, long c)
+{
+  if (!c)
+    {
+    }
+  else
+    x = 11 ^ x;
+  return x;
+}
+
+long
+test_ShiftLeft_eqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y << 11;
+  else
+    x = y;
+  return x;
+}
+
+long
+test_ShiftR_eqz_imm (long x, long y, long c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_ShiftR_logical_eqz_imm (unsigned long x, unsigned long y, unsigned long z,
+			     unsigned long c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateL_eqz_imm (unsigned long x, unsigned long y, unsigned long c)
+{
+  if (c)
+    x = (y << 11) | (y >> (64 - 11));
+  else
+    x = y;
+  return x;
+}
+
+unsigned long
+test_RotateR_eqz_imm (unsigned long x, unsigned long y, unsigned long c)
+{
+  if (c)
+    x = (y >> 11) | (y << (64 - 11));
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ADD_ceqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y + 11;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftLeft_eqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y << 11;
+  else
+    x = y;
+  return x;
+}
+
+int
+test_ShiftR_eqz_imm_int (int x, int y, int c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_ShiftR_logical_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = y >> 11;
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateL_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = (y << 11) | (y >> (32 - 11));
+  else
+    x = y;
+  return x;
+}
+
+unsigned int
+test_RotateR_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
+{
+  if (c)
+    x = (y >> 11) | (y << (32 - 11));
+  else
+    x = y;
+  return x;
+}
+
+/* { dg-final { scan-assembler-times {czero\.eqz} 39 } } */
+/* { dg-final { scan-assembler-times {czero\.nez} 28 } } */
+/* { dg-final { scan-assembler-times {movcc} 67 } } */
-- 
2.17.1


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

* Re: [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB
  2023-11-28  2:32 [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Fei Gao
                   ` (2 preceding siblings ...)
  2023-11-28  2:32 ` [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y Fei Gao
@ 2023-11-28  3:09 ` Kito Cheng
  2023-11-28  5:03   ` Jeff Law
  3 siblings, 1 reply; 11+ messages in thread
From: Kito Cheng @ 2023-11-28  3:09 UTC (permalink / raw)
  To: Fei Gao; +Cc: gcc-patches, palmer, jeffreyalaw, zengxiao

Personally I don't like to play with the pattern order to tweak the
code gen since it kinda introduces implicit relation/rule here, but I
guess the only way to prevent that is to duplicate the pattern for SFB
again, which is not an ideal solution...

Anyway, it's obviously a better code gen, so LGTM :)

On Tue, Nov 28, 2023 at 10:33 AM Fei Gao <gaofei@eswincomputing.com> wrote:
>
> Move Zicond md files ahead of SFB to recognize Zicond first.
>
> Take the following case for example.
>
> CFLAGS: -mtune=sifive-7-series -march=rv64gc_zicond -mabi=lp64d
>
> long primitiveSemantics_00(long a, long b) { return a == 0 ? 0 : b; }
>
> before patch:
> primitiveSemantics_00:
>         bne     a0,zero,1f      # movcc
>         mv      a1,zero
> 1:
>         mv      a0,a1
>         ret
>
> after patch:
> primitiveSemantics_00:
>         czero.eqz       a0,a1,a0
>         ret
>
> Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>
>
> gcc/ChangeLog:
>
>         * config/riscv/riscv.md (*mov<GPR:mode><X:mode>cc):move to sfb.md
>         * config/riscv/sfb.md: New file.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/zicond-sfb-primitiveSemantics.c: New test.
> ---
>  gcc/config/riscv/riscv.md                     | 19 +------
>  gcc/config/riscv/sfb.md                       | 37 ++++++++++++++
>  .../riscv/zicond-sfb-primitiveSemantics.c     | 50 +++++++++++++++++++
>  3 files changed, 88 insertions(+), 18 deletions(-)
>  create mode 100644 gcc/config/riscv/sfb.md
>  create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c
>
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 935eeb7fd8e..d020988446f 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -2711,24 +2711,6 @@
>    DONE;
>  })
>
> -;; Patterns for implementations that optimize short forward branches.
> -
> -(define_insn "*mov<GPR:mode><X:mode>cc"
> -  [(set (match_operand:GPR 0 "register_operand" "=r,r")
> -       (if_then_else:GPR
> -        (match_operator 5 "ordered_comparison_operator"
> -               [(match_operand:X 1 "register_operand" "r,r")
> -                (match_operand:X 2 "reg_or_0_operand" "rJ,rJ")])
> -        (match_operand:GPR 3 "register_operand" "0,0")
> -        (match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
> -  "TARGET_SFB_ALU"
> -  "@
> -   b%C5\t%1,%z2,1f\t# movcc\;mv\t%0,%z4\n1:
> -   b%C5\t%1,%z2,1f\t# movcc\;li\t%0,%4\n1:"
> -  [(set_attr "length" "8")
> -   (set_attr "type" "sfb_alu")
> -   (set_attr "mode" "<GPR:MODE>")])
> -
>  ;; Used to implement built-in functions.
>  (define_expand "condjump"
>    [(set (pc)
> @@ -3748,5 +3730,6 @@
>  (include "generic-ooo.md")
>  (include "vector.md")
>  (include "zicond.md")
> +(include "sfb.md")
>  (include "zc.md")
>  (include "corev.md")
> diff --git a/gcc/config/riscv/sfb.md b/gcc/config/riscv/sfb.md
> new file mode 100644
> index 00000000000..52af4b17d46
> --- /dev/null
> +++ b/gcc/config/riscv/sfb.md
> @@ -0,0 +1,37 @@
> +;; Machine description for short forward branches(SFB).
> +;; Copyright (C) 2023 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/>.
> +
> +
> +;; Patterns for implementations that optimize short forward branches.
> +
> +(define_insn "*mov<GPR:mode><X:mode>cc"
> +  [(set (match_operand:GPR 0 "register_operand" "=r,r")
> +       (if_then_else:GPR
> +        (match_operator 5 "ordered_comparison_operator"
> +               [(match_operand:X 1 "register_operand" "r,r")
> +                (match_operand:X 2 "reg_or_0_operand" "rJ,rJ")])
> +        (match_operand:GPR 3 "register_operand" "0,0")
> +        (match_operand:GPR 4 "sfb_alu_operand" "rJ,IL")))]
> +  "TARGET_SFB_ALU"
> +  "@
> +   b%C5\t%1,%z2,1f\t# movcc\;mv\t%0,%z4\n1:
> +   b%C5\t%1,%z2,1f\t# movcc\;li\t%0,%4\n1:"
> +  [(set_attr "length" "8")
> +   (set_attr "type" "sfb_alu")
> +   (set_attr "mode" "<GPR:MODE>")])
> diff --git a/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c b/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c
> new file mode 100644
> index 00000000000..2c60656d5eb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/zicond-sfb-primitiveSemantics.c
> @@ -0,0 +1,50 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mtune=sifive-7-series -march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
> +/* { dg-options "-mtune=sifive-7-series -march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
> +/* { dg-skip-if "" { *-*-* } {"-O0" "-Og"} } */
> +
> +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 {\mczero\.eqz\M} 6 } } */
> +/* { dg-final { scan-assembler-times {\mczero\.nez\M} 6 } } */
> +/* { dg-final { scan-assembler-not {\mbeq\M} } } */
> +/* { dg-final { scan-assembler-not {\mbne\M} } } */
> +/* { dg-final { scan-assembler-not {\mmovcc\M} } } */
> --
> 2.17.1
>

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

* Re: [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y.
  2023-11-28  2:32 ` [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y Fei Gao
@ 2023-11-28  5:00   ` Jeff Law
  0 siblings, 0 replies; 11+ messages in thread
From: Jeff Law @ 2023-11-28  5:00 UTC (permalink / raw)
  To: Fei Gao, gcc-patches; +Cc: kito.cheng, palmer, zengxiao



On 11/27/23 19:32, Fei Gao wrote:
> In x=c ? (y op CONST) : y cases, Zicond based czero ifcvt generates
> more true dependency in code sequence than SFB based movcc. So exit
> noce_try_cond_zero_arith in such cases to have a better code sequence
> generated by noce_try_cmove_arith.
> 
> Take the following case for example.
> 
> CFLAGS: -mtune=sifive-7-series -march=rv64gc_zbb_zicond -mabi=lp64d -O2
> 
> unsigned int
> test_RotateR_eqz_imm_int (unsigned int x, unsigned int y, unsigned int c)
> {
>    if (c)
>      x = (y >> 11) | (y << (32 - 11));
>    else
>      x = y;
>    return x;
> }
> 
> before patch:
> 	li	a5,11
> 	czero.eqz	a2,a5,a2
> 	rorw	a0,a1,a2
> 	ret
> 
> after patch:
> 	roriw	a0,a1,11
> 	bne	a2,zero,1f	# movcc
> 	mv	a0,a1
> 1:
> 	ret
> 
> Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>
> 
> gcc/ChangeLog:
> 
>          * config/riscv/riscv.cc (riscv_have_sfb): hook implementation
>          (TARGET_HAVE_SFB): define hook in riscv
>          * doc/tm.texi: add TARGET_HAVE_SFB
>          * doc/tm.texi.in: add TARGET_HAVE_SFB
>          * ifcvt.cc (noce_try_cond_zero_arith): prefer SFB for x=c ? (y op CONST) : y
>          * target.def:add TARGET_HAVE_SFB
This is not OK.  It's basically a target #if.  It's not significantly 
different than the original kit which had a hook to prefer czero over 
other forms.


Selection between the two forms should be drive by the target cost 
modeling and expansion code.  Using a hook like this isn't acceptable.


Jeff

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

* Re: [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB
  2023-11-28  3:09 ` [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Kito Cheng
@ 2023-11-28  5:03   ` Jeff Law
  2023-12-04  7:01     ` Fei Gao
  0 siblings, 1 reply; 11+ messages in thread
From: Jeff Law @ 2023-11-28  5:03 UTC (permalink / raw)
  To: Kito Cheng, Fei Gao; +Cc: gcc-patches, palmer, zengxiao



On 11/27/23 20:09, Kito Cheng wrote:
> Personally I don't like to play with the pattern order to tweak the
> code gen since it kinda introduces implicit relation/rule here, but I
> guess the only way to prevent that is to duplicate the pattern for SFB
> again, which is not an ideal solution...
I won't object to this patch, but I don't really like it either.

This patch highlights that the SFB code is not well integrated with the 
rest of the conditional move support.

Jeff

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

* Re: [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns
  2023-11-28  2:32 ` [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns Fei Gao
@ 2023-11-29  5:26   ` Jeff Law
  2023-11-29 11:09     ` Fei Gao
  0 siblings, 1 reply; 11+ messages in thread
From: Jeff Law @ 2023-11-29  5:26 UTC (permalink / raw)
  To: Fei Gao, gcc-patches; +Cc: kito.cheng, palmer, zengxiao



On 11/27/23 19:32, Fei Gao wrote:
> op=[PLUS, MINUS, IOR, XOR, ASHIFT, ASHIFTRT, LSHIFTRT, ROTATE, ROTATERT]
> 
> SIGN_EXTEND, ZERO_EXTEND and SUBREG has been considered
> to support SImode in 64-bit machine.
Let's defer these for now.  We're supposed to be wrapping up work that 
was posted before stage1 closed.  If these opcodes were trivial to 
support, then I would let them through, but SUBREGs for example can be 
problematical as their semantics can be complex.


> 
> Conditional op, if zero
> rd = (rc == 0) ? (rs1 op rs2) : rs1
> -->
> czero.nez rd, rs2, rc
> op rd, rs1, rd
> 
> Conditional op, if non-zero
> rd = (rc != 0) ? (rs1 op rs2) : rs1
> -->
> czero.eqz rd, rs2, rc
> op rd, rs1, rd
> 
> Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>
> 
> gcc/ChangeLog:
> 
>          * ifcvt.cc (noce_try_cond_zero_arith):handler for condtional zero based ifcvt
>          (noce_emit_czero): helper for noce_try_cond_zero_arith
>          (noce_cond_zero_binary_op_supported): check supported OPs for condtional zero based ifcvt
>          (get_base_reg): get base reg of a subreg or the reg itself
>          (noce_bbs_ok_for_cond_zero_arith): check if BBs are OK for condtional zero based ifcvt
>          (noce_process_if_block): add noce_try_cond_zero_arith
> 
> gcc/testsuite/ChangeLog:
> 
>          * gcc.target/riscv/zicond_ifcvt_opt.c: New test.
> ---
>   gcc/ifcvt.cc                                  | 210 ++++++
>   .../gcc.target/riscv/zicond_ifcvt_opt.c       | 682 ++++++++++++++++++
>   2 files changed, 892 insertions(+)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
> 
> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
> index a0af553b9ff..8f6a0e7f5fe 100644
> --- a/gcc/ifcvt.cc
> +++ b/gcc/ifcvt.cc
> @@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
>   static bool noce_try_minmax (struct noce_if_info *);
>   static bool noce_try_abs (struct noce_if_info *);
>   static bool noce_try_sign_mask (struct noce_if_info *);
> +static int noce_try_cond_zero_arith (struct noce_if_info *);
>   
>   /* Return the comparison code for reversed condition for IF_INFO,
>      or UNKNOWN if reversing the condition is not possible.  */
> @@ -1831,6 +1832,40 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
>       return NULL_RTX;
>   }
>   
> +/*  Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
> +    IF_INFO describes the if-conversion scenario under consideration.
> +    CZERO_CODE selects the condition (EQ/NE).
> +    NON_ZERO_OP is the nonzero operand of the conditional move
> +    TARGET is the desired output register.  */
> +
> +static rtx
> +noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
> +		 rtx non_zero_op, rtx target)
[ ... ]
The code you wrote is safe in that if constructs a suitable if-then-else 
as a single object, starts a new sequence the uses emit_insn to put that 
object onto a sequence.  Then you extract that one and only one insn 
from the sequence and validate it can be recognized.

In cases where you want to do something like this and know you're going 
to emit one and only one insn you can use 'make_insn_raw' without 
generating a new sequence.

I would suggest you replace all the code starting with start_sequence() 
and ending with end_sequence () (inclusive) with something like

insn = make_insn_raw (set);
if (recog_memoized (insn) >= 0)
   {
     emit_insn (insn);
     return target;
   }
return NULL_RTX;


Note that in the future (gcc-15) when this code is generalized to use 
the expander it will potentially generate multiple insns at which point 
we'll have to put them on a sequence and validate they all are 
recognizable.  But we'll tackle that at the appropriate time.


> +
> +  return false;
> +}
> +
> +/*  Helper function to return REG itself or inner expression of a SUBREG,
> +    otherwise NULL_RTX for other RTX_CODE.  */
> +
> +static rtx
> +get_base_reg (rtx exp)
> +{
> +  if (REG_P (exp))
> +    return exp;
> +  else if (SUBREG_P (exp))
> +    return SUBREG_REG (exp);
> +
> +  return NULL_RTX;
> +
I would advise against handling subregs at this point.  What you're 
doing is probably too simplistic given the semantics of subregs.



> +
> +  /* Strip sign_extend if any.  */
> +  if (GET_CODE (a) == SIGN_EXTEND || GET_CODE (a) == ZERO_EXTEND)
> +    bin_exp = XEXP (a, 0);
> +  else
> +    bin_exp = a;
Similarly while I do think we're going to want to handle extensions, 
let's not try and add them at this point.  We want to get this wrapped 
up & integrated so that everyone can move their focus to bugfixing for 
gcc-14.

> +
> +/*  Try to covert if-then-else with conditional zero,
> +    returning TURE on success or FALSE on failure.
> +    IF_INFO describes the if-conversion scenario under consideration.  */
> +
> +static int
> +noce_try_cond_zero_arith (struct noce_if_info *if_info)
> +{
> +  rtx target, a;
> +  rtx_insn *seq;
> +  machine_mode mode = GET_MODE (if_info->x);
> +  rtx common = NULL_RTX;
> +  enum rtx_code czero_code = UNKNOWN;
> +  rtx non_zero_op = NULL_RTX;
> +  rtx *to_replace = NULL;
> +
> +  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
> +					&to_replace))
> +    return false;
> +
> +  /* Disallow CONST_INT currently for simplicity*/
> +  if (to_replace == NULL || !REG_P (*to_replace))
> +    return false;If you're not going to allow CONST_INT reject them in the 
ok_for_condzero_arith routine.  Presumably you're rejecting constants 
because zicond doesn't allow them in the arms.  We'll want to handle 
them in the future and can do so easily once we're using the expander.



> +
> +  non_zero_op = *to_replace;
> +
> +  start_sequence ();
> +
> +  /* If x is used in both input and out like x = c ? x + z : x,
> +     use a new reg to avoid modifying x  */
> +  if (common && rtx_equal_p (common, if_info->x))
> +    target = gen_reg_rtx (mode);
> +  else
> +    target = if_info->x;
> +
> +  target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
> +  if (!target || !to_replace)
> +    {
> +      end_sequence ();
> +      return false;
> +    }
> +
> +  *to_replace = target;
> +  emit_insn (gen_rtx_SET (if_info->x, a));
This isn't necessarily safe.  Use emit_move_insn instead.

This is pretty close.  Hopefully one more iteration and it can be 
integrated.

jeff

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

* Re: Re: [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns
  2023-11-29  5:26   ` Jeff Law
@ 2023-11-29 11:09     ` Fei Gao
  2023-12-05  8:36       ` Fei Gao
  0 siblings, 1 reply; 11+ messages in thread
From: Fei Gao @ 2023-11-29 11:09 UTC (permalink / raw)
  To: jeffreyalaw, gcc-patches; +Cc: Kito Cheng, Palmer Dabbelt, zengxiao

On 2023-11-29 13:26  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 11/27/23 19:32, Fei Gao wrote:
>> op=[PLUS, MINUS, IOR, XOR, ASHIFT, ASHIFTRT, LSHIFTRT, ROTATE, ROTATERT]
>>
>> SIGN_EXTEND, ZERO_EXTEND and SUBREG has been considered
>> to support SImode in 64-bit machine.
>Let's defer these for now.  We're supposed to be wrapping up work that
>was posted before stage1 closed.  If these opcodes were trivial to
>support, then I would let them through, but SUBREGs for example can be
>problematical as their semantics can be complex. 

I can delete the  32bit-support in 64 bit machine.
Or split this patch into 2 parts word-size support and 32bit-support in 64 bit machine.
Or keep current status if the following words persuades you :)

Regarding complexity, the current patch differs from 1st version by "to_replace" and reduces
complexity significantly. noce_simple_bbs() ensures we have only single set for insn_a like x=sext(subreg(y) op subreg(z)).
Instead of constructing an insn considering complex extension and subreg from scratch, to_replace locates the rtx z
in noce_bbs_ok_for_cond_zero_arith,
and then replace it with czero result. In this way, extension and subreg are as simple as reg cases.
All the cases for extension and subreg have been uploaded in this patch.
They can be found by searching "int" in gcc.target/riscv/zicond_ifcvt_opt.c

Could you please let me known which you prefer?

>
>
>>
>> Conditional op, if zero
>> rd = (rc == 0) ? (rs1 op rs2) : rs1
>> -->
>> czero.nez rd, rs2, rc
>> op rd, rs1, rd
>>
>> Conditional op, if non-zero
>> rd = (rc != 0) ? (rs1 op rs2) : rs1
>> -->
>> czero.eqz rd, rs2, rc
>> op rd, rs1, rd
>>
>> Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>
>>
>> gcc/ChangeLog:
>>
>>          * ifcvt.cc (noce_try_cond_zero_arith):handler for condtional zero based ifcvt
>>          (noce_emit_czero): helper for noce_try_cond_zero_arith
>>          (noce_cond_zero_binary_op_supported): check supported OPs for condtional zero based ifcvt
>>          (get_base_reg): get base reg of a subreg or the reg itself
>>          (noce_bbs_ok_for_cond_zero_arith): check if BBs are OK for condtional zero based ifcvt
>>          (noce_process_if_block): add noce_try_cond_zero_arith
>>
>> gcc/testsuite/ChangeLog:
>>
>>          * gcc.target/riscv/zicond_ifcvt_opt.c: New test.
>> ---
>>   gcc/ifcvt.cc                                  | 210 ++++++
>>   .../gcc.target/riscv/zicond_ifcvt_opt.c       | 682 ++++++++++++++++++
>>   2 files changed, 892 insertions(+)
>>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
>>
>> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
>> index a0af553b9ff..8f6a0e7f5fe 100644
>> --- a/gcc/ifcvt.cc
>> +++ b/gcc/ifcvt.cc
>> @@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
>>   static bool noce_try_minmax (struct noce_if_info *);
>>   static bool noce_try_abs (struct noce_if_info *);
>>   static bool noce_try_sign_mask (struct noce_if_info *);
>> +static int noce_try_cond_zero_arith (struct noce_if_info *);
>>  
>>   /* Return the comparison code for reversed condition for IF_INFO,
>>      or UNKNOWN if reversing the condition is not possible.  */
>> @@ -1831,6 +1832,40 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
>>       return NULL_RTX;
>>   }
>>  
>> +/*  Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
>> +    IF_INFO describes the if-conversion scenario under consideration.
>> +    CZERO_CODE selects the condition (EQ/NE).
>> +    NON_ZERO_OP is the nonzero operand of the conditional move
>> +    TARGET is the desired output register.  */
>> +
>> +static rtx
>> +noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
>> +	rtx non_zero_op, rtx target)
>[ ... ]
>The code you wrote is safe in that if constructs a suitable if-then-else
>as a single object, starts a new sequence the uses emit_insn to put that
>object onto a sequence.  Then you extract that one and only one insn
>from the sequence and validate it can be recognized.
>
>In cases where you want to do something like this and know you're going
>to emit one and only one insn you can use 'make_insn_raw' without
>generating a new sequence.
>
>I would suggest you replace all the code starting with start_sequence()
>and ending with end_sequence () (inclusive) with something like
>
>insn = make_insn_raw (set);
>if (recog_memoized (insn) >= 0)
>   {
>     emit_insn (insn);
>     return target;
>   }
>return NULL_RTX; 
Thanks for your advice, I will take it in next version.

>
>
>Note that in the future (gcc-15) when this code is generalized to use
>the expander it will potentially generate multiple insns at which point
>we'll have to put them on a sequence and validate they all are
>recognizable.  But we'll tackle that at the appropriate time. 
Sure. 

>
>
>> +
>> +  return false;
>> +}
>> +
>> +/*  Helper function to return REG itself or inner expression of a SUBREG,
>> +    otherwise NULL_RTX for other RTX_CODE.  */
>> +
>> +static rtx
>> +get_base_reg (rtx exp)
>> +{
>> +  if (REG_P (exp))
>> +    return exp;
>> +  else if (SUBREG_P (exp))
>> +    return SUBREG_REG (exp);
>> +
>> +  return NULL_RTX;
>> +
>I would advise against handling subregs at this point.  What you're
>doing is probably too simplistic given the semantics of subregs.
>
>
>
>> +
>> +  /* Strip sign_extend if any.  */
>> +  if (GET_CODE (a) == SIGN_EXTEND || GET_CODE (a) == ZERO_EXTEND)
>> +    bin_exp = XEXP (a, 0);
>> +  else
>> +    bin_exp = a;
>Similarly while I do think we're going to want to handle extensions,
>let's not try and add them at this point.  We want to get this wrapped
>up & integrated so that everyone can move their focus to bugfixing for
>gcc-14. 
Same reply with the one regarding  *SIGN_EXTEND, ZERO_EXTEND and SUBREG* at
the beginning.

>
>> +
>> +/*  Try to covert if-then-else with conditional zero,
>> +    returning TURE on success or FALSE on failure.
>> +    IF_INFO describes the if-conversion scenario under consideration.  */
>> +
>> +static int
>> +noce_try_cond_zero_arith (struct noce_if_info *if_info)
>> +{
>> +  rtx target, a;
>> +  rtx_insn *seq;
>> +  machine_mode mode = GET_MODE (if_info->x);
>> +  rtx common = NULL_RTX;
>> +  enum rtx_code czero_code = UNKNOWN;
>> +  rtx non_zero_op = NULL_RTX;
>> +  rtx *to_replace = NULL;
>> +
>> +  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
>> +	&to_replace))
>> +    return false;
>> +
>> +  /* Disallow CONST_INT currently for simplicity*/
>> +  if (to_replace == NULL || !REG_P (*to_replace))
>> +    return false;If you're not going to allow CONST_INT reject them in the
>ok_for_condzero_arith routine.  Presumably you're rejecting constants
>because zicond doesn't allow them in the arms.  We'll want to handle
>them in the future and can do so easily once we're using the expander. 

I remembered the shift-by-6 case mentioned by you, see [PATCH 3/4] for const_int support:)
https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg327149.html

Also AND is supported  in 
https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg327219.html

Could you please reveiw 2 patches above so I will repost together if needed? 
>
>
>
>> +
>> +  non_zero_op = *to_replace;
>> +
>> +  start_sequence ();
>> +
>> +  /* If x is used in both input and out like x = c ? x + z : x,
>> +     use a new reg to avoid modifying x  */
>> +  if (common && rtx_equal_p (common, if_info->x))
>> +    target = gen_reg_rtx (mode);
>> +  else
>> +    target = if_info->x;
>> +
>> +  target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
>> +  if (!target || !to_replace)
>> +    {
>> +      end_sequence ();
>> +      return false;
>> +    }
>> +
>> +  *to_replace = target;
>> +  emit_insn (gen_rtx_SET (if_info->x, a));
>This isn't necessarily safe.  Use emit_move_insn instead. 
OK. 

Thanks & BR
Fei

>
>This is pretty close.  Hopefully one more iteration and it can be
>integrated.
>
>jeff

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

* Re: Re: [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB
  2023-11-28  5:03   ` Jeff Law
@ 2023-12-04  7:01     ` Fei Gao
  0 siblings, 0 replies; 11+ messages in thread
From: Fei Gao @ 2023-12-04  7:01 UTC (permalink / raw)
  To: jeffreyalaw, Kito Cheng; +Cc: gcc-patches, Palmer Dabbelt, zengxiao

Committed.  Thanks Kito and Jeff.

BR
Fei

On 2023-11-28 13:03  Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>
>
>On 11/27/23 20:09, Kito Cheng wrote:
>> Personally I don't like to play with the pattern order to tweak the
>> code gen since it kinda introduces implicit relation/rule here, but I
>> guess the only way to prevent that is to duplicate the pattern for SFB
>> again, which is not an ideal solution...
>I won't object to this patch, but I don't really like it either.
>
>This patch highlights that the SFB code is not well integrated with the
>rest of the conditional move support.
>
>Jeff

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

* Re: Re: [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns
  2023-11-29 11:09     ` Fei Gao
@ 2023-12-05  8:36       ` Fei Gao
  0 siblings, 0 replies; 11+ messages in thread
From: Fei Gao @ 2023-12-05  8:36 UTC (permalink / raw)
  To: gaofei, jeffreyalaw, gcc-patches; +Cc: Kito Cheng, Palmer Dabbelt, zengxiao



On 2023-11-29 19:09  Fei Gao <gaofei@eswincomputing.com> wrote:
>
>On 2023-11-29 13:26  Jeff Law <jeffreyalaw@gmail.com> wrote:
>>
>>
>>
>>On 11/27/23 19:32, Fei Gao wrote:
>>> op=[PLUS, MINUS, IOR, XOR, ASHIFT, ASHIFTRT, LSHIFTRT, ROTATE, ROTATERT]
>>>
>>> SIGN_EXTEND, ZERO_EXTEND and SUBREG has been considered
>>> to support SImode in 64-bit machine.
>>Let's defer these for now.  We're supposed to be wrapping up work that
>>was posted before stage1 closed.  If these opcodes were trivial to
>>support, then I would let them through, but SUBREGs for example can be
>>problematical as their semantics can be complex.
>
>I can delete the  32bit-support in 64 bit machine.
>Or split this patch into 2 parts word-size support and 32bit-support in 64 bit machine.
>Or keep current status if the following words persuades you :)
>
>Regarding complexity, the current patch differs from 1st version by "to_replace" and reduces
>complexity significantly. noce_simple_bbs() ensures we have only single set for insn_a like x=sext(subreg(y) op subreg(z)).
>Instead of constructing an insn considering complex extension and subreg from scratch, to_replace locates the rtx z
>in noce_bbs_ok_for_cond_zero_arith,
>and then replace it with czero result. In this way, extension and subreg are as simple as reg cases.
>All the cases for extension and subreg have been uploaded in this patch.
>They can be found by searching "int" in gcc.target/riscv/zicond_ifcvt_opt.c
>
>Could you please let me known which you prefer? 
I split the patches. See new series https://patchwork.sourceware.org/project/gcc/list/?series=27924
>
>>
>>
>>>
>>> Conditional op, if zero
>>> rd = (rc == 0) ? (rs1 op rs2) : rs1
>>> -->
>>> czero.nez rd, rs2, rc
>>> op rd, rs1, rd
>>>
>>> Conditional op, if non-zero
>>> rd = (rc != 0) ? (rs1 op rs2) : rs1
>>> -->
>>> czero.eqz rd, rs2, rc
>>> op rd, rs1, rd
>>>
>>> Co-authored-by: Xiao Zeng<zengxiao@eswincomputing.com>
>>>
>>> gcc/ChangeLog:
>>>
>>>          * ifcvt.cc (noce_try_cond_zero_arith):handler for condtional zero based ifcvt
>>>          (noce_emit_czero): helper for noce_try_cond_zero_arith
>>>          (noce_cond_zero_binary_op_supported): check supported OPs for condtional zero based ifcvt
>>>          (get_base_reg): get base reg of a subreg or the reg itself
>>>          (noce_bbs_ok_for_cond_zero_arith): check if BBs are OK for condtional zero based ifcvt
>>>          (noce_process_if_block): add noce_try_cond_zero_arith
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>          * gcc.target/riscv/zicond_ifcvt_opt.c: New test.
>>> ---
>>>   gcc/ifcvt.cc                                  | 210 ++++++
>>>   .../gcc.target/riscv/zicond_ifcvt_opt.c       | 682 ++++++++++++++++++
>>>   2 files changed, 892 insertions(+)
>>>   create mode 100644 gcc/testsuite/gcc.target/riscv/zicond_ifcvt_opt.c
>>>
>>> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
>>> index a0af553b9ff..8f6a0e7f5fe 100644
>>> --- a/gcc/ifcvt.cc
>>> +++ b/gcc/ifcvt.cc
>>> @@ -787,6 +787,7 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **);
>>>   static bool noce_try_minmax (struct noce_if_info *);
>>>   static bool noce_try_abs (struct noce_if_info *);
>>>   static bool noce_try_sign_mask (struct noce_if_info *);
>>> +static int noce_try_cond_zero_arith (struct noce_if_info *);
>>>  
>>>   /* Return the comparison code for reversed condition for IF_INFO,
>>>      or UNKNOWN if reversing the condition is not possible.  */
>>> @@ -1831,6 +1832,40 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
>>>       return NULL_RTX;
>>>   }
>>>  
>>> +/*  Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
>>> +    IF_INFO describes the if-conversion scenario under consideration.
>>> +    CZERO_CODE selects the condition (EQ/NE).
>>> +    NON_ZERO_OP is the nonzero operand of the conditional move
>>> +    TARGET is the desired output register.  */
>>> +
>>> +static rtx
>>> +noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code,
>>> +	rtx non_zero_op, rtx target)
>>[ ... ]
>>The code you wrote is safe in that if constructs a suitable if-then-else
>>as a single object, starts a new sequence the uses emit_insn to put that
>>object onto a sequence.  Then you extract that one and only one insn
>>from the sequence and validate it can be recognized.
>>
>>In cases where you want to do something like this and know you're going
>>to emit one and only one insn you can use 'make_insn_raw' without
>>generating a new sequence.
>>
>>I would suggest you replace all the code starting with start_sequence()
>>and ending with end_sequence () (inclusive) with something like
>>
>>insn = make_insn_raw (set);
>>if (recog_memoized (insn) >= 0)
>>   {
>>     emit_insn (insn);
>>     return target;
>>   }
>>return NULL_RTX;
>Thanks for your advice, I will take it in next version. 
I used add_insn instead of emit_insn to avoid a segment fault caused by invalid
NEXT_INSN (insn) of the raw insn.

BR, 
Fei
>
>>
>>
>>Note that in the future (gcc-15) when this code is generalized to use
>>the expander it will potentially generate multiple insns at which point
>>we'll have to put them on a sequence and validate they all are
>>recognizable.  But we'll tackle that at the appropriate time.
>Sure. 
>
>>
>>
>>> +
>>> +  return false;
>>> +}
>>> +
>>> +/*  Helper function to return REG itself or inner expression of a SUBREG,
>>> +    otherwise NULL_RTX for other RTX_CODE.  */
>>> +
>>> +static rtx
>>> +get_base_reg (rtx exp)
>>> +{
>>> +  if (REG_P (exp))
>>> +    return exp;
>>> +  else if (SUBREG_P (exp))
>>> +    return SUBREG_REG (exp);
>>> +
>>> +  return NULL_RTX;
>>> +
>>I would advise against handling subregs at this point.  What you're
>>doing is probably too simplistic given the semantics of subregs.
>>
>>
>>
>>> +
>>> +  /* Strip sign_extend if any.  */
>>> +  if (GET_CODE (a) == SIGN_EXTEND || GET_CODE (a) == ZERO_EXTEND)
>>> +    bin_exp = XEXP (a, 0);
>>> +  else
>>> +    bin_exp = a;
>>Similarly while I do think we're going to want to handle extensions,
>>let's not try and add them at this point.  We want to get this wrapped
>>up & integrated so that everyone can move their focus to bugfixing for
>>gcc-14.
>Same reply with the one regarding  *SIGN_EXTEND, ZERO_EXTEND and SUBREG* at
>the beginning.
>
>>
>>> +
>>> +/*  Try to covert if-then-else with conditional zero,
>>> +    returning TURE on success or FALSE on failure.
>>> +    IF_INFO describes the if-conversion scenario under consideration.  */
>>> +
>>> +static int
>>> +noce_try_cond_zero_arith (struct noce_if_info *if_info)
>>> +{
>>> +  rtx target, a;
>>> +  rtx_insn *seq;
>>> +  machine_mode mode = GET_MODE (if_info->x);
>>> +  rtx common = NULL_RTX;
>>> +  enum rtx_code czero_code = UNKNOWN;
>>> +  rtx non_zero_op = NULL_RTX;
>>> +  rtx *to_replace = NULL;
>>> +
>>> +  if (!noce_bbs_ok_for_cond_zero_arith (if_info, &common, &czero_code, &a,
>>> +	&to_replace))
>>> +    return false;
>>> +
>>> +  /* Disallow CONST_INT currently for simplicity*/
>>> +  if (to_replace == NULL || !REG_P (*to_replace))
>>> +    return false;If you're not going to allow CONST_INT reject them in the
>>ok_for_condzero_arith routine.  Presumably you're rejecting constants
>>because zicond doesn't allow them in the arms.  We'll want to handle
>>them in the future and can do so easily once we're using the expander.
>
>I remembered the shift-by-6 case mentioned by you, see [PATCH 3/4] for const_int support:)
>https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg327149.html
>
>Also AND is supported  in 
>https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg327219.html
>
>Could you please reveiw 2 patches above so I will repost together if needed? 
>>
>>
>>
>>> +
>>> +  non_zero_op = *to_replace;
>>> +
>>> +  start_sequence ();
>>> +
>>> +  /* If x is used in both input and out like x = c ? x + z : x,
>>> +     use a new reg to avoid modifying x  */
>>> +  if (common && rtx_equal_p (common, if_info->x))
>>> +    target = gen_reg_rtx (mode);
>>> +  else
>>> +    target = if_info->x;
>>> +
>>> +  target = noce_emit_czero (if_info, czero_code, non_zero_op, target);
>>> +  if (!target || !to_replace)
>>> +    {
>>> +      end_sequence ();
>>> +      return false;
>>> +    }
>>> +
>>> +  *to_replace = target;
>>> +  emit_insn (gen_rtx_SET (if_info->x, a));
>>This isn't necessarily safe.  Use emit_move_insn instead.
>OK. 
>
>Thanks & BR
>Fei
>
>>
>>This is pretty close.  Hopefully one more iteration and it can be
>>integrated.
>>
>>jeff

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

end of thread, other threads:[~2023-12-05  8:36 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-28  2:32 [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Fei Gao
2023-11-28  2:32 ` [PATCH 2/4] [ifcvt] optimize x=c ? (y op z) : y by RISC-V Zicond like insns Fei Gao
2023-11-29  5:26   ` Jeff Law
2023-11-29 11:09     ` Fei Gao
2023-12-05  8:36       ` Fei Gao
2023-11-28  2:32 ` [PATCH 3/4] [ifcvt] optimize x=c ? (y op const_int) " Fei Gao
2023-11-28  2:32 ` [PATCH 4/4] [V2] [ifcvt] prefer SFB to Zicond for x=c ? (y op CONST) : y Fei Gao
2023-11-28  5:00   ` Jeff Law
2023-11-28  3:09 ` [PATCH 1/4] [RISC-V] prefer Zicond primitive semantics to SFB Kito Cheng
2023-11-28  5:03   ` Jeff Law
2023-12-04  7:01     ` Fei Gao

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