[committed,RISC-V] Handle more cases in riscv_expand_conditional_move

Message ID 8a79e0aa-f507-b5d3-c5a7-ca292c1b0aaf@gmail.com
State Unresolved
Headers
Series [committed,RISC-V] Handle more cases in riscv_expand_conditional_move |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jeff Law Aug. 7, 2023, 3:06 p.m. UTC
  As I've mentioned in the main zicond thread, Ventana has had patches 
that support more cases by first emitting a suitable scc instruction 
essentially as a canonicalization step of the condition for zicond.

For example if we have

(set (target) (if_then_else (op (reg1) (reg2))
                             (true_value)
                             (false_value)))

The two register comparison isn't handled by zicond directly.  But we 
can generate something like this instead

(set (temp) (op (reg1) (reg2)))
(set (target) (if_then_else (op (temp) (const_int 0))
                             (true_value)
                             (false_value)

Then let the remaining code from Xiao handle the true_value/false_value 
to make sure it's zicond compatible.

This is primarily Raphael's work.  My involvement has been mostly to 
move it from its original location (in the .md file) into the expander 
function and fix minor problems with the FP case.


Committed to the trunk,

Jeff
commit 8ae83274d8cc60547e8c92a41a4f4716b045f57a
Author: Raphael Zinsly <rzinsly@ventanamicro.com>
Date:   Mon Aug 7 10:26:24 2023 -0400

    [committed] [RISC-V] Handle more cases in riscv_expand_conditional_move
    
    As I've mentioned in the main zicond thread, Ventana has had patches
    that support more cases by first emitting a suitable scc instruction
    essentially as a canonicalization step of the condition for zicond.
    
    For example if we have
    
    (set (target) (if_then_else (op (reg1) (reg2))
                                (true_value)
                                (false_value)))
    
    The two register comparison isn't handled by zicond directly.  But we
    can generate something like this instead
    
    (set (temp) (op (reg1) (reg2)))
    (set (target) (if_then_else (op (temp) (const_int 0))
                                (true_value)
                                (false_value)
    
    Then let the remaining code from Xiao handle the true_value/false_value
    to make sure it's zicond compatible.
    
    This is primarily Raphael's work.  My involvement has been mostly to
    move it from its original location (in the .md file) into the expander
    function and fix minor problems with the FP case.
    
    gcc/
            * config/riscv/riscv.cc (riscv_expand_int_scc): Add invert_ptr
            as an argument and pass it to riscv_emit_int_order_test.
            (riscv_expand_conditional_move): Handle cases where the condition
            is not EQ/NE or the second argument to the conditional is not
            (const_int 0).
            * config/riscv/riscv-protos.h (riscv_expand_int_scc): Update prototype.
    
            Co-authored-by: Jeff Law <jlaw@ventanamicro.com>
  

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 324991e2619..53b87cb28d3 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -103,7 +103,7 @@  extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_return ();
 
 #ifdef RTX_CODE
-extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx);
+extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool *invert_ptr = 0);
 extern void riscv_expand_float_scc (rtx, enum rtx_code, rtx, rtx);
 extern void riscv_expand_conditional_branch (rtx, enum rtx_code, rtx, rtx);
 extern rtx riscv_emit_binary (enum rtx_code code, rtx dest, rtx x, rtx y);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 7728cd34569..279304afc19 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3499,7 +3499,7 @@  riscv_emit_float_compare (enum rtx_code *code, rtx *op0, rtx *op1)
 /* CODE-compare OP0 and OP1.  Store the result in TARGET.  */
 
 void
-riscv_expand_int_scc (rtx target, enum rtx_code code, rtx op0, rtx op1)
+riscv_expand_int_scc (rtx target, enum rtx_code code, rtx op0, rtx op1, bool *invert_ptr)
 {
   riscv_extend_comparands (code, &op0, &op1);
   op0 = force_reg (word_mode, op0);
@@ -3510,7 +3510,7 @@  riscv_expand_int_scc (rtx target, enum rtx_code code, rtx op0, rtx op1)
       riscv_emit_binary (code, target, zie, const0_rtx);
     }
   else
-    riscv_emit_int_order_test (code, 0, target, op0, op1);
+    riscv_emit_int_order_test (code, invert_ptr, target, op0, op1);
 }
 
 /* Like riscv_expand_int_scc, but for floating-point comparisons.  */
@@ -3576,7 +3576,6 @@  riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
       return true;
     }
   else if (TARGET_ZICOND
-	   && (code == EQ || code == NE)
 	   && GET_MODE_CLASS (mode) == MODE_INT)
     {
       /* The comparison must be comparing WORD_MODE objects.   We must
@@ -3586,6 +3585,45 @@  riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
       if (GET_MODE (op0) != word_mode || GET_MODE (op1) != word_mode)
 	return false;
 
+      /* Canonicalize the comparison.  It must be an equality comparison
+	 against 0.  If it isn't, then emit an SCC instruction so that
+	 we can then use an equality comparison against zero.  */
+      if (!equality_operator (op, VOIDmode) || op1 != CONST0_RTX (mode))
+	{
+	  enum rtx_code new_code = NE;
+	  bool *invert_ptr = 0;
+	  bool invert = false;
+
+	  if (code == LE || code == GE)
+	    invert_ptr = &invert;
+
+	  /* Emit an scc like instruction into a temporary
+	     so that we can use an EQ/NE comparison.  */
+	  rtx tmp = gen_reg_rtx (mode);
+
+	  /* We can support both FP and integer conditional moves.  */
+	  if (INTEGRAL_MODE_P (GET_MODE (XEXP (op, 0))))
+	    riscv_expand_int_scc (tmp, code, op0, op1, invert_ptr);
+	  else if (FLOAT_MODE_P (GET_MODE (XEXP (op, 0)))
+		   && fp_scc_comparison (op, GET_MODE (op)))
+	    riscv_expand_float_scc (tmp, code, op0, op1);
+	  else
+	    return false;
+
+	  /* If riscv_expand_int_scc inverts the condition, then it will
+	     flip the value of INVERT.  We need to know where so that
+	     we can adjust it for our needs.  */
+	  if (invert)
+	    new_code = EQ;
+
+	  op = gen_rtx_fmt_ee (new_code, mode, tmp, const0_rtx);
+
+	  /* We've generated a new comparison.  Update the local variables.  */
+	  code = GET_CODE (op);
+	  op0 = XEXP (op, 0);
+	  op1 = XEXP (op, 1);
+	}
+
       /* 0, reg or 0, imm */
       if (cons == CONST0_RTX (mode)
 	  && (REG_P (alt)