Commit 6e9ca932 by Chung-Ju Wu Committed by Chung-Ju Wu

[NDS32] Refine movcc, cmov, cstore and cbranch patterns.

gcc/
	* config/nds32/nds32-md-auxiliary.c (nds32_inverse_cond_code,
	nds32_cond_code_str, output_cond_branch,
	output_cond_branch_compare_zero, nds32_expand_cbranch,
	nds32_expand_cstore, nds32_expand_movcc,
	nds32_output_cbranchsi4_equality_zero,
	nds32_output_cbranchsi4_equality_reg,
	nds32_output_cbranchsi4_equality_reg_or_const_int,
	nds32_output_cbranchsi4_greater_less_zero: New functions.
	* config/nds32/nds32-protos.h (nds32_expand_cbranch,
	nds32_expand_cstore, nds32_expand_movcc,
	nds32_output_cbranchsi4_equality_zero,
	nds32_output_cbranchsi4_equality_reg,
	nds32_output_cbranchsi4_equality_reg_or_const_int,
	nds32_output_cbranchsi4_greater_less_zero): Declare.
	* config/nds32/predicates.md (nds32_movecc_comparison_operator,
	nds32_rimm11s_operand): New predicates.
	* config/nds32/nds32.h (nds32_expand_result_type): New enum type.
	* config/nds32/nds32.md: Rewrite all the branch and conditional move
	patterns.

Co-Authored-By: Kito Cheng <kito.cheng@gmail.com>

From-SVN: r259070
parent 5ba6d585
2018-04-04 Chung-Ju Wu <jasonwucj@gmail.com>
Kito Cheng <kito.cheng@gmail.com>
* config/nds32/nds32-md-auxiliary.c (nds32_inverse_cond_code,
nds32_cond_code_str, output_cond_branch,
output_cond_branch_compare_zero, nds32_expand_cbranch,
nds32_expand_cstore, nds32_expand_movcc,
nds32_output_cbranchsi4_equality_zero,
nds32_output_cbranchsi4_equality_reg,
nds32_output_cbranchsi4_equality_reg_or_const_int,
nds32_output_cbranchsi4_greater_less_zero: New functions.
* config/nds32/nds32-protos.h (nds32_expand_cbranch,
nds32_expand_cstore, nds32_expand_movcc,
nds32_output_cbranchsi4_equality_zero,
nds32_output_cbranchsi4_equality_reg,
nds32_output_cbranchsi4_equality_reg_or_const_int,
nds32_output_cbranchsi4_greater_less_zero): Declare.
* config/nds32/predicates.md (nds32_movecc_comparison_operator,
nds32_rimm11s_operand): New predicates.
* config/nds32/nds32.h (nds32_expand_result_type): New enum type.
* config/nds32/nds32.md: Rewrite all the branch and conditional move
patterns.
2018-04-04 Kito Cheng <kito.cheng@gmail.com> 2018-04-04 Kito Cheng <kito.cheng@gmail.com>
* config/nds32/nds32-doubleword.md: Refine all the instruction type. * config/nds32/nds32-doubleword.md: Refine all the instruction type.
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include "output.h" #include "output.h"
#include "tm-constrs.h" #include "tm-constrs.h"
#include "expr.h" #include "expr.h"
#include "emit-rtl.h"
#include "explow.h"
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -76,7 +78,780 @@ nds32_byte_to_size (int byte) ...@@ -76,7 +78,780 @@ nds32_byte_to_size (int byte)
} }
} }
/* A helper function to return memory format. */ static int
nds32_inverse_cond_code (int code)
{
switch (code)
{
case NE:
return EQ;
case EQ:
return NE;
case GT:
return LE;
case LE:
return GT;
case GE:
return LT;
case LT:
return GE;
default:
gcc_unreachable ();
}
}
static const char *
nds32_cond_code_str (int code)
{
switch (code)
{
case NE:
return "ne";
case EQ:
return "eq";
case GT:
return "gt";
case LE:
return "le";
case GE:
return "ge";
case LT:
return "lt";
default:
gcc_unreachable ();
}
}
static void
output_cond_branch (int code, const char *suffix, bool r5_p,
bool long_jump_p, rtx *operands)
{
char pattern[256];
const char *cond_code;
if (r5_p && REGNO (operands[2]) == 5 && TARGET_16_BIT)
{
/* This is special case for beqs38 and bnes38,
second operand 2 can't be $r5 and it's almost meanless,
however it may occur after copy propgation. */
if (code == EQ)
{
/* $r5 == $r5 always taken! */
if (long_jump_p)
snprintf (pattern, sizeof (pattern),
"j\t%%3");
else
snprintf (pattern, sizeof (pattern),
"j8\t%%3");
}
else
/* Don't output anything since $r5 != $r5 never taken! */
pattern[0] = '\0';
}
else if (long_jump_p)
{
int inverse_code = nds32_inverse_cond_code (code);
cond_code = nds32_cond_code_str (inverse_code);
/* b<cond><suffix> $r0, $r1, .L0
=>
b<inverse_cond><suffix> $r0, $r1, .LCB0
j .L0
.LCB0:
or
b<cond><suffix> $r0, $r1, .L0
=>
b<inverse_cond><suffix> $r0, $r1, .LCB0
j .L0
.LCB0:
*/
if (r5_p && TARGET_16_BIT)
{
snprintf (pattern, sizeof (pattern),
"b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n.LCB%%=:",
cond_code);
}
else
{
snprintf (pattern, sizeof (pattern),
"b%s%s\t%%1, %%2, .LCB%%=\n\tj\t%%3\n.LCB%%=:",
cond_code, suffix);
}
}
else
{
cond_code = nds32_cond_code_str (code);
if (r5_p && TARGET_16_BIT)
{
/* b<cond>s38 $r1, .L0 */
snprintf (pattern, sizeof (pattern),
"b%ss38\t %%2, %%3", cond_code);
}
else
{
/* b<cond><suffix> $r0, $r1, .L0 */
snprintf (pattern, sizeof (pattern),
"b%s%s\t%%1, %%2, %%3", cond_code, suffix);
}
}
output_asm_insn (pattern, operands);
}
static void
output_cond_branch_compare_zero (int code, const char *suffix,
bool long_jump_p, rtx *operands,
bool ta_implied_p)
{
char pattern[256];
const char *cond_code;
if (long_jump_p)
{
int inverse_code = nds32_inverse_cond_code (code);
cond_code = nds32_cond_code_str (inverse_code);
if (ta_implied_p && TARGET_16_BIT)
{
/* b<cond>z<suffix> .L0
=>
b<inverse_cond>z<suffix> .LCB0
j .L0
.LCB0:
*/
snprintf (pattern, sizeof (pattern),
"b%sz%s\t.LCB%%=\n\tj\t%%2\n.LCB%%=:",
cond_code, suffix);
}
else
{
/* b<cond>z<suffix> $r0, .L0
=>
b<inverse_cond>z<suffix> $r0, .LCB0
j .L0
.LCB0:
*/
snprintf (pattern, sizeof (pattern),
"b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n.LCB%%=:",
cond_code, suffix);
}
}
else
{
cond_code = nds32_cond_code_str (code);
if (ta_implied_p && TARGET_16_BIT)
{
/* b<cond>z<suffix> .L0 */
snprintf (pattern, sizeof (pattern),
"b%sz%s\t%%2", cond_code, suffix);
}
else
{
/* b<cond>z<suffix> $r0, .L0 */
snprintf (pattern, sizeof (pattern),
"b%sz%s\t%%1, %%2", cond_code, suffix);
}
}
output_asm_insn (pattern, operands);
}
/* ------------------------------------------------------------------------ */
/* Auxiliary function for expand RTL pattern. */
enum nds32_expand_result_type
nds32_expand_cbranch (rtx *operands)
{
rtx tmp_reg;
enum rtx_code code;
code = GET_CODE (operands[0]);
/* If operands[2] is (const_int 0),
we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions.
So we have gcc generate original template rtx. */
if (GET_CODE (operands[2]) == CONST_INT)
if (INTVAL (operands[2]) == 0)
if ((code != GTU)
&& (code != GEU)
&& (code != LTU)
&& (code != LEU))
return EXPAND_CREATE_TEMPLATE;
/* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than)
behavior for the comparison, we might need to generate other
rtx patterns to achieve same semantic. */
switch (code)
{
case GT:
case GTU:
if (GET_CODE (operands[2]) == CONST_INT)
{
/* GT reg_A, const_int => !(LT reg_A, const_int + 1) */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
/* We want to plus 1 into the integer value
of operands[2] to create 'slt' instruction.
This caculation is performed on the host machine,
which may be 64-bit integer.
So the meaning of caculation result may be
different from the 32-bit nds32 target.
For example:
0x7fffffff + 0x1 -> 0x80000000,
this value is POSITIVE on 64-bit machine,
but the expected value on 32-bit nds32 target
should be NEGATIVE value.
Hence, instead of using GEN_INT(), we use gen_int_mode() to
explicitly create SImode constant rtx. */
enum rtx_code cmp_code;
rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
if (satisfies_constraint_Is15 (plus1))
{
operands[2] = plus1;
cmp_code = EQ;
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (
gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* GTU, use slt instruction */
emit_insn (
gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
}
else
{
cmp_code = NE;
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (
gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* GTU, use slt instruction */
emit_insn (
gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
}
PUT_CODE (operands[0], cmp_code);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
}
else
{
/* GT reg_A, reg_B => LT reg_B, reg_A */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* GTU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
PUT_CODE (operands[0], NE);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
}
case GE:
case GEU:
/* GE reg_A, reg_B => !(LT reg_A, reg_B) */
/* GE reg_A, const_int => !(LT reg_A, const_int) */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], EQ);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
case LT:
case LTU:
/* LT reg_A, reg_B => LT reg_A, reg_B */
/* LT reg_A, const_int => LT reg_A, const_int */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
if (code == LT)
{
/* LT, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* LTU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], NE);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
case LE:
case LEU:
if (GET_CODE (operands[2]) == CONST_INT)
{
/* LE reg_A, const_int => LT reg_A, const_int + 1 */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
enum rtx_code cmp_code;
/* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN).
We better have an assert here in case GCC does not properly
optimize it away. The INT_MAX here is 0x7fffffff for target. */
rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
if (satisfies_constraint_Is15 (plus1))
{
operands[2] = plus1;
cmp_code = NE;
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (
gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* LEU, use slt instruction */
emit_insn (
gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
}
else
{
cmp_code = EQ;
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (
gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* LEU, use slt instruction */
emit_insn (
gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
}
PUT_CODE (operands[0], cmp_code);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
}
else
{
/* LE reg_A, reg_B => !(LT reg_B, reg_A) */
if (optimize_size || optimize == 0)
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
else
tmp_reg = gen_reg_rtx (SImode);
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
PUT_CODE (operands[0], EQ);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
return EXPAND_DONE;
}
case EQ:
case NE:
/* NDS32 ISA has various form for eq/ne behavior no matter
what kind of the operand is.
So just generate original template rtx. */
/* Put operands[2] into register if operands[2] is a large
const_int or ISAv2. */
if (GET_CODE (operands[2]) == CONST_INT
&& (!satisfies_constraint_Is11 (operands[2])
|| TARGET_ISA_V2))
operands[2] = force_reg (SImode, operands[2]);
return EXPAND_CREATE_TEMPLATE;
default:
return EXPAND_FAIL;
}
}
enum nds32_expand_result_type
nds32_expand_cstore (rtx *operands)
{
rtx tmp_reg;
enum rtx_code code;
code = GET_CODE (operands[1]);
switch (code)
{
case EQ:
case NE:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A == const_int_B)
--> xori reg_C, reg_A, const_int_B
slti reg_R, reg_C, const_int_1
reg_R = (reg_A != const_int_B)
--> xori reg_C, reg_A, const_int_B
slti reg_R, const_int0, reg_C */
tmp_reg = gen_reg_rtx (SImode);
/* If the integer value is not in the range of imm15s,
we need to force register first because our addsi3 pattern
only accept nds32_rimm15s_operand predicate. */
rtx new_imm = gen_int_mode (-INTVAL (operands[3]), SImode);
if (satisfies_constraint_Is15 (new_imm))
emit_insn (gen_addsi3 (tmp_reg, operands[2], new_imm));
else
{
if (!(satisfies_constraint_Iu15 (operands[3])
|| (TARGET_EXT_PERF
&& satisfies_constraint_It15 (operands[3]))))
operands[3] = force_reg (SImode, operands[3]);
emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
}
if (code == EQ)
emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
else
emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
return EXPAND_DONE;
}
else
{
/* reg_R = (reg_A == reg_B)
--> xor reg_C, reg_A, reg_B
slti reg_R, reg_C, const_int_1
reg_R = (reg_A != reg_B)
--> xor reg_C, reg_A, reg_B
slti reg_R, const_int0, reg_C */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
if (code == EQ)
emit_insn (gen_slt_eq0 (operands[0], tmp_reg));
else
emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
return EXPAND_DONE;
}
case GT:
case GTU:
/* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */
/* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[3], operands[2]));
}
else
{
/* GTU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[3], operands[2]));
}
return EXPAND_DONE;
case GE:
case GEU:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A >= const_int_B)
--> movi reg_C, const_int_B - 1
slt reg_R, reg_C, reg_A */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_movsi (tmp_reg,
gen_int_mode (INTVAL (operands[3]) - 1,
SImode)));
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2]));
}
return EXPAND_DONE;
}
else
{
/* reg_R = (reg_A >= reg_B)
--> slt reg_R, reg_A, reg_B
xori reg_R, reg_R, const_int_1 */
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (operands[0],
operands[2], operands[3]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0],
operands[2], operands[3]));
}
/* perform 'not' behavior */
emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
return EXPAND_DONE;
}
case LT:
case LTU:
/* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */
/* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */
if (code == LT)
{
/* LT, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[2], operands[3]));
}
else
{
/* LTU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[2], operands[3]));
}
return EXPAND_DONE;
case LE:
case LEU:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A <= const_int_B)
--> movi reg_C, const_int_B + 1
slt reg_R, reg_A, reg_C */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_movsi (tmp_reg,
gen_int_mode (INTVAL (operands[3]) + 1,
SImode)));
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg));
}
return EXPAND_DONE;
}
else
{
/* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A
xori reg_R, reg_R, const_int_1 */
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (operands[0],
operands[3], operands[2]));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0],
operands[3], operands[2]));
}
/* perform 'not' behavior */
emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
return EXPAND_DONE;
}
default:
gcc_unreachable ();
}
}
enum nds32_expand_result_type
nds32_expand_movcc (rtx *operands)
{
enum rtx_code code = GET_CODE (operands[1]);
enum rtx_code new_code = code;
machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0));
rtx cmp_op0 = XEXP (operands[1], 0);
rtx cmp_op1 = XEXP (operands[1], 1);
rtx tmp;
if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)
&& XEXP (operands[1], 1) == const0_rtx)
{
/* If the operands[1] rtx is already (eq X 0) or (ne X 0),
we have gcc generate original template rtx. */
return EXPAND_CREATE_TEMPLATE;
}
else
{
/* Since there is only 'slt'(Set when Less Than) instruction for
comparison in Andes ISA, the major strategy we use here is to
convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination.
We design constraints properly so that the reload phase will assist
to make one source operand to use same register as result operand.
Then we can use cmovz/cmovn to catch the other source operand
which has different register. */
int reverse = 0;
/* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part
Strategy : Reverse condition and swap comparison operands
For example:
a <= b ? P : Q (LE or LEU)
--> a > b ? Q : P (reverse condition)
--> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU')
a >= b ? P : Q (GE or GEU)
--> a < b ? Q : P (reverse condition to achieve 'LT/LTU')
a < b ? P : Q (LT or LTU)
--> (NO NEED TO CHANGE, it is already 'LT/LTU')
a > b ? P : Q (GT or GTU)
--> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */
switch (code)
{
case GE: case GEU: case LE: case LEU:
new_code = reverse_condition (code);
reverse = 1;
break;
case EQ:
case NE:
/* no need to reverse condition */
break;
default:
return EXPAND_FAIL;
}
/* For '>' comparison operator, we swap operands
so that we can have 'LT/LTU' operator. */
if (new_code == GT || new_code == GTU)
{
tmp = cmp_op0;
cmp_op0 = cmp_op1;
cmp_op1 = tmp;
new_code = swap_condition (new_code);
}
/* Use a temporary register to store slt/slts result. */
tmp = gen_reg_rtx (SImode);
if (new_code == EQ || new_code == NE)
{
emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1));
/* tmp == 0 if cmp_op0 == cmp_op1. */
operands[1] = gen_rtx_fmt_ee (new_code, VOIDmode, tmp, const0_rtx);
}
else
{
/* This emit_insn will create corresponding 'slt/slts'
insturction. */
if (new_code == LT)
emit_insn (gen_slts_compare (tmp, cmp_op0, cmp_op1));
else if (new_code == LTU)
emit_insn (gen_slt_compare (tmp, cmp_op0, cmp_op1));
else
gcc_unreachable ();
/* Change comparison semantic into (eq X 0) or (ne X 0) behavior
so that cmovz or cmovn will be matched later.
For reverse condition cases, we want to create a semantic that:
(eq X 0) --> pick up "else" part
For normal cases, we want to create a semantic that:
(ne X 0) --> pick up "then" part
Later we will have cmovz/cmovn instruction pattern to
match corresponding behavior and output instruction. */
operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
VOIDmode, tmp, const0_rtx);
}
}
return EXPAND_CREATE_TEMPLATE;
}
/* ------------------------------------------------------------------------ */
/* Function to return memory format. */
enum nds32_16bit_address_type enum nds32_16bit_address_type
nds32_mem_format (rtx op) nds32_mem_format (rtx op)
{ {
...@@ -1146,6 +1921,190 @@ nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode) ...@@ -1146,6 +1921,190 @@ nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode)
} }
} }
const char *
nds32_output_cbranchsi4_equality_zero (rtx_insn *insn, rtx *operands)
{
enum rtx_code code;
bool long_jump_p = false;
code = GET_CODE (operands[0]);
/* This zero-comparison conditional branch has two forms:
32-bit instruction => beqz/bnez imm16s << 1
16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1
For 32-bit case,
we assume it is always reachable. (but check range -65500 ~ 65500)
For 16-bit case,
it must satisfy { 255 >= (label - pc) >= -256 } condition.
However, since the $pc for nds32 is at the beginning of the instruction,
we should leave some length space for current insn.
So we use range -250 ~ 250. */
switch (get_attr_length (insn))
{
case 8:
long_jump_p = true;
/* fall through */
case 2:
if (which_alternative == 0)
{
/* constraint: t */
/* b<cond>zs8 .L0
or
b<inverse_cond>zs8 .LCB0
j .L0
.LCB0:
*/
output_cond_branch_compare_zero (code, "s8", long_jump_p,
operands, true);
return "";
}
else if (which_alternative == 1)
{
/* constraint: l */
/* b<cond>z38 $r0, .L0
or
b<inverse_cond>z38 $r0, .LCB0
j .L0
.LCB0:
*/
output_cond_branch_compare_zero (code, "38", long_jump_p,
operands, false);
return "";
}
else
{
/* constraint: r */
/* For which_alternative==2, it should not be here. */
gcc_unreachable ();
}
case 10:
/* including constraints: t, l, and r */
long_jump_p = true;
/* fall through */
case 4:
/* including constraints: t, l, and r */
output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
return "";
default:
gcc_unreachable ();
}
}
const char *
nds32_output_cbranchsi4_equality_reg (rtx_insn *insn, rtx *operands)
{
enum rtx_code code;
bool long_jump_p, r5_p;
int insn_length;
insn_length = get_attr_length (insn);
long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
code = GET_CODE (operands[0]);
/* This register-comparison conditional branch has one form:
32-bit instruction => beq/bne imm14s << 1
For 32-bit case,
we assume it is always reachable. (but check range -16350 ~ 16350). */
switch (code)
{
case EQ:
case NE:
output_cond_branch (code, "", r5_p, long_jump_p, operands);
return "";
default:
gcc_unreachable ();
}
}
const char *
nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *insn,
rtx *operands)
{
enum rtx_code code;
bool long_jump_p, r5_p;
int insn_length;
insn_length = get_attr_length (insn);
long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false;
r5_p = (insn_length == 2 || insn_length == 8) ? true : false;
code = GET_CODE (operands[0]);
/* This register-comparison conditional branch has one form:
32-bit instruction => beq/bne imm14s << 1
32-bit instruction => beqc/bnec imm8s << 1
For 32-bit case, we assume it is always reachable.
(but check range -16350 ~ 16350 and -250 ~ 250). */
switch (code)
{
case EQ:
case NE:
if (which_alternative == 2)
{
/* r, Is11 */
/* b<cond>c */
output_cond_branch (code, "c", r5_p, long_jump_p, operands);
}
else
{
/* r, r */
/* v, r */
output_cond_branch (code, "", r5_p, long_jump_p, operands);
}
return "";
default:
gcc_unreachable ();
}
}
const char *
nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands)
{
enum rtx_code code;
bool long_jump_p;
int insn_length;
insn_length = get_attr_length (insn);
gcc_assert (insn_length == 4 || insn_length == 10);
long_jump_p = (insn_length == 10) ? true : false;
code = GET_CODE (operands[0]);
/* This zero-greater-less-comparison conditional branch has one form:
32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1
For 32-bit case, we assume it is always reachable.
(but check range -65500 ~ 65500). */
switch (code)
{
case GT:
case GE:
case LT:
case LE:
output_cond_branch_compare_zero (code, "", long_jump_p, operands, false);
break;
default:
gcc_unreachable ();
}
return "";
}
/* Return true X is need use long call. */ /* Return true X is need use long call. */
bool bool
nds32_long_call_p (rtx symbol) nds32_long_call_p (rtx symbol)
......
...@@ -116,6 +116,16 @@ extern bool nds32_symbol_load_store_p (rtx_insn *); ...@@ -116,6 +116,16 @@ extern bool nds32_symbol_load_store_p (rtx_insn *);
extern const char *nds32_output_casesi_pc_relative (rtx *); extern const char *nds32_output_casesi_pc_relative (rtx *);
extern const char *nds32_output_casesi (rtx *); extern const char *nds32_output_casesi (rtx *);
/* Auxiliary functions for conditional branch generation. */
extern enum nds32_expand_result_type nds32_expand_cbranch (rtx *);
extern enum nds32_expand_result_type nds32_expand_cstore (rtx *);
/* Auxiliary functions for conditional move generation. */
extern enum nds32_expand_result_type nds32_expand_movcc (rtx *);
/* Auxiliary functions to identify long-call symbol. */ /* Auxiliary functions to identify long-call symbol. */
extern bool nds32_long_call_p (rtx); extern bool nds32_long_call_p (rtx);
...@@ -132,6 +142,12 @@ extern const char *nds32_output_32bit_load (rtx *, int); ...@@ -132,6 +142,12 @@ extern const char *nds32_output_32bit_load (rtx *, int);
extern const char *nds32_output_32bit_load_s (rtx *, int); extern const char *nds32_output_32bit_load_s (rtx *, int);
extern const char *nds32_output_smw_single_word (rtx *); extern const char *nds32_output_smw_single_word (rtx *);
extern const char *nds32_output_lmw_single_word (rtx *); extern const char *nds32_output_lmw_single_word (rtx *);
extern const char *nds32_output_cbranchsi4_equality_zero (rtx_insn *, rtx *);
extern const char *nds32_output_cbranchsi4_equality_reg (rtx_insn *, rtx *);
extern const char *nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *,
rtx *);
extern const char *nds32_output_cbranchsi4_greater_less_zero (rtx_insn *, rtx *);
/* Auxiliary functions to output stack push/pop instruction. */ /* Auxiliary functions to output stack push/pop instruction. */
......
...@@ -33,6 +33,14 @@ ...@@ -33,6 +33,14 @@
#define NDS32_SYMBOL_REF_RODATA_P(x) \ #define NDS32_SYMBOL_REF_RODATA_P(x) \
((SYMBOL_REF_FLAGS (x) & NDS32_SYMBOL_FLAG_RODATA) != 0) ((SYMBOL_REF_FLAGS (x) & NDS32_SYMBOL_FLAG_RODATA) != 0)
/* Classifies expand result for expand helper function. */
enum nds32_expand_result_type
{
EXPAND_DONE,
EXPAND_FAIL,
EXPAND_CREATE_TEMPLATE
};
/* Computing the Length of an Insn. */ /* Computing the Length of an Insn. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ #define ADJUST_INSN_LENGTH(INSN, LENGTH) \
(LENGTH = nds32_adjust_insn_length (INSN, LENGTH)) (LENGTH = nds32_adjust_insn_length (INSN, LENGTH))
......
...@@ -801,128 +801,35 @@ ...@@ -801,128 +801,35 @@
;; Conditional Move patterns ;; Conditional Move patterns
;; ---------------------------------------------------------------------------- ;; ----------------------------------------------------------------------------
(define_expand "movsicc" (define_expand "mov<mode>cc"
[(set (match_operand:SI 0 "register_operand" "") [(set (match_operand:QIHISI 0 "register_operand" "")
(if_then_else:SI (match_operand 1 "comparison_operator" "") (if_then_else:QIHISI (match_operand 1 "nds32_movecc_comparison_operator" "")
(match_operand:SI 2 "register_operand" "") (match_operand:QIHISI 2 "register_operand" "")
(match_operand:SI 3 "register_operand" "")))] (match_operand:QIHISI 3 "register_operand" "")))]
"TARGET_CMOV" "TARGET_CMOV && !optimize_size"
{ {
if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) enum nds32_expand_result_type result = nds32_expand_movcc (operands);
&& GET_MODE (XEXP (operands[1], 0)) == SImode switch (result)
&& XEXP (operands[1], 1) == const0_rtx)
{
/* If the operands[1] rtx is already (eq X 0) or (ne X 0),
we have gcc generate original template rtx. */
goto create_template;
}
else
{ {
/* Since there is only 'slt'(Set when Less Than) instruction for case EXPAND_DONE:
comparison in Andes ISA, the major strategy we use here is to DONE;
convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination. break;
We design constraints properly so that the reload phase will assist case EXPAND_FAIL:
to make one source operand to use same register as result operand. FAIL;
Then we can use cmovz/cmovn to catch the other source operand break;
which has different register. */ case EXPAND_CREATE_TEMPLATE:
enum rtx_code code = GET_CODE (operands[1]); break;
enum rtx_code new_code = code; default:
rtx cmp_op0 = XEXP (operands[1], 0); gcc_unreachable ();
rtx cmp_op1 = XEXP (operands[1], 1);
rtx tmp;
int reverse = 0;
/* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part
Strategy : Reverse condition and swap comparison operands
For example:
a <= b ? P : Q (LE or LEU)
--> a > b ? Q : P (reverse condition)
--> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU')
a >= b ? P : Q (GE or GEU)
--> a < b ? Q : P (reverse condition to achieve 'LT/LTU')
a < b ? P : Q (LT or LTU)
--> (NO NEED TO CHANGE, it is already 'LT/LTU')
a > b ? P : Q (GT or GTU)
--> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */
switch (code)
{
case NE:
/* (a != b ? P : Q)
can be expressed as
(a == b ? Q : P)
so, fall through to reverse condition */
case GE: case GEU: case LE: case LEU:
new_code = reverse_condition (code);
reverse = 1;
break;
case EQ: case GT: case GTU: case LT: case LTU:
/* no need to reverse condition */
break;
default:
FAIL;
}
/* For '>' comparison operator, we swap operands
so that we can have 'LT/LTU' operator. */
if (new_code == GT || new_code == GTU)
{
tmp = cmp_op0;
cmp_op0 = cmp_op1;
cmp_op1 = tmp;
new_code = swap_condition (new_code);
}
/* Use a temporary register to store slt/slts result. */
tmp = gen_reg_rtx (SImode);
/* Split EQ and NE because we don't have direct comparison of EQ and NE.
If we don't split it, the conditional move transformation will fail
when producing (SET A (EQ B C)) or (SET A (NE B C)). */
if (new_code == EQ)
{
emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1));
emit_insn (gen_slt_compare (tmp, tmp, GEN_INT (1)));
}
else if (new_code == NE)
{
emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1));
emit_insn (gen_slt_compare (tmp, GEN_INT (0), tmp));
}
else
/* This emit_insn will create corresponding 'slt/slts' insturction. */
emit_insn (gen_rtx_SET (tmp, gen_rtx_fmt_ee (new_code, SImode,
cmp_op0, cmp_op1)));
/* Change comparison semantic into (eq X 0) or (ne X 0) behavior
so that cmovz or cmovn will be matched later.
For reverse condition cases, we want to create a semantic that:
(eq X 0) --> pick up "else" part
For normal cases, we want to create a semantic that:
(ne X 0) --> pick up "then" part
Later we will have cmovz/cmovn instruction pattern to
match corresponding behavior and output instruction. */
operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE,
VOIDmode, tmp, const0_rtx);
} }
create_template:
do {} while(0); /* dummy line */
}) })
(define_insn "cmovz" (define_insn "cmovz<mode>"
[(set (match_operand:SI 0 "register_operand" "=r, r") [(set (match_operand:QIHISI 0 "register_operand" "=r, r")
(if_then_else:SI (eq (match_operand:SI 1 "register_operand" " r, r") (if_then_else:QIHISI (eq (match_operand:SI 1 "register_operand" " r, r")
(const_int 0)) (const_int 0))
(match_operand:SI 2 "register_operand" " r, 0") (match_operand:QIHISI 2 "register_operand" " r, 0")
(match_operand:SI 3 "register_operand" " 0, r")))] (match_operand:QIHISI 3 "register_operand" " 0, r")))]
"TARGET_CMOV" "TARGET_CMOV"
"@ "@
cmovz\t%0, %2, %1 cmovz\t%0, %2, %1
...@@ -930,12 +837,12 @@ create_template: ...@@ -930,12 +837,12 @@ create_template:
[(set_attr "type" "alu") [(set_attr "type" "alu")
(set_attr "length" "4")]) (set_attr "length" "4")])
(define_insn "cmovn" (define_insn "cmovn<mode>"
[(set (match_operand:SI 0 "register_operand" "=r, r") [(set (match_operand:QIHISI 0 "register_operand" "=r, r")
(if_then_else:SI (ne (match_operand:SI 1 "register_operand" " r, r") (if_then_else:QIHISI (ne (match_operand:SI 1 "register_operand" " r, r")
(const_int 0)) (const_int 0))
(match_operand:SI 2 "register_operand" " r, 0") (match_operand:QIHISI 2 "register_operand" " r, 0")
(match_operand:SI 3 "register_operand" " 0, r")))] (match_operand:QIHISI 3 "register_operand" " 0, r")))]
"TARGET_CMOV" "TARGET_CMOV"
"@ "@
cmovn\t%0, %2, %1 cmovn\t%0, %2, %1
...@@ -943,6 +850,16 @@ create_template: ...@@ -943,6 +850,16 @@ create_template:
[(set_attr "type" "alu") [(set_attr "type" "alu")
(set_attr "length" "4")]) (set_attr "length" "4")])
;; A hotfix to help RTL combiner to merge a cmovn insn and a zero_extend insn.
;; It should be removed once after we change the expansion form of the cmovn.
(define_insn "*cmovn_simplified_<mode>"
[(set (match_operand:QIHISI 0 "register_operand" "=r")
(if_then_else:QIHISI (match_operand:SI 1 "register_operand" "r")
(match_operand:QIHISI 2 "register_operand" "r")
(match_operand:QIHISI 3 "register_operand" "0")))]
""
"cmovn\t%0, %2, %1"
[(set_attr "type" "alu")])
;; ---------------------------------------------------------------------------- ;; ----------------------------------------------------------------------------
;; Conditional Branch patterns ;; Conditional Branch patterns
...@@ -957,573 +874,188 @@ create_template: ...@@ -957,573 +874,188 @@ create_template:
(pc)))] (pc)))]
"" ""
{ {
rtx tmp_reg; enum nds32_expand_result_type result = nds32_expand_cbranch (operands);
enum rtx_code code; switch (result)
code = GET_CODE (operands[0]);
/* If operands[2] is (const_int 0),
we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions.
So we have gcc generate original template rtx. */
if (GET_CODE (operands[2]) == CONST_INT)
if (INTVAL (operands[2]) == 0)
if ((code != GTU)
&& (code != GEU)
&& (code != LTU)
&& (code != LEU))
goto create_template;
/* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than)
behavior for the comparison, we might need to generate other
rtx patterns to achieve same semantic. */
switch (code)
{ {
case GT: case EXPAND_DONE:
case GTU:
if (GET_CODE (operands[2]) == CONST_INT)
{
/* GT reg_A, const_int => !(LT reg_A, const_int + 1) */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
/* We want to plus 1 into the integer value
of operands[2] to create 'slt' instruction.
This caculation is performed on the host machine,
which may be 64-bit integer.
So the meaning of caculation result may be
different from the 32-bit nds32 target.
For example:
0x7fffffff + 0x1 -> 0x80000000,
this value is POSITIVE on 64-bit machine,
but the expected value on 32-bit nds32 target
should be NEGATIVE value.
Hence, instead of using GEN_INT(), we use gen_int_mode() to
explicitly create SImode constant rtx. */
operands[2] = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* GTU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], EQ);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE;
}
else
{
/* GT reg_A, reg_B => LT reg_B, reg_A */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* GTU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
PUT_CODE (operands[0], NE);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE;
}
case GE:
case GEU:
/* GE reg_A, reg_B => !(LT reg_A, reg_B) */
/* GE reg_A, const_int => !(LT reg_A, const_int) */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], EQ);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE; DONE;
break;
case LT: case EXPAND_FAIL:
case LTU:
/* LT reg_A, reg_B => LT reg_A, reg_B */
/* LT reg_A, const_int => LT reg_A, const_int */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
if (code == LT)
{
/* LT, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* LTU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], NE);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE;
case LE:
case LEU:
if (GET_CODE (operands[2]) == CONST_INT)
{
/* LE reg_A, const_int => LT reg_A, const_int + 1 */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
/* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN).
We better have an assert here in case GCC does not properly
optimize it away. The INT_MAX here is 0x7fffffff for target. */
gcc_assert (code != LE || INTVAL (operands[2]) != 0x7fffffff);
operands[2] = gen_int_mode (INTVAL (operands[2]) + 1, SImode);
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2]));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2]));
}
PUT_CODE (operands[0], NE);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE;
}
else
{
/* LE reg_A, reg_B => !(LT reg_B, reg_A) */
tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1]));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1]));
}
PUT_CODE (operands[0], EQ);
operands[1] = tmp_reg;
operands[2] = const0_rtx;
emit_insn (gen_cbranchsi4 (operands[0], operands[1],
operands[2], operands[3]));
DONE;
}
case EQ:
case NE:
/* NDS32 ISA has various form for eq/ne behavior no matter
what kind of the operand is.
So just generate original template rtx. */
goto create_template;
default:
FAIL; FAIL;
break;
case EXPAND_CREATE_TEMPLATE:
break;
default:
gcc_unreachable ();
} }
create_template:
do {} while(0); /* dummy line */
}) })
(define_insn "*cbranchsi4_equality_zero" (define_insn "cbranchsi4_equality_zero"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "nds32_equality_comparison_operator" (if_then_else (match_operator 0 "nds32_equality_comparison_operator"
[(match_operand:SI 1 "register_operand" "t, l, r") [(match_operand:SI 1 "register_operand" "t,l, r")
(const_int 0)]) (const_int 0)])
(label_ref (match_operand 2 "" "")) (label_ref (match_operand 2 "" ""))
(pc)))] (pc)))]
"" ""
{ {
enum rtx_code code; return nds32_output_cbranchsi4_equality_zero (insn, operands);
code = GET_CODE (operands[0]);
/* This zero-comparison conditional branch has two forms:
32-bit instruction => beqz/bnez imm16s << 1
16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1
For 32-bit case,
we assume it is always reachable. (but check range -65500 ~ 65500)
For 16-bit case,
it must satisfy { 255 >= (label - pc) >= -256 } condition.
However, since the $pc for nds32 is at the beginning of the instruction,
we should leave some length space for current insn.
So we use range -250 ~ 250. */
switch (get_attr_length (insn))
{
case 2:
if (which_alternative == 0)
{
/* constraint: t */
return (code == EQ) ? "beqzs8\t%2" : "bnezs8\t%2";
}
else if (which_alternative == 1)
{
/* constraint: l */
return (code == EQ) ? "beqz38\t%1, %2" : "bnez38\t%1, %2";
}
else
{
/* constraint: r */
/* For which_alternative==2, it should not be here. */
gcc_unreachable ();
}
case 4:
/* including constraints: t, l, and r */
return (code == EQ) ? "beqz\t%1, %2" : "bnez\t%1, %2";
case 6:
if (which_alternative == 0)
{
/* constraint: t */
if (code == EQ)
{
/* beqzs8 .L0
=>
bnezs8 .LCB0
j .L0
.LCB0:
*/
return "bnezs8\t.LCB%=\;j\t%2\n.LCB%=:";
}
else
{
/* bnezs8 .L0
=>
beqzs8 .LCB0
j .L0
.LCB0:
*/
return "beqzs8\t.LCB%=\;j\t%2\n.LCB%=:";
}
}
else if (which_alternative == 1)
{
/* constraint: l */
if (code == EQ)
{
/* beqz38 $r0, .L0
=>
bnez38 $r0, .LCB0
j .L0
.LCB0:
*/
return "bnez38\t%1, .LCB%=\;j\t%2\n.LCB%=:";
}
else
{
/* bnez38 $r0, .L0
=>
beqz38 $r0, .LCB0
j .L0
.LCB0:
*/
return "beqz38\t%1, .LCB%=\;j\t%2\n.LCB%=:";
}
}
else
{
/* constraint: r */
/* For which_alternative==2, it should not be here. */
gcc_unreachable ();
}
case 8:
/* constraint: t, l, r. */
if (code == EQ)
{
/* beqz $r8, .L0
=>
bnez $r8, .LCB0
j .L0
.LCB0:
*/
return "bnez\t%1, .LCB%=\;j\t%2\n.LCB%=:";
}
else
{
/* bnez $r8, .L0
=>
beqz $r8, .LCB0
j .L0
.LCB0:
*/
return "beqz\t%1, .LCB%=\;j\t%2\n.LCB%=:";
}
default:
gcc_unreachable ();
}
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "enabled" "yes") (set_attr_alternative "enabled"
[
;; Alternative 0
(if_then_else (match_test "TARGET_16_BIT")
(const_string "yes")
(const_string "no"))
;; Alternative 1
(if_then_else (match_test "TARGET_16_BIT")
(const_string "yes")
(const_string "no"))
;; Alternative 2
(const_string "yes")
])
(set_attr_alternative "length" (set_attr_alternative "length"
[ [
;; Alternative 0 ;; Alternative 0
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 2) (pc)) (const_int 250))) (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250))
(if_then_else (match_test "TARGET_16_BIT") (le (minus (match_dup 2) (pc)) (const_int 250)))
(const_int 2)
(const_int 4))
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 4)
(if_then_else (match_test "TARGET_16_BIT") (if_then_else (match_test "TARGET_16_BIT")
(const_int 6) (const_int 2)
(const_int 8)))) (const_int 4))
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 4)
(if_then_else (match_test "TARGET_16_BIT")
(const_int 8)
(const_int 10))))
(const_int 10))
;; Alternative 1 ;; Alternative 1
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 2) (pc)) (const_int 250))) (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250))
(if_then_else (match_test "TARGET_16_BIT") (le (minus (match_dup 2) (pc)) (const_int 250)))
(const_int 2) (if_then_else (match_test "TARGET_16_BIT")
(const_int 4)) (const_int 2)
(const_int 4))
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 4)
(if_then_else (match_test "TARGET_16_BIT")
(const_int 8)
(const_int 10))))
(const_int 10))
;; Alternative 2
(if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(le (minus (match_dup 2) (pc)) (const_int 65500))) (le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 4) (const_int 4)
(if_then_else (match_test "TARGET_16_BIT") (const_int 10))
(const_int 6) (const_int 10))
(const_int 8))))
;; Alternative 2
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 4)
(const_int 8))
])]) ])])
;; This pattern is dedicated to V2 ISA, ;; This pattern is dedicated to V2 ISA,
;; because V2 DOES NOT HAVE beqc/bnec instruction. ;; because V2 DOES NOT HAVE beqc/bnec instruction.
(define_insn "*cbranchsi4_equality_reg" (define_insn "cbranchsi4_equality_reg"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "nds32_equality_comparison_operator" (if_then_else (match_operator 0 "nds32_equality_comparison_operator"
[(match_operand:SI 1 "register_operand" "r") [(match_operand:SI 1 "register_operand" "v, r")
(match_operand:SI 2 "nds32_reg_constant_operand" "r")]) (match_operand:SI 2 "register_operand" "l, r")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"TARGET_ISA_V2" "TARGET_ISA_V2"
{ {
enum rtx_code code; return nds32_output_cbranchsi4_equality_reg (insn, operands);
code = GET_CODE (operands[0]);
/* This register-comparison conditional branch has one form:
32-bit instruction => beq/bne imm14s << 1
For 32-bit case,
we assume it is always reachable. (but check range -16350 ~ 16350). */
switch (code)
{
case EQ:
/* r, r */
switch (get_attr_length (insn))
{
case 4:
return "beq\t%1, %2, %3";
case 8:
/* beq $r0, $r1, .L0
=>
bne $r0, $r1, .LCB0
j .L0
.LCB0:
*/
return "bne\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
case NE:
/* r, r */
switch (get_attr_length (insn))
{
case 4:
return "bne\t%1, %2, %3";
case 8:
/* bne $r0, $r1, .L0
=>
beq $r0, $r1, .LCB0
j .L0
.LCB0:
*/
return "beq\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
default:
gcc_unreachable ();
}
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set (attr "length") (set_attr_alternative "enabled"
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) [
(le (minus (match_dup 3) (pc)) (const_int 16350))) ;; Alternative 0
(const_int 4) (if_then_else (match_test "TARGET_16_BIT")
(const_int 8)))]) (const_string "yes")
(const_string "no"))
;; Alternative 1
(const_string "yes")
])
(set_attr_alternative "length"
[
;; Alternative 0
(if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 250)))
(const_int 2)
(if_then_else (and (ge (minus (match_dup 3) (pc))
(const_int -16350))
(le (minus (match_dup 3) (pc))
(const_int 16350)))
(const_int 4)
(const_int 8)))
(const_int 8))
;; Alternative 1
(if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350))
(le (minus (match_dup 3) (pc)) (const_int 16350)))
(const_int 4)
(const_int 10))
(const_int 10))
])])
;; This pattern is dedicated to V3/V3M, ;; This pattern is dedicated to V3/V3M,
;; because V3/V3M DO HAVE beqc/bnec instruction. ;; because V3/V3M DO HAVE beqc/bnec instruction.
(define_insn "*cbranchsi4_equality_reg_or_const_int" (define_insn "cbranchsi4_equality_reg_or_const_int"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "nds32_equality_comparison_operator" (if_then_else (match_operator 0 "nds32_equality_comparison_operator"
[(match_operand:SI 1 "register_operand" "r, r") [(match_operand:SI 1 "register_operand" "v, r, r")
(match_operand:SI 2 "nds32_reg_constant_operand" "r, Is11")]) (match_operand:SI 2 "nds32_rimm11s_operand" "l, r, Is11")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"TARGET_ISA_V3 || TARGET_ISA_V3M" "TARGET_ISA_V3 || TARGET_ISA_V3M"
{ {
enum rtx_code code; return nds32_output_cbranchsi4_equality_reg_or_const_int (insn, operands);
code = GET_CODE (operands[0]);
/* This register-comparison conditional branch has one form:
32-bit instruction => beq/bne imm14s << 1
32-bit instruction => beqc/bnec imm8s << 1
For 32-bit case, we assume it is always reachable.
(but check range -16350 ~ 16350 and -250 ~ 250). */
switch (code)
{
case EQ:
if (which_alternative == 0)
{
/* r, r */
switch (get_attr_length (insn))
{
case 4:
return "beq\t%1, %2, %3";
case 8:
/* beq $r0, $r1, .L0
=>
bne $r0, $r1, .LCB0
j .L0
.LCB0:
*/
return "bne\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
}
else
{
/* r, Is11 */
switch (get_attr_length (insn))
{
case 4:
return "beqc\t%1, %2, %3";
case 8:
/* beqc $r0, constant, .L0
=>
bnec $r0, constant, .LCB0
j .L0
.LCB0:
*/
return "bnec\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
}
case NE:
if (which_alternative == 0)
{
/* r, r */
switch (get_attr_length (insn))
{
case 4:
return "bne\t%1, %2, %3";
case 8:
/* bne $r0, $r1, .L0
=>
beq $r0, $r1, .LCB0
j .L0
.LCB0:
*/
return "beq\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
}
else
{
/* r, Is11 */
switch (get_attr_length (insn))
{
case 4:
return "bnec\t%1, %2, %3";
case 8:
/* bnec $r0, constant, .L0
=>
beqc $r0, constant, .LCB0
j .L0
.LCB0:
*/
return "beqc\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:";
default:
gcc_unreachable ();
}
}
default:
gcc_unreachable ();
}
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr_alternative "enabled"
[
;; Alternative 0
(if_then_else (match_test "TARGET_16_BIT")
(const_string "yes")
(const_string "no"))
;; Alternative 1
(const_string "yes")
;; Alternative 2
(const_string "yes")
])
(set_attr_alternative "length" (set_attr_alternative "length"
[ [
;; Alternative 0 ;; Alternative 0
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 3) (pc)) (const_int 16350))) (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250))
(const_int 4) (le (minus (match_dup 3) (pc)) (const_int 250)))
(const_int 8)) (const_int 2)
(if_then_else (and (ge (minus (match_dup 3) (pc))
(const_int -16350))
(le (minus (match_dup 3) (pc))
(const_int 16350)))
(const_int 4)
(const_int 8)))
(const_int 8))
;; Alternative 1 ;; Alternative 1
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 3) (pc)) (const_int 250))) (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350))
(const_int 4) (le (minus (match_dup 3) (pc)) (const_int 16350)))
(const_int 8)) (const_int 4)
(const_int 10))
(const_int 10))
;; Alternative 2
(if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250))
(le (minus (match_dup 3) (pc)) (const_int 250)))
(const_int 4)
(const_int 10))
(const_int 10))
])]) ])])
...@@ -1536,80 +1068,16 @@ create_template: ...@@ -1536,80 +1068,16 @@ create_template:
(pc)))] (pc)))]
"" ""
{ {
enum rtx_code code; return nds32_output_cbranchsi4_greater_less_zero (insn, operands);
code = GET_CODE (operands[0]);
/* This zero-greater-less-comparison conditional branch has one form:
32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1
For 32-bit case, we assume it is always reachable.
(but check range -65500 ~ 65500). */
if (get_attr_length (insn) == 8)
{
/* The branch target is too far to simply use one
bgtz/bgez/bltz/blez instruction.
We need to reverse condition and use 'j' to jump to the target. */
switch (code)
{
case GT:
/* bgtz $r8, .L0
=>
blez $r8, .LCB0
j .L0
.LCB0:
*/
return "blez\t%1, .LCB%=\;j\t%2\n.LCB%=:";
case GE:
/* bgez $r8, .L0
=>
bltz $r8, .LCB0
j .L0
.LCB0:
*/
return "bltz\t%1, .LCB%=\;j\t%2\n.LCB%=:";
case LT:
/* bltz $r8, .L0
=>
bgez $r8, .LCB0
j .L0
.LCB0:
*/
return "bgez\t%1, .LCB%=\;j\t%2\n.LCB%=:";
case LE:
/* blez $r8, .L0
=>
bgtz $r8, .LCB0
j .L0
.LCB0:
*/
return "bgtz\t%1, .LCB%=\;j\t%2\n.LCB%=:";
default:
gcc_unreachable ();
}
}
switch (code)
{
case GT:
return "bgtz\t%1, %2";
case GE:
return "bgez\t%1, %2";
case LT:
return "bltz\t%1, %2";
case LE:
return "blez\t%1, %2";
default:
gcc_unreachable ();
}
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set (attr "length") (set (attr "length")
(if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 2) (pc)) (const_int 65500))) (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500))
(const_int 4) (le (minus (match_dup 2) (pc)) (const_int 65500)))
(const_int 8)))]) (const_int 4)
(const_int 10))
(const_int 10)))])
(define_expand "cstoresi4" (define_expand "cstoresi4"
...@@ -1619,228 +1087,77 @@ create_template: ...@@ -1619,228 +1087,77 @@ create_template:
(match_operand:SI 3 "nonmemory_operand" "")]))] (match_operand:SI 3 "nonmemory_operand" "")]))]
"" ""
{ {
rtx tmp_reg; enum nds32_expand_result_type result = nds32_expand_cstore (operands);
enum rtx_code code; switch (result)
code = GET_CODE (operands[1]);
switch (code)
{ {
case EQ: case EXPAND_DONE:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A == const_int_B)
--> addi reg_C, reg_A, -const_int_B
slti reg_R, reg_C, const_int_1 */
tmp_reg = gen_reg_rtx (SImode);
operands[3] = gen_int_mode (-INTVAL (operands[3]), SImode);
/* If the integer value is not in the range of imm15s,
we need to force register first because our addsi3 pattern
only accept nds32_rimm15s_operand predicate. */
if (!satisfies_constraint_Is15 (operands[3]))
operands[3] = force_reg (SImode, operands[3]);
emit_insn (gen_addsi3 (tmp_reg, operands[2], operands[3]));
emit_insn (gen_slt_compare (operands[0], tmp_reg, const1_rtx));
DONE;
}
else
{
/* reg_R = (reg_A == reg_B)
--> xor reg_C, reg_A, reg_B
slti reg_R, reg_C, const_int_1 */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
emit_insn (gen_slt_compare (operands[0], tmp_reg, const1_rtx));
DONE;
}
case NE:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A != const_int_B)
--> addi reg_C, reg_A, -const_int_B
slti reg_R, const_int_0, reg_C */
tmp_reg = gen_reg_rtx (SImode);
operands[3] = gen_int_mode (-INTVAL (operands[3]), SImode);
/* If the integer value is not in the range of imm15s,
we need to force register first because our addsi3 pattern
only accept nds32_rimm15s_operand predicate. */
if (!satisfies_constraint_Is15 (operands[3]))
operands[3] = force_reg (SImode, operands[3]);
emit_insn (gen_addsi3 (tmp_reg, operands[2], operands[3]));
emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
DONE;
}
else
{
/* reg_R = (reg_A != reg_B)
--> xor reg_C, reg_A, reg_B
slti reg_R, const_int_0, reg_C */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3]));
emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg));
DONE;
}
case GT:
case GTU:
/* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */
/* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */
if (code == GT)
{
/* GT, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[3], operands[2]));
}
else
{
/* GTU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[3], operands[2]));
}
DONE; DONE;
break;
case GE: case EXPAND_FAIL:
case GEU: FAIL;
if (GET_CODE (operands[3]) == CONST_INT) break;
{ case EXPAND_CREATE_TEMPLATE:
/* reg_R = (reg_A >= const_int_B) break;
--> movi reg_C, const_int_B - 1
slt reg_R, reg_C, reg_A */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_movsi (tmp_reg,
gen_int_mode (INTVAL (operands[3]) - 1,
SImode)));
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2]));
}
DONE;
}
else
{
/* reg_R = (reg_A >= reg_B)
--> slt reg_R, reg_A, reg_B
xori reg_R, reg_R, const_int_1 */
if (code == GE)
{
/* GE, use slts instruction */
emit_insn (gen_slts_compare (operands[0],
operands[2], operands[3]));
}
else
{
/* GEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0],
operands[2], operands[3]));
}
/* perform 'not' behavior */
emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
DONE;
}
case LT:
case LTU:
/* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */
/* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */
if (code == LT)
{
/* LT, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[2], operands[3]));
}
else
{
/* LTU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[2], operands[3]));
}
DONE;
case LE:
case LEU:
if (GET_CODE (operands[3]) == CONST_INT)
{
/* reg_R = (reg_A <= const_int_B)
--> movi reg_C, const_int_B + 1
slt reg_R, reg_A, reg_C */
tmp_reg = gen_reg_rtx (SImode);
emit_insn (gen_movsi (tmp_reg,
gen_int_mode (INTVAL (operands[3]) + 1,
SImode)));
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg));
}
DONE;
}
else
{
/* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A
xori reg_R, reg_R, const_int_1 */
if (code == LE)
{
/* LE, use slts instruction */
emit_insn (gen_slts_compare (operands[0],
operands[3], operands[2]));
}
else
{
/* LEU, use slt instruction */
emit_insn (gen_slt_compare (operands[0],
operands[3], operands[2]));
}
/* perform 'not' behavior */
emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx));
DONE;
}
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
}) })
(define_insn "slts_compare" (define_expand "slts_compare"
[(set (match_operand:SI 0 "register_operand" "=t, t, r, r") [(set (match_operand:SI 0 "register_operand" "")
(lt:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") (lt:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] (match_operand:SI 2 "general_operand" "")))]
""
{
if (!REG_P (operands[1]))
operands[1] = force_reg (SImode, operands[1]);
if (!REG_P (operands[2]) && !satisfies_constraint_Is15 (operands[2]))
operands[2] = force_reg (SImode, operands[2]);
})
(define_insn "slts_compare_impl"
[(set (match_operand:SI 0 "register_operand" "=t, t, r, r")
(lt:SI (match_operand:SI 1 "register_operand" " d, d, r, r")
(match_operand:SI 2 "nds32_rimm15s_operand" " r,Iu05, r, Is15")))]
"" ""
"@ "@
slts45\t%1, %2 slts45\t%1, %2
sltsi45\t%1, %2 sltsi45\t%1, %2
slts\t%0, %1, %2 slts\t%0, %1, %2
sltsi\t%0, %1, %2" sltsi\t%0, %1, %2"
[(set_attr "type" " alu, alu, alu, alu") [(set_attr "type" "alu, alu, alu, alu")
(set_attr "length" " 2, 2, 4, 4")]) (set_attr "length" " 2, 2, 4, 4")])
(define_insn "slt_eq0"
[(set (match_operand:SI 0 "register_operand" "=t, r")
(eq:SI (match_operand:SI 1 "register_operand" " d, r")
(const_int 0)))]
""
"@
slti45\t%1, 1
slti\t%0, %1, 1"
[(set_attr "type" "alu, alu")
(set_attr "length" " 2, 4")])
(define_expand "slt_compare"
[(set (match_operand:SI 0 "register_operand" "")
(ltu:SI (match_operand:SI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")))]
""
{
if (!REG_P (operands[1]))
operands[1] = force_reg (SImode, operands[1]);
if (!REG_P (operands[2]) && !satisfies_constraint_Is15 (operands[2]))
operands[2] = force_reg (SImode, operands[2]);
})
(define_insn "slt_compare" (define_insn "slt_compare_impl"
[(set (match_operand:SI 0 "register_operand" "=t, t, r, r") [(set (match_operand:SI 0 "register_operand" "=t, t, r, r")
(ltu:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") (ltu:SI (match_operand:SI 1 "register_operand" " d, d, r, r")
(match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] (match_operand:SI 2 "nds32_rimm15s_operand" " r, Iu05, r, Is15")))]
"" ""
"@ "@
slt45\t%1, %2 slt45\t%1, %2
...@@ -1883,10 +1200,12 @@ create_template: ...@@ -1883,10 +1200,12 @@ create_template:
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "enabled" "yes") (set_attr "enabled" "yes")
(set (attr "length") (set (attr "length")
(if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) (if_then_else (match_test "!CROSSING_JUMP_P (insn)")
(le (minus (match_dup 0) (pc)) (const_int 250))) (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250))
(if_then_else (match_test "TARGET_16_BIT") (le (minus (match_dup 0) (pc)) (const_int 250)))
(const_int 2) (if_then_else (match_test "TARGET_16_BIT")
(const_int 2)
(const_int 4))
(const_int 4)) (const_int 4))
(const_int 4)))]) (const_int 4)))])
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
(define_predicate "nds32_greater_less_comparison_operator" (define_predicate "nds32_greater_less_comparison_operator"
(match_code "gt,ge,lt,le")) (match_code "gt,ge,lt,le"))
(define_predicate "nds32_movecc_comparison_operator"
(match_code "eq,ne,le,leu,ge,geu"))
(define_special_predicate "nds32_logical_binary_operator" (define_special_predicate "nds32_logical_binary_operator"
(match_code "and,ior,xor")) (match_code "and,ior,xor"))
...@@ -39,6 +42,11 @@ ...@@ -39,6 +42,11 @@
(and (match_operand 0 "const_int_operand") (and (match_operand 0 "const_int_operand")
(match_test "satisfies_constraint_Is15 (op)")))) (match_test "satisfies_constraint_Is15 (op)"))))
(define_predicate "nds32_rimm11s_operand"
(ior (match_operand 0 "register_operand")
(and (match_operand 0 "const_int_operand")
(match_test "satisfies_constraint_Is11 (op)"))))
(define_predicate "nds32_imm5u_operand" (define_predicate "nds32_imm5u_operand"
(and (match_operand 0 "const_int_operand") (and (match_operand 0 "const_int_operand")
(match_test "satisfies_constraint_Iu05 (op)"))) (match_test "satisfies_constraint_Iu05 (op)")))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment