aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Zinsly <rzinsly@ventanamicro.com>2023-08-07 10:26:24 -0400
committerJeff Law <jeffreyalaw@gmail.com>2023-08-07 11:04:34 -0400
commit8ae83274d8cc60547e8c92a41a4f4716b045f57a (patch)
tree75bc226626ee67181ddb7d33c08d37f1a5afd09e
parentb57bd27cb68fdbe5d9dcd571b1cb66f72b841290 (diff)
downloadgcc-8ae83274d8cc60547e8c92a41a4f4716b045f57a.zip
gcc-8ae83274d8cc60547e8c92a41a4f4716b045f57a.tar.gz
gcc-8ae83274d8cc60547e8c92a41a4f4716b045f57a.tar.bz2
[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>
-rw-r--r--gcc/config/riscv/riscv-protos.h2
-rw-r--r--gcc/config/riscv/riscv.cc44
2 files changed, 42 insertions, 4 deletions
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 324991e..53b87cb 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 7728cd3..279304a 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)