From: Chung-Ju Wu Date: Wed, 4 Apr 2018 08:48:56 +0000 (+0000) Subject: [NDS32] Refine movcc, cmov, cstore and cbranch patterns. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6e9ca9328ae625ad366d6a1043f2b8df58b56cb6;p=gcc.git [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 From-SVN: r259070 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d84cb00403d..651523fab1e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2018-04-04 Chung-Ju Wu + Kito Cheng + + * 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 * config/nds32/nds32-doubleword.md: Refine all the instruction type. diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c index 5311b69ecf6..f707f198530 100644 --- a/gcc/config/nds32/nds32-md-auxiliary.c +++ b/gcc/config/nds32/nds32-md-auxiliary.c @@ -37,6 +37,8 @@ #include "output.h" #include "tm-constrs.h" #include "expr.h" +#include "emit-rtl.h" +#include "explow.h" /* ------------------------------------------------------------------------ */ @@ -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 $r0, $r1, .L0 + => + b $r0, $r1, .LCB0 + j .L0 + .LCB0: + + or + + b $r0, $r1, .L0 + => + b $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) + { + /* bs38 $r1, .L0 */ + snprintf (pattern, sizeof (pattern), + "b%ss38\t %%2, %%3", cond_code); + } + else + { + /* b $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) + { + /* bz .L0 + => + bz .LCB0 + j .L0 + .LCB0: + */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t.LCB%%=\n\tj\t%%2\n.LCB%%=:", + cond_code, suffix); + } + else + { + /* bz $r0, .L0 + => + bz $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) + { + /* bz .L0 */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t%%2", cond_code, suffix); + } + else + { + /* bz $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 nds32_mem_format (rtx op) { @@ -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 */ + /* bzs8 .L0 + or + bzs8 .LCB0 + j .L0 + .LCB0: + */ + output_cond_branch_compare_zero (code, "s8", long_jump_p, + operands, true); + return ""; + } + else if (which_alternative == 1) + { + /* constraint: l */ + /* bz38 $r0, .L0 + or + bz38 $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 */ + /* bc */ + 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. */ bool nds32_long_call_p (rtx symbol) diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index 6a3281be1ba..97aad41840b 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -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 (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. */ extern bool nds32_long_call_p (rtx); @@ -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_smw_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. */ diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h index 42a1c1296a5..e2f109766db 100644 --- a/gcc/config/nds32/nds32.h +++ b/gcc/config/nds32/nds32.h @@ -33,6 +33,14 @@ #define NDS32_SYMBOL_REF_RODATA_P(x) \ ((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. */ #define ADJUST_INSN_LENGTH(INSN, LENGTH) \ (LENGTH = nds32_adjust_insn_length (INSN, LENGTH)) diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index b105e26d437..662be73d8e8 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -801,128 +801,35 @@ ;; Conditional Move patterns ;; ---------------------------------------------------------------------------- -(define_expand "movsicc" - [(set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (match_operand 1 "comparison_operator" "") - (match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "register_operand" "")))] - "TARGET_CMOV" +(define_expand "movcc" + [(set (match_operand:QIHISI 0 "register_operand" "") + (if_then_else:QIHISI (match_operand 1 "nds32_movecc_comparison_operator" "") + (match_operand:QIHISI 2 "register_operand" "") + (match_operand:QIHISI 3 "register_operand" "")))] + "TARGET_CMOV && !optimize_size" { - if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) - && GET_MODE (XEXP (operands[1], 0)) == SImode - && 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 + enum nds32_expand_result_type result = nds32_expand_movcc (operands); + switch (result) { - /* 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. */ - enum rtx_code code = GET_CODE (operands[1]); - enum rtx_code new_code = code; - rtx cmp_op0 = XEXP (operands[1], 0); - 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); + case EXPAND_DONE: + DONE; + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; + default: + gcc_unreachable (); } - -create_template: - do {} while(0); /* dummy line */ }) -(define_insn "cmovz" - [(set (match_operand:SI 0 "register_operand" "=r, r") - (if_then_else:SI (eq (match_operand:SI 1 "register_operand" " r, r") +(define_insn "cmovz" + [(set (match_operand:QIHISI 0 "register_operand" "=r, r") + (if_then_else:QIHISI (eq (match_operand:SI 1 "register_operand" " r, r") (const_int 0)) - (match_operand:SI 2 "register_operand" " r, 0") - (match_operand:SI 3 "register_operand" " 0, r")))] + (match_operand:QIHISI 2 "register_operand" " r, 0") + (match_operand:QIHISI 3 "register_operand" " 0, r")))] "TARGET_CMOV" "@ cmovz\t%0, %2, %1 @@ -930,12 +837,12 @@ create_template: [(set_attr "type" "alu") (set_attr "length" "4")]) -(define_insn "cmovn" - [(set (match_operand:SI 0 "register_operand" "=r, r") - (if_then_else:SI (ne (match_operand:SI 1 "register_operand" " r, r") +(define_insn "cmovn" + [(set (match_operand:QIHISI 0 "register_operand" "=r, r") + (if_then_else:QIHISI (ne (match_operand:SI 1 "register_operand" " r, r") (const_int 0)) - (match_operand:SI 2 "register_operand" " r, 0") - (match_operand:SI 3 "register_operand" " 0, r")))] + (match_operand:QIHISI 2 "register_operand" " r, 0") + (match_operand:QIHISI 3 "register_operand" " 0, r")))] "TARGET_CMOV" "@ cmovn\t%0, %2, %1 @@ -943,6 +850,16 @@ create_template: [(set_attr "type" "alu") (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_" + [(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 @@ -957,573 +874,188 @@ create_template: (pc)))] "" { - 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)) - 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) + enum nds32_expand_result_type result = nds32_expand_cbranch (operands); + switch (result) { - case GT: - 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])); - + case EXPAND_DONE: 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 */ - 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: + break; + case EXPAND_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) (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)]) (label_ref (match_operand 2 "" "")) (pc)))] "" { - enum rtx_code code; - - 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 (); - } + return nds32_output_cbranchsi4_equality_zero (insn, operands); } [(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" [ ;; Alternative 0 - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) - (le (minus (match_dup 2) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (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 "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 250))) (if_then_else (match_test "TARGET_16_BIT") - (const_int 6) - (const_int 8)))) + (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 1 - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) - (le (minus (match_dup 2) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) - (const_int 4)) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 250))) + (if_then_else (match_test "TARGET_16_BIT") + (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)) (le (minus (match_dup 2) (pc)) (const_int 65500))) (const_int 4) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 6) - (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)) + (const_int 10)) + (const_int 10)) ])]) ;; This pattern is dedicated to V2 ISA, ;; because V2 DOES NOT HAVE beqc/bnec instruction. -(define_insn "*cbranchsi4_equality_reg" +(define_insn "cbranchsi4_equality_reg" [(set (pc) (if_then_else (match_operator 0 "nds32_equality_comparison_operator" - [(match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "nds32_reg_constant_operand" "r")]) + [(match_operand:SI 1 "register_operand" "v, r") + (match_operand:SI 2 "register_operand" "l, r")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_ISA_V2" { - enum rtx_code code; - - 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 (); - } + return nds32_output_cbranchsi4_equality_reg (insn, operands); } [(set_attr "type" "branch") - (set (attr "length") - (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)))]) + (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") + ]) + (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, ;; 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) (if_then_else (match_operator 0 "nds32_equality_comparison_operator" - [(match_operand:SI 1 "register_operand" "r, r") - (match_operand:SI 2 "nds32_reg_constant_operand" "r, Is11")]) + [(match_operand:SI 1 "register_operand" "v, r, r") + (match_operand:SI 2 "nds32_rimm11s_operand" "l, r, Is11")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_ISA_V3 || TARGET_ISA_V3M" { - enum rtx_code code; - - 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 (); - } + return nds32_output_cbranchsi4_equality_reg_or_const_int (insn, operands); } [(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" [ ;; Alternative 0 - (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)) + (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 (and (ge (minus (match_dup 3) (pc)) (const_int -250)) - (le (minus (match_dup 3) (pc)) (const_int 250))) - (const_int 4) - (const_int 8)) + (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)) + ;; 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: (pc)))] "" { - enum rtx_code code; - - 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 (); - } + return nds32_output_cbranchsi4_greater_less_zero (insn, operands); } [(set_attr "type" "branch") (set (attr "length") - (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)))]) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (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 10)) + (const_int 10)))]) (define_expand "cstoresi4" @@ -1619,228 +1087,77 @@ create_template: (match_operand:SI 3 "nonmemory_operand" "")]))] "" { - rtx tmp_reg; - enum rtx_code code; - - code = GET_CODE (operands[1]); - - switch (code) + enum nds32_expand_result_type result = nds32_expand_cstore (operands); + switch (result) { - case EQ: - 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])); - } - + case EXPAND_DONE: 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])); - } - - 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; - } - - + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; default: gcc_unreachable (); } }) -(define_insn "slts_compare" - [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") - (lt:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") - (match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] +(define_expand "slts_compare" + [(set (match_operand:SI 0 "register_operand" "") + (lt: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 "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 sltsi45\t%1, %2 slts\t%0, %1, %2 sltsi\t%0, %1, %2" - [(set_attr "type" " alu, alu, alu, alu") - (set_attr "length" " 2, 2, 4, 4")]) + [(set_attr "type" "alu, alu, alu, alu") + (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" - [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") - (ltu:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") - (match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] +(define_insn "slt_compare_impl" + [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") + (ltu:SI (match_operand:SI 1 "register_operand" " d, d, r, r") + (match_operand:SI 2 "nds32_rimm15s_operand" " r, Iu05, r, Is15")))] "" "@ slt45\t%1, %2 @@ -1883,10 +1200,12 @@ create_template: [(set_attr "type" "branch") (set_attr "enabled" "yes") (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) - (le (minus (match_dup 0) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) + (le (minus (match_dup 0) (pc)) (const_int 250))) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) (const_int 4)) (const_int 4)))]) diff --git a/gcc/config/nds32/predicates.md b/gcc/config/nds32/predicates.md index ad04b51baf2..7cf4635e1cf 100644 --- a/gcc/config/nds32/predicates.md +++ b/gcc/config/nds32/predicates.md @@ -24,6 +24,9 @@ (define_predicate "nds32_greater_less_comparison_operator" (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" (match_code "and,ior,xor")) @@ -39,6 +42,11 @@ (and (match_operand 0 "const_int_operand") (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" (and (match_operand 0 "const_int_operand") (match_test "satisfies_constraint_Iu05 (op)")))