[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>
This commit is contained in:
Raphael Zinsly 2023-08-07 10:26:24 -04:00 committed by Jeff Law
parent b57bd27cb6
commit 8ae83274d8
2 changed files with 42 additions and 4 deletions

View File

@ -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);

View File

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