mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
[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:
parent
b57bd27cb6
commit
8ae83274d8
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user