[NDS32] Refine movcc, cmov, cstore and cbranch patterns.
authorChung-Ju Wu <jasonwucj@gmail.com>
Wed, 4 Apr 2018 08:48:56 +0000 (08:48 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Wed, 4 Apr 2018 08:48:56 +0000 (08:48 +0000)
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

gcc/ChangeLog
gcc/config/nds32/nds32-md-auxiliary.c
gcc/config/nds32/nds32-protos.h
gcc/config/nds32/nds32.h
gcc/config/nds32/nds32.md
gcc/config/nds32/predicates.md

index d84cb00403db76542cf624575699825c041ff49c..651523fab1ef185ab7c3912646f493862b49b0b6 100644 (file)
@@ -1,3 +1,26 @@
+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>
 
        * config/nds32/nds32-doubleword.md: Refine all the instruction type.
index 5311b69ecf6a98995e00d2acff15f25b8a739c50..f707f19853027cb6c030deca95087de8db9ec42c 100644 (file)
@@ -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<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
 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 */
+         /*    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.  */
 bool
 nds32_long_call_p (rtx symbol)
index 6a3281be1ba851b993089a07bdc34494e98aebbd..97aad41840b5fe9ca67a15ebcfeffff9a7d5b994 100644 (file)
@@ -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.  */
 
index 42a1c1296a500a744523243b6cd3b7e72bb5d53d..e2f109766dbc1cc4a7134a4f2795f3ee2ccf31b5 100644 (file)
 #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))
index b105e26d437aca50880329a22e5e0d2eea75ec96..662be73d8e8e4c4c51057f39af434217e1d4b9c6 100644 (file)
 ;; 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 "mov<mode>cc"
+  [(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<mode>"
+  [(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<mode>"
+  [(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_<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
@@ -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)))])
 
index ad04b51baf26d68615e64a9f97e15765e07d32fa..7cf4635e1cf971342289f7865d9122a16f0cbdbd 100644 (file)
@@ -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"))
 
        (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)")))