[v3,RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
Checks
Commit Message
This patch recognizes Zicond patterns when the select pattern
with condition eq or neq to 0 (using eq as an example), namely:
1 rd = (rs2 == 0) ? non-imm : 0
2 rd = (rs2 == 0) ? non-imm : non-imm
3 rd = (rs2 == 0) ? reg : non-imm
4 rd = (rs2 == 0) ? reg : reg
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
Zicond patterns
* config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test.
* gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test.
* gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test.
* gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test.
---
gcc/config/riscv/riscv.cc | 137 ++++++++++++++++++
gcc/config/riscv/riscv.md | 4 +-
.../zicond-primitiveSemantics_return_0_imm.c | 65 +++++++++
...zicond-primitiveSemantics_return_imm_imm.c | 73 ++++++++++
...zicond-primitiveSemantics_return_imm_reg.c | 65 +++++++++
...zicond-primitiveSemantics_return_reg_reg.c | 65 +++++++++
6 files changed, 407 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c
Comments
On 8/1/23 19:38, Xiao Zeng wrote:
> This patch recognizes Zicond patterns when the select pattern
> with condition eq or neq to 0 (using eq as an example), namely:
>
> 1 rd = (rs2 == 0) ? non-imm : 0
> 2 rd = (rs2 == 0) ? non-imm : non-imm
> 3 rd = (rs2 == 0) ? reg : non-imm
> 4 rd = (rs2 == 0) ? reg : reg
>
> gcc/ChangeLog:
>
> * config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
> Zicond patterns
> * config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test.
So I've done a partial commit of this patch. I'm still evaluating a few
of the cases and haven't included them yet.
The most notable change I've made is the 0, imm case and imm, 0 case can
trivially handle 0, reg and reg, 0 as well. I also changed the imm, imm
case to use gen_int_mode rather than GEN_INT. It may not be strictly
necessary here, but it does future proof the code a bit if we were to
support additional mode (and we may well want to do that).
I'm hoping to get the rest of patch #3 in today, though I suspect the
testing will push it into tomorrow. Then I want to layer on Raphael's
code to handle missed cases using scc insns.
Jeff
commit 9e3fd332959930efd3cabf222afbac910507d2f3
Author: Xiao Zeng <zengxiao@eswincomputing.com>
Date: Thu Aug 3 16:09:46 2023 -0400
[PATCH 3/5] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
[ This is a partial commit. So not all the cases mentioned by
Xiao are currently handled. ]
This patch recognizes Zicond patterns when the select pattern
with condition eq or neq to 0 (using eq as an example), namely:
1 rd = (rs2 == 0) ? non-imm : 0
2 rd = (rs2 == 0) ? non-imm : non-imm
3 rd = (rs2 == 0) ? reg : non-imm
4 rd = (rs2 == 0) ? reg : reg
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
various Zicond patterns.
* config/riscv/riscv.md (mov<mode>cc): Allow TARGET_ZICOND. Use
sfb_alu_operand for both arms of the conditional move.
Co-authored-by: Jeff Law <jlaw@ventanamicro.com>
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d8fab68dbb4..8b725610815 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3580,15 +3580,67 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p);
rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
- /* The expander allows (const_int 0) for CONS for the benefit of
- TARGET_XTHEADCONDMOV, but that case isn't supported for
- TARGET_SFB_ALU. So force that operand into a register if
- necessary. */
+ /* The expander is a bit loose in its specification of the true
+ arm of the conditional move. That allows us to support more
+ cases for extensions which are more general than SFB. But
+ does mean we need to force CONS into a register at this point. */
cons = force_reg (GET_MODE (dest), cons);
emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
cond, cons, 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
+ enforce that so that we don't strip away a sign_extension
+ thinking it is unnecessary. We might consider using
+ riscv_extend_operands if they are not already properly extended. */
+ if (GET_MODE (op0) != word_mode || GET_MODE (op1) != word_mode)
+ return false;
+
+ /* 0, reg or 0, imm */
+ if (cons == CONST0_RTX (mode)
+ && (REG_P (alt)
+ || (CONST_INT_P (alt) && alt != CONST0_RTX (mode))))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ alt = force_reg (mode, alt);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ /* imm, imm */
+ else if (CONST_INT_P (cons) && cons != CONST0_RTX (mode)
+ && CONST_INT_P (alt) && alt != CONST0_RTX (mode))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ HOST_WIDE_INT t = INTVAL (alt) - INTVAL (cons);
+ alt = force_reg (mode, gen_int_mode (t, mode));
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ CONST0_RTX (mode),
+ alt)));
+ riscv_emit_binary (PLUS, dest, dest, cons);
+ return true;
+ }
+ /* reg, 0 or imm, 0 */
+ else if ((REG_P (cons)
+ || (CONST_INT_P (cons) && cons != CONST0_RTX (mode)))
+ && alt == CONST0_RTX (mode))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ cons = force_reg (mode, cons);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ }
return false;
}
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 24819cc737c..688fd697255 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2492,9 +2492,9 @@ (define_insn "*branch<mode>"
(define_expand "mov<mode>cc"
[(set (match_operand:GPR 0 "register_operand")
(if_then_else:GPR (match_operand 1 "comparison_operator")
- (match_operand:GPR 2 "reg_or_0_operand")
+ (match_operand:GPR 2 "sfb_alu_operand")
(match_operand:GPR 3 "sfb_alu_operand")))]
- "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
+ "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
{
if (riscv_expand_conditional_move (operands[0], operands[1],
operands[2], operands[3]))
On 8/1/23 19:38, Xiao Zeng wrote:
> This patch recognizes Zicond patterns when the select pattern
> with condition eq or neq to 0 (using eq as an example), namely:
>
> 1 rd = (rs2 == 0) ? non-imm : 0
> 2 rd = (rs2 == 0) ? non-imm : non-imm
> 3 rd = (rs2 == 0) ? reg : non-imm
> 4 rd = (rs2 == 0) ? reg : reg
>
> gcc/ChangeLog:
>
> * config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
> Zicond patterns
> * config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc
So I've made minor adjustments to the remaining three cases. First we
need to check the code before optimizing the cases were one of the arms
of the conditional move matches op0.
I slightly adjusted the case for out of range constants. Its better to
check SMALL_OPERAND rather than testing for specific constants. And
when that triggers, we can just force the value into a register and
continue as-is rather than recursing.
The patch I'm committing fixes one comment typo (whitespace) and a bit
of accidentally duplicated code I added in a prior commit.
Next up Raphael's patches to handle nontrival conditionals by emiting an
scc insn :-)
Jeff
ps. I'm deferrring the testsuite bits until we sort out the costing
problems. THey're definitely not forgotten and I still use them in my
local tree.
commit 4e87c953d16377457b31b65b6c3268d932e462ab
Author: Xiao Zeng <zengxiao@eswincomputing.com>
Date: Fri Aug 4 17:23:56 2023 -0400
[PATCH v3] [RISC-V] Generate Zicond instruction for select pattern with condition eq or neq to 0
This patch recognizes Zicond patterns when the select pattern
with condition eq or neq to 0 (using eq as an example), namely:
1 rd = (rs2 == 0) ? non-imm : 0
2 rd = (rs2 == 0) ? non-imm : non-imm
3 rd = (rs2 == 0) ? reg : non-imm
4 rd = (rs2 == 0) ? reg : reg
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
more Zicond patterns. Fix whitespace typo.
(riscv_rtx_costs): Remove accidental code duplication.
Co-authored-by: Jeff Law <jlaw@ventanamicro.com>
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 8b725610815..7728cd34569 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2522,20 +2522,6 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
*total = COSTS_N_INSNS (1);
return true;
}
- else if (TARGET_ZICOND
- && outer_code == SET
- && ((GET_CODE (XEXP (x, 1)) == REG
- && XEXP (x, 2) == CONST0_RTX (GET_MODE (XEXP (x, 1))))
- || (GET_CODE (XEXP (x, 2)) == REG
- && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 2))))
- || (GET_CODE (XEXP (x, 1)) == REG
- && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 0), 0)))
- || (GET_CODE (XEXP (x, 1)) == REG
- && rtx_equal_p (XEXP (x, 2), XEXP (XEXP (x, 0), 0)))))
- {
- *total = COSTS_N_INSNS (1);
- return true;
- }
else if (LABEL_REF_P (XEXP (x, 1)) && XEXP (x, 2) == pc_rtx)
{
if (equality_operator (XEXP (x, 0), mode)
@@ -3583,7 +3569,7 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
/* The expander is a bit loose in its specification of the true
arm of the conditional move. That allows us to support more
cases for extensions which are more general than SFB. But
- does mean we need to force CONS into a register at this point. */
+ does mean we need to force CONS into a register at this point. */
cons = force_reg (GET_MODE (dest), cons);
emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
cond, cons, alt)));
@@ -3628,6 +3614,40 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
riscv_emit_binary (PLUS, dest, dest, cons);
return true;
}
+ /* imm, reg */
+ else if (CONST_INT_P (cons) && cons != CONST0_RTX (mode) && REG_P (alt))
+ {
+ /* Optimize for register value of 0. */
+ if (code == NE && rtx_equal_p (op0, alt) && op1 == CONST0_RTX (mode))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ cons = force_reg (mode, cons);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+
+ rtx temp1 = gen_reg_rtx (mode);
+ rtx temp2 = gen_int_mode (-1 * INTVAL (cons), mode);
+
+ /* TEMP2 might not fit into a signed 12 bit immediate suitable
+ for an addi instruction. If that's the case, force it into
+ a register. */
+ if (!SMALL_OPERAND (INTVAL (temp2)))
+ temp2 = force_reg (mode, temp2);
+
+ riscv_emit_binary (PLUS, temp1, alt, temp2);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ CONST0_RTX (mode),
+ temp1)));
+ riscv_emit_binary (PLUS, dest, dest, cons);
+ return true;
+ }
/* reg, 0 or imm, 0 */
else if ((REG_P (cons)
|| (CONST_INT_P (cons) && cons != CONST0_RTX (mode)))
@@ -3640,6 +3660,73 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
cons, alt)));
return true;
}
+ /* reg, imm */
+ else if (REG_P (cons) && CONST_INT_P (alt) && alt != CONST0_RTX (mode))
+ {
+ /* Optimize for register value of 0. */
+ if (code == EQ && rtx_equal_p (op0, cons) && op1 == CONST0_RTX (mode))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ alt = force_reg (mode, alt);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+
+ rtx temp1 = gen_reg_rtx (mode);
+ rtx temp2 = gen_int_mode (-1 * INTVAL (alt), mode);
+
+ /* TEMP2 might not fit into a signed 12 bit immediate suitable
+ for an addi instruction. If that's the case, force it into
+ a register. */
+ if (!SMALL_OPERAND (INTVAL (temp2)))
+ temp2 = force_reg (mode, temp2);
+
+ riscv_emit_binary (PLUS, temp1, cons, temp2);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ temp1,
+ CONST0_RTX (mode))));
+ riscv_emit_binary (PLUS, dest, dest, alt);
+ return true;
+ }
+ /* reg, reg */
+ else if (REG_P (cons) && REG_P (alt))
+ {
+ if ((code == EQ && rtx_equal_p (cons, op0))
+ || (code == NE && rtx_equal_p (alt, op0)))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ if (!rtx_equal_p (cons, op0))
+ std::swap (alt, cons);
+ alt = force_reg (mode, alt);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+
+ rtx reg1 = gen_reg_rtx (mode);
+ rtx reg2 = gen_reg_rtx (mode);
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE,
+ GET_MODE (op0), op0, op1);
+ emit_insn (gen_rtx_SET (reg2,
+ gen_rtx_IF_THEN_ELSE (mode, cond2,
+ CONST0_RTX (mode),
+ cons)));
+ emit_insn (gen_rtx_SET (reg1,
+ gen_rtx_IF_THEN_ELSE (mode, cond1,
+ CONST0_RTX (mode),
+ alt)));
+ riscv_emit_binary (IOR, dest, reg1, reg2);
+ return true;
+ }
}
return false;
On Sat, Aug 05, 2023 at 05:31:00 AM Jeff Law <jeffreyalaw@gmail.com> wrote:
>
>On 8/1/23 19:38, Xiao Zeng wrote:
>> This patch recognizes Zicond patterns when the select pattern
>> with condition eq or neq to 0 (using eq as an example), namely:
>>
>> 1 rd = (rs2 == 0) ? non-imm : 0
>> 2 rd = (rs2 == 0) ? non-imm : non-imm
>> 3 rd = (rs2 == 0) ? reg : non-imm
>> 4 rd = (rs2 == 0) ? reg : reg
>>
>> gcc/ChangeLog:
>>
>> * config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
>> Zicond patterns
>> * config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc
>So I've made minor adjustments to the remaining three cases. First we
>need to check the code before optimizing the cases were one of the arms
>of the conditional move matches op0.
>
>I slightly adjusted the case for out of range constants. Its better to
>check SMALL_OPERAND rather than testing for specific constants. And
>when that triggers, we can just force the value into a register and
>continue as-is rather than recursing.
>
These changes make the code more concise and readable. Thumbs up!
>The patch I'm committing fixes one comment typo (whitespace) and a bit
>of accidentally duplicated code I added in a prior commit.
>
>Next up Raphael's patches to handle nontrival conditionals by emiting an
>scc insn :-)
It would be great to see other implementations for conditional execution. :-)
>
>Jeff
>
>ps. I'm deferrring the testsuite bits until we sort out the costing
>problems. THey're definitely not forgotten and I still use them in my
>local tree.
Thank you Jeff, I look forward to a unified, complete and concise
implementation method for cost calculation as soon as possible.
Thanks
Xiao Zeng
On 8/1/23 19:38, Xiao Zeng wrote:
> This patch recognizes Zicond patterns when the select pattern
> with condition eq or neq to 0 (using eq as an example), namely:
>
> 1 rd = (rs2 == 0) ? non-imm : 0
> 2 rd = (rs2 == 0) ? non-imm : non-imm
> 3 rd = (rs2 == 0) ? reg : non-imm
> 4 rd = (rs2 == 0) ? reg : reg
>
> gcc/ChangeLog:
>
> * config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize
> Zicond patterns
> * config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test.
> * gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test.
I've added -Oz and -Og to the skip list and pushed the tests up to the
trunk.
jeff
@@ -3557,6 +3557,143 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt)
cond, cons, alt)));
return true;
}
+ else if (TARGET_ZICOND
+ && (code == EQ || code == NE)
+ && GET_MODE_CLASS (mode) == MODE_INT)
+ {
+ /* 0 + imm */
+ if (CONST_INT_P (cons) && cons == CONST0_RTX (GET_MODE (cons))
+ && CONST_INT_P (alt) && alt != CONST0_RTX (GET_MODE (alt)))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ alt = force_reg (mode, alt);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ /* imm + imm */
+ else if (CONST_INT_P (cons) && cons != CONST0_RTX (GET_MODE (cons))
+ && CONST_INT_P (alt) && alt != CONST0_RTX (GET_MODE (alt)))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ alt = force_reg (mode, GEN_INT (INTVAL (alt) - INTVAL (cons)));
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ CONST0_RTX (mode),
+ alt)));
+ riscv_emit_binary (PLUS, dest, dest, cons);
+ return true;
+ }
+ /* imm + reg */
+ else if (CONST_INT_P (cons) && cons != CONST0_RTX (GET_MODE (cons))
+ && REG_P (alt))
+ {
+ if (op0 == alt && op1 == CONST0_RTX (GET_MODE (op1)))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ cons = force_reg (mode, cons);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ /* Handle the special situation of: -2048 == INTVAL (alt)
+ to avoid failure due to an unrecognized insn. Let the costing
+ model determine if the conditional move sequence is better
+ than the branching sequence. */
+ if (-2048 == INTVAL (cons))
+ {
+ rtx reg = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (reg, cons));
+ return riscv_expand_conditional_move (dest, op, reg, alt);
+ }
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ rtx temp = GEN_INT (-1 * INTVAL (cons));
+ riscv_emit_binary (PLUS, alt, alt, temp);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ CONST0_RTX (mode),
+ alt)));
+ riscv_emit_binary (PLUS, dest, dest, cons);
+ return true;
+ }
+ /* imm + 0 */
+ else if (CONST_INT_P (cons) && cons != CONST0_RTX (GET_MODE (cons))
+ && CONST_INT_P (alt) && alt == CONST0_RTX (GET_MODE (alt)))
+ {
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ cons = force_reg (mode, cons);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ /* reg + imm */
+ else if (REG_P (cons) && CONST_INT_P (alt)
+ && alt != CONST0_RTX (GET_MODE (alt)))
+ {
+ if (op0 == cons && op1 == CONST0_RTX (GET_MODE (op1)))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ alt = force_reg (mode, alt);
+ emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond,
+ cons, alt)));
+ return true;
+ }
+ if (-2048 == INTVAL (alt))
+ {
+ rtx reg = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (reg, alt));
+ return riscv_expand_conditional_move (dest, op, cons, reg);
+ }
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ rtx temp = GEN_INT (-1 * INTVAL (alt));
+ riscv_emit_binary (PLUS, cons, cons, temp);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond, cons,
+ CONST0_RTX (mode))));
+ riscv_emit_binary (PLUS, dest, dest, alt);
+ return true;
+ }
+ /* reg + reg */
+ else if (REG_P (cons) && REG_P (alt))
+ {
+ if (op0 == cons && op1 == CONST0_RTX (GET_MODE (op1)))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ CONST0_RTX (mode),
+ alt)));
+ return true;
+ }
+ if (op0 == alt && op1 == CONST0_RTX (GET_MODE (op1)))
+ {
+ rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ emit_insn (gen_rtx_SET (dest,
+ gen_rtx_IF_THEN_ELSE (mode, cond, cons,
+ CONST0_RTX (mode))));
+ return true;
+ }
+ rtx reg1 = gen_reg_rtx (mode);
+ rtx reg2 = gen_reg_rtx (mode);
+ riscv_emit_int_compare (&code, &op0, &op1, true);
+ rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
+ rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE,
+ GET_MODE (op0), op0, op1);
+ emit_insn (gen_rtx_SET (reg2,
+ gen_rtx_IF_THEN_ELSE (mode, cond2,
+ CONST0_RTX (mode),
+ cons)));
+ emit_insn (gen_rtx_SET (reg1,
+ gen_rtx_IF_THEN_ELSE (mode, cond1,
+ CONST0_RTX (mode),
+ alt)));
+ riscv_emit_binary (IOR, dest, reg1, reg2);
+ return true;
+ }
+ }
return false;
}
@@ -2492,9 +2492,9 @@
(define_expand "mov<mode>cc"
[(set (match_operand:GPR 0 "register_operand")
(if_then_else:GPR (match_operand 1 "comparison_operator")
- (match_operand:GPR 2 "reg_or_0_operand")
+ (match_operand:GPR 2 "sfb_alu_operand")
(match_operand:GPR 3 "sfb_alu_operand")))]
- "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV"
+ "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND"
{
if (riscv_expand_conditional_move (operands[0], operands[1],
operands[2], operands[3]))
new file mode 100644
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_0_imm_00(long a, long b) {
+ return a == 0 ? 0 : 3;
+}
+
+long primitiveSemantics_return_0_imm_01(long a, long b) {
+ return a != 0 ? 0 : 3;
+}
+
+long primitiveSemantics_return_0_imm_02(long a, long b) {
+ return a == 0 ? 3 : 0;
+}
+
+long primitiveSemantics_return_0_imm_03(long a, long b) {
+ return a != 0 ? 3 : 0;
+}
+
+long primitiveSemantics_return_0_imm_04(long a, long b) {
+ if (a)
+ b = 0;
+ else
+ b = 3;
+ return b;
+}
+
+long primitiveSemantics_return_0_imm_05(long a, long b) {
+ if (!a)
+ b = 0;
+ else
+ b = 3;
+ return b;
+}
+
+int primitiveSemantics_return_0_imm_06(int a, int b) { return a == 0 ? 0 : 3; }
+
+int primitiveSemantics_return_0_imm_07(int a, int b) { return a != 0 ? 0 : 3; }
+
+int primitiveSemantics_return_0_imm_08(int a, int b) { return a == 0 ? 3 : 0; }
+
+int primitiveSemantics_return_0_imm_09(int a, int b) { return a != 0 ? 3 : 0; }
+
+int primitiveSemantics_return_0_imm_10(int a, int b) {
+ if (a)
+ b = 0;
+ else
+ b = 3;
+ return b;
+}
+
+int primitiveSemantics_return_0_imm_11(int a, int b) {
+ if (!a)
+ b = 0;
+ else
+ b = 3;
+ return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
new file mode 100644
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_imm_imm_00(long a, long b) {
+ return a == 0 ? 4 : 6;
+}
+
+long primitiveSemantics_return_imm_imm_01(long a, long b) {
+ return a != 0 ? 4 : 6;
+}
+
+long primitiveSemantics_return_imm_imm_02(long a, long b) {
+ return a == 0 ? 6 : 4;
+}
+
+long primitiveSemantics_return_imm_imm_03(long a, long b) {
+ return a != 0 ? 6 : 4;
+}
+
+long primitiveSemantics_return_imm_imm_04(long a, long b) {
+ if (a)
+ b = 4;
+ else
+ b = 6;
+ return b;
+}
+
+long primitiveSemantics_return_imm_imm_05(long a, long b) {
+ if (!a)
+ b = 4;
+ else
+ b = 6;
+ return b;
+}
+
+int primitiveSemantics_return_imm_imm_06(int a, int b) {
+ return a == 0 ? 4 : 6;
+}
+
+int primitiveSemantics_return_imm_imm_07(int a, int b) {
+ return a != 0 ? 4 : 6;
+}
+
+int primitiveSemantics_return_imm_imm_08(int a, int b) {
+ return a == 0 ? 6 : 4;
+}
+
+int primitiveSemantics_return_imm_imm_09(int a, int b) {
+ return a != 0 ? 6 : 4;
+}
+
+int primitiveSemantics_return_imm_imm_10(int a, int b) {
+ if (a)
+ b = 4;
+ else
+ b = 6;
+ return b;
+}
+
+int primitiveSemantics_return_imm_imm_11(int a, int b) {
+ if (!a)
+ b = 4;
+ else
+ b = 6;
+ return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
new file mode 100644
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_imm_reg_00(long a, long b) {
+ return a == 0 ? 1 : b;
+}
+
+long primitiveSemantics_return_imm_reg_01(long a, long b) {
+ return a != 0 ? 1 : b;
+}
+
+long primitiveSemantics_return_imm_reg_02(long a, long b) {
+ return a == 0 ? b : 1;
+}
+
+long primitiveSemantics_return_imm_reg_03(long a, long b) {
+ return a != 0 ? b : 1;
+}
+
+long primitiveSemantics_return_imm_reg_04(long a, long b) {
+ if (a)
+ b = 1;
+ return b;
+}
+
+long primitiveSemantics_return_imm_reg_05(long a, long b) {
+ if (!a)
+ b = 1;
+ return b;
+}
+
+int primitiveSemantics_return_imm_reg_06(int a, int b) {
+ return a == 0 ? 1 : b;
+}
+
+int primitiveSemantics_return_imm_reg_07(int a, int b) {
+ return a != 0 ? 1 : b;
+}
+
+int primitiveSemantics_return_imm_reg_08(int a, int b) {
+ return a == 0 ? b : 1;
+}
+
+int primitiveSemantics_return_imm_reg_09(int a, int b) {
+ return a != 0 ? b : 1;
+}
+
+int primitiveSemantics_return_imm_reg_10(int a, int b) {
+ if (a)
+ b = 1;
+ return b;
+}
+
+int primitiveSemantics_return_imm_reg_11(int a, int b) {
+ if (!a)
+ b = 1;
+ return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 6 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */
new file mode 100644
@@ -0,0 +1,65 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */
+
+long primitiveSemantics_return_reg_reg_00(long a, long b, long c) {
+ return a == 0 ? c : b;
+}
+
+long primitiveSemantics_return_reg_reg_01(long a, long b, long c) {
+ return a != 0 ? c : b;
+}
+
+long primitiveSemantics_return_reg_reg_02(long a, long b, long c) {
+ return a == 0 ? b : c;
+}
+
+long primitiveSemantics_return_reg_reg_03(long a, long b, long c) {
+ return a != 0 ? b : c;
+}
+
+long primitiveSemantics_return_reg_reg_04(long a, long b, long c) {
+ if (a)
+ b = c;
+ return b;
+}
+
+long primitiveSemantics_return_reg_reg_05(long a, long b, long c) {
+ if (!a)
+ b = c;
+ return b;
+}
+
+int primitiveSemantics_return_reg_reg_06(int a, int b, int c) {
+ return a == 0 ? c : b;
+}
+
+int primitiveSemantics_return_reg_reg_07(int a, int b, int c) {
+ return a != 0 ? c : b;
+}
+
+int primitiveSemantics_return_reg_reg_08(int a, int b, int c) {
+ return a == 0 ? b : c;
+}
+
+int primitiveSemantics_return_reg_reg_09(int a, int b, int c) {
+ return a != 0 ? b : c;
+}
+
+int primitiveSemantics_return_reg_reg_10(int a, int b, int c) {
+ if (a)
+ b = c;
+ return b;
+}
+
+int primitiveSemantics_return_reg_reg_11(int a, int b, int c) {
+ if (!a)
+ b = c;
+ return b;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz" 12 } } */
+/* { dg-final { scan-assembler-times "czero.nez" 12 } } */
+/* { dg-final { scan-assembler-not "beq" } } */
+/* { dg-final { scan-assembler-not "bne" } } */