Move some external functions used by machine description patterns to nds32-md-auxilia...
authorjasonwucj <jasonwucj@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jul 2014 07:35:43 +0000 (07:35 +0000)
committerjasonwucj <jasonwucj@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 Jul 2014 07:35:43 +0000 (07:35 +0000)
gcc/
* config/nds32/nds32.c (nds32_byte_to_size): Move to ...
(nds32_output_casesi_pc_relative): Move to ...
(nds32_output_casesi): Move to ...
(nds32_mem_format): Move to ...
(nds32_output_16bit_store): Move to ...
(nds32_output_16bit_load): Move to ...
(nds32_output_32bit_store): Move to ...
(nds32_output_32bit_load): Move to ...
(nds32_output_32bit_load_s): Move to ...
(nds32_output_stack_push): Move to ...
(nds32_output_stack_pop): Move to ...
* config/nds32/nds32-md-auxiliary.c: ... here.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@212286 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/nds32/nds32-md-auxiliary.c
gcc/config/nds32/nds32.c

index 10ded35..cc364eb 100644 (file)
@@ -1,4 +1,21 @@
 2014-07-04  Chung-Ju Wu  <jasonwucj@gmail.com>
+           Kito Cheng  <kito@0xlab.org>
+           Monk Chiang  <sh.chiang04@gmail.com>
+
+       * config/nds32/nds32.c (nds32_byte_to_size): Move to ...
+       (nds32_output_casesi_pc_relative): Move to ...
+       (nds32_output_casesi): Move to ...
+       (nds32_mem_format): Move to ...
+       (nds32_output_16bit_store): Move to ...
+       (nds32_output_16bit_load): Move to ...
+       (nds32_output_32bit_store): Move to ...
+       (nds32_output_32bit_load): Move to ...
+       (nds32_output_32bit_load_s): Move to ...
+       (nds32_output_stack_push): Move to ...
+       (nds32_output_stack_pop): Move to ...
+       * config/nds32/nds32-md-auxiliary.c: ... here.
+
+2014-07-04  Chung-Ju Wu  <jasonwucj@gmail.com>
            Ling-Hua Tseng  <uranus@tinlans.org>
 
        * config/nds32/nds32-pipelines-auxiliary.c: Add comment to describe
index c3dcbba..419f4ef 100644 (file)
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
+
+/* ------------------------------------------------------------------------ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "calls.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"       /* Required by recog.h.  */
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"         /* For DFA state_t.  */
+#include "insn-codes.h"                /* For CODE_FOR_xxx.  */
+#include "reload.h"            /* For push_reload().  */
+#include "flags.h"
+#include "function.h"
+#include "expr.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "df.h"
+#include "tm_p.h"
+#include "tm-constrs.h"
+#include "optabs.h"            /* For GEN_FCN.  */
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h"         /* For add_builtin_function().  */
+#include "ggc.h"
+#include "builtins.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* A helper function to return character based on byte size.  */
+static char
+nds32_byte_to_size (int byte)
+{
+  switch (byte)
+    {
+    case 4:
+      return 'w';
+    case 2:
+      return 'h';
+    case 1:
+      return 'b';
+    default:
+      /* Normally it should not be here.  */
+      gcc_unreachable ();
+    }
+}
+
+/* A helper function to return memory format.  */
+enum nds32_16bit_address_type
+nds32_mem_format (rtx op)
+{
+  enum machine_mode mode_test;
+  int val;
+  int regno;
+
+  if (!TARGET_16_BIT)
+    return ADDRESS_NOT_16BIT_FORMAT;
+
+  mode_test = GET_MODE (op);
+
+  op = XEXP (op, 0);
+
+  /* 45 format.  */
+  if (GET_CODE (op) == REG && (mode_test == SImode))
+    return ADDRESS_REG;
+
+  /* 333 format for QI/HImode.  */
+  if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
+    return ADDRESS_LO_REG_IMM3U;
+
+  /* post_inc 333 format.  */
+  if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
+    {
+      regno = REGNO(XEXP (op, 0));
+
+      if (regno < 8)
+       return ADDRESS_POST_INC_LO_REG_IMM3U;
+    }
+
+  /* post_inc 333 format.  */
+  if ((GET_CODE (op) == POST_MODIFY)
+      && (mode_test == SImode)
+      && (REG_P (XEXP (XEXP (op, 1), 0)))
+      && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
+    {
+      regno = REGNO (XEXP (XEXP (op, 1), 0));
+      val = INTVAL (XEXP (XEXP (op, 1), 1));
+      if (regno < 8 && val < 32)
+       return ADDRESS_POST_INC_LO_REG_IMM3U;
+    }
+
+  if ((GET_CODE (op) == PLUS)
+      && (GET_CODE (XEXP (op, 0)) == REG)
+      && (GET_CODE (XEXP (op, 1)) == CONST_INT))
+    {
+      val = INTVAL (XEXP (op, 1));
+
+      regno = REGNO(XEXP (op, 0));
+
+      if (regno > 7
+         && regno != SP_REGNUM
+         && regno != FP_REGNUM)
+       return ADDRESS_NOT_16BIT_FORMAT;
+
+      switch (mode_test)
+       {
+       case QImode:
+         /* 333 format.  */
+         if (val >= 0 && val < 8 && regno < 8)
+           return ADDRESS_LO_REG_IMM3U;
+         break;
+
+       case HImode:
+         /* 333 format.  */
+         if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
+           return ADDRESS_LO_REG_IMM3U;
+         break;
+
+       case SImode:
+       case SFmode:
+       case DFmode:
+         /* fp imply 37 format.  */
+         if ((regno == FP_REGNUM) &&
+             (val >= 0 && val < 512 && (val % 4 == 0)))
+           return ADDRESS_FP_IMM7U;
+         /* sp imply 37 format.  */
+         else if ((regno == SP_REGNUM) &&
+                  (val >= 0 && val < 512 && (val % 4 == 0)))
+           return ADDRESS_SP_IMM7U;
+         /* 333 format.  */
+         else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
+           return ADDRESS_LO_REG_IMM3U;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return ADDRESS_NOT_16BIT_FORMAT;
+}
+
+/* Output 16-bit store.  */
+const char *
+nds32_output_16bit_store (rtx *operands, int byte)
+{
+  char pattern[100];
+  char size;
+  rtx code = XEXP (operands[0], 0);
+
+  size = nds32_byte_to_size (byte);
+
+  switch (nds32_mem_format (operands[0]))
+    {
+    case ADDRESS_REG:
+      operands[0] = code;
+      output_asm_insn ("swi450\t%1, [%0]", operands);
+      break;
+    case ADDRESS_LO_REG_IMM3U:
+      snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
+      output_asm_insn (pattern, operands);
+      break;
+    case ADDRESS_POST_INC_LO_REG_IMM3U:
+      snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
+      output_asm_insn (pattern, operands);
+      break;
+    case ADDRESS_FP_IMM7U:
+      output_asm_insn ("swi37\t%1, %0", operands);
+      break;
+    case ADDRESS_SP_IMM7U:
+      /* Get immediate value and set back to operands[1].  */
+      operands[0] = XEXP (code, 1);
+      output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
+      break;
+    default:
+      break;
+    }
+
+  return "";
+}
+
+/* Output 16-bit load.  */
+const char *
+nds32_output_16bit_load (rtx *operands, int byte)
+{
+  char pattern[100];
+  unsigned char size;
+  rtx code = XEXP (operands[1], 0);
+
+  size = nds32_byte_to_size (byte);
+
+  switch (nds32_mem_format (operands[1]))
+    {
+    case ADDRESS_REG:
+      operands[1] = code;
+      output_asm_insn ("lwi450\t%0, [%1]", operands);
+      break;
+    case ADDRESS_LO_REG_IMM3U:
+      snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
+      output_asm_insn (pattern, operands);
+      break;
+    case ADDRESS_POST_INC_LO_REG_IMM3U:
+      snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
+      output_asm_insn (pattern, operands);
+      break;
+    case ADDRESS_FP_IMM7U:
+      output_asm_insn ("lwi37\t%0, %1", operands);
+      break;
+    case ADDRESS_SP_IMM7U:
+      /* Get immediate value and set back to operands[0].  */
+      operands[1] = XEXP (code, 1);
+      output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
+      break;
+    default:
+      break;
+    }
+
+  return "";
+}
+
+/* Output 32-bit store.  */
+const char *
+nds32_output_32bit_store (rtx *operands, int byte)
+{
+  char pattern[100];
+  unsigned char size;
+  rtx code = XEXP (operands[0], 0);
+
+  size = nds32_byte_to_size (byte);
+
+  switch (GET_CODE (code))
+    {
+    case REG:
+      /* (mem (reg X))
+        => access location by using register,
+        use "sbi / shi / swi" */
+      snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
+      break;
+
+    case SYMBOL_REF:
+    case CONST:
+      /* (mem (symbol_ref X))
+        (mem (const (...)))
+        => access global variables,
+        use "sbi.gp / shi.gp / swi.gp" */
+      operands[0] = XEXP (operands[0], 0);
+      snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
+      break;
+
+    case POST_INC:
+      /* (mem (post_inc reg))
+        => access location by using register which will be post increment,
+        use "sbi.bi / shi.bi / swi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "s%ci.bi\t%%1, %%0, %d", size, byte);
+      break;
+
+    case POST_DEC:
+      /* (mem (post_dec reg))
+        => access location by using register which will be post decrement,
+        use "sbi.bi / shi.bi / swi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "s%ci.bi\t%%1, %%0, -%d", size, byte);
+      break;
+
+    case POST_MODIFY:
+      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (post_modify (reg) (plus (reg) (reg))))
+            => access location by using register which will be
+            post modified with reg,
+            use "sb.bi/ sh.bi / sw.bi" */
+         snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
+         break;
+       case CONST_INT:
+         /* (mem (post_modify (reg) (plus (reg) (const_int))))
+            => access location by using register which will be
+            post modified with const_int,
+            use "sbi.bi/ shi.bi / swi.bi" */
+         snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case PLUS:
+      switch (GET_CODE (XEXP (code, 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+            => access location by adding two registers,
+            use "sb / sh / sw" */
+         snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
+         break;
+       case CONST_INT:
+         /* (mem (plus reg const_int))
+            => access location by adding one register with const_int,
+            use "sbi / shi / swi" */
+         snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case LO_SUM:
+      operands[2] = XEXP (code, 1);
+      operands[0] = XEXP (code, 0);
+      snprintf (pattern, sizeof (pattern),
+               "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
+      break;
+
+    default:
+      abort ();
+    }
+
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Output 32-bit load.  */
+const char *
+nds32_output_32bit_load (rtx *operands, int byte)
+{
+  char pattern[100];
+  unsigned char size;
+  rtx code;
+
+  code = XEXP (operands[1], 0);
+
+  size = nds32_byte_to_size (byte);
+
+  switch (GET_CODE (code))
+    {
+    case REG:
+      /* (mem (reg X))
+        => access location by using register,
+        use "lbi / lhi / lwi" */
+      snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
+      break;
+
+    case SYMBOL_REF:
+    case CONST:
+      /* (mem (symbol_ref X))
+        (mem (const (...)))
+        => access global variables,
+        use "lbi.gp / lhi.gp / lwi.gp" */
+      operands[1] = XEXP (operands[1], 0);
+      snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
+      break;
+
+    case POST_INC:
+      /* (mem (post_inc reg))
+        => access location by using register which will be post increment,
+        use "lbi.bi / lhi.bi / lwi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "l%ci.bi\t%%0, %%1, %d", size, byte);
+      break;
+
+    case POST_DEC:
+      /* (mem (post_dec reg))
+        => access location by using register which will be post decrement,
+        use "lbi.bi / lhi.bi / lwi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "l%ci.bi\t%%0, %%1, -%d", size, byte);
+      break;
+
+    case POST_MODIFY:
+      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (post_modify (reg) (plus (reg) (reg))))
+            => access location by using register which will be
+            post modified with reg,
+            use "lb.bi/ lh.bi / lw.bi" */
+         snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
+         break;
+       case CONST_INT:
+         /* (mem (post_modify (reg) (plus (reg) (const_int))))
+            => access location by using register which will be
+            post modified with const_int,
+            use "lbi.bi/ lhi.bi / lwi.bi" */
+         snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case PLUS:
+      switch (GET_CODE (XEXP (code, 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+            use "lb / lh / lw" */
+         snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
+         break;
+       case CONST_INT:
+         /* (mem (plus reg const_int))
+            => access location by adding one register with const_int,
+            use "lbi / lhi / lwi" */
+         snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case LO_SUM:
+      operands[2] = XEXP (code, 1);
+      operands[1] = XEXP (code, 0);
+      snprintf (pattern, sizeof (pattern),
+               "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
+      break;
+
+    default:
+      abort ();
+    }
+
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Output 32-bit load with signed extension.  */
+const char *
+nds32_output_32bit_load_s (rtx *operands, int byte)
+{
+  char pattern[100];
+  unsigned char size;
+  rtx code;
+
+  code = XEXP (operands[1], 0);
+
+  size = nds32_byte_to_size (byte);
+
+  switch (GET_CODE (code))
+    {
+    case REG:
+      /* (mem (reg X))
+         => access location by using register,
+         use "lbsi / lhsi" */
+      snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
+      break;
+
+    case SYMBOL_REF:
+    case CONST:
+      /* (mem (symbol_ref X))
+         (mem (const (...)))
+         => access global variables,
+         use "lbsi.gp / lhsi.gp" */
+      operands[1] = XEXP (operands[1], 0);
+      snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
+      break;
+
+    case POST_INC:
+      /* (mem (post_inc reg))
+         => access location by using register which will be post increment,
+         use "lbsi.bi / lhsi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "l%csi.bi\t%%0, %%1, %d", size, byte);
+      break;
+
+    case POST_DEC:
+      /* (mem (post_dec reg))
+         => access location by using register which will be post decrement,
+         use "lbsi.bi / lhsi.bi" */
+      snprintf (pattern, sizeof (pattern),
+               "l%csi.bi\t%%0, %%1, -%d", size, byte);
+      break;
+
+    case POST_MODIFY:
+      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (post_modify (reg) (plus (reg) (reg))))
+            => access location by using register which will be
+            post modified with reg,
+            use "lbs.bi/ lhs.bi" */
+         snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
+         break;
+       case CONST_INT:
+         /* (mem (post_modify (reg) (plus (reg) (const_int))))
+            => access location by using register which will be
+            post modified with const_int,
+            use "lbsi.bi/ lhsi.bi" */
+         snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case PLUS:
+      switch (GET_CODE (XEXP (code, 1)))
+       {
+       case REG:
+       case SUBREG:
+         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
+            use "lbs / lhs" */
+         snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
+         break;
+       case CONST_INT:
+         /* (mem (plus reg const_int))
+            => access location by adding one register with const_int,
+            use "lbsi / lhsi" */
+         snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
+         break;
+       default:
+         abort ();
+       }
+      break;
+
+    case LO_SUM:
+      operands[2] = XEXP (code, 1);
+      operands[1] = XEXP (code, 0);
+      snprintf (pattern, sizeof (pattern),
+               "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
+      break;
+
+    default:
+      abort ();
+    }
+
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Function to output stack push operation.
+   We need to deal with normal stack push multiple or stack v3push.  */
+const char *
+nds32_output_stack_push (void)
+{
+  /* A string pattern for output_asm_insn().  */
+  char pattern[100];
+  /* The operands array which will be used in output_asm_insn().  */
+  rtx operands[3];
+  /* Pick up callee-saved first regno and last regno for further use.  */
+  int rb_regno = cfun->machine->callee_saved_regs_first_regno;
+  int re_regno = cfun->machine->callee_saved_regs_last_regno;
+
+  if (TARGET_V3PUSH)
+    {
+      /* For stack v3push:
+           operands[0]: Re
+           operands[1]: imm8u */
+
+      /* This variable is to check if 'push25 Re,imm8u' is available.  */
+      int sp_adjust;
+
+      /* Set operands[0].  */
+      operands[0] = gen_rtx_REG (SImode, re_regno);
+
+      /* Check if we can generate 'push25 Re,imm8u',
+         otherwise, generate 'push25 Re,0'.  */
+      sp_adjust = cfun->machine->local_size
+                 + cfun->machine->out_args_size
+                 + cfun->machine->callee_saved_area_padding_bytes;
+      if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
+         && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
+       operands[1] = GEN_INT (sp_adjust);
+      else
+       operands[1] = GEN_INT (0);
+
+      /* Create assembly code pattern.  */
+      snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
+    }
+  else
+    {
+      /* For normal stack push multiple:
+         operands[0]: Rb
+         operands[1]: Re
+         operands[2]: En4 */
+
+      /* This variable is used to check if we only need to generate En4 field.
+         As long as Rb==Re=SP_REGNUM, we set this variable to 1.  */
+      int push_en4_only_p = 0;
+
+      /* Set operands[0] and operands[1].  */
+      operands[0] = gen_rtx_REG (SImode, rb_regno);
+      operands[1] = gen_rtx_REG (SImode, re_regno);
+
+      /* 'smw.adm $sp,[$sp],$sp,0' means push nothing.  */
+      if (!cfun->machine->fp_size
+         && !cfun->machine->gp_size
+         && !cfun->machine->lp_size
+         && REGNO (operands[0]) == SP_REGNUM
+         && REGNO (operands[1]) == SP_REGNUM)
+       {
+         /* No need to generate instruction.  */
+         return "";
+       }
+      else
+       {
+         /* If Rb==Re=SP_REGNUM, we only need to generate En4 field.  */
+         if (REGNO (operands[0]) == SP_REGNUM
+             && REGNO (operands[1]) == SP_REGNUM)
+           push_en4_only_p = 1;
+
+         /* Create assembly code pattern.
+            We need to handle the form: "Rb, Re, { $fp $gp $lp }".  */
+         snprintf (pattern, sizeof (pattern),
+                   "push.s\t%s{%s%s%s }",
+                   push_en4_only_p ? "" : "%0, %1, ",
+                   cfun->machine->fp_size ? " $fp" : "",
+                   cfun->machine->gp_size ? " $gp" : "",
+                   cfun->machine->lp_size ? " $lp" : "");
+       }
+    }
+
+  /* We use output_asm_insn() to output assembly code by ourself.  */
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Function to output stack pop operation.
+   We need to deal with normal stack pop multiple or stack v3pop.  */
+const char *
+nds32_output_stack_pop (void)
+{
+  /* A string pattern for output_asm_insn().  */
+  char pattern[100];
+  /* The operands array which will be used in output_asm_insn().  */
+  rtx operands[3];
+  /* Pick up callee-saved first regno and last regno for further use.  */
+  int rb_regno = cfun->machine->callee_saved_regs_first_regno;
+  int re_regno = cfun->machine->callee_saved_regs_last_regno;
+
+  if (TARGET_V3PUSH)
+    {
+      /* For stack v3pop:
+           operands[0]: Re
+           operands[1]: imm8u */
+
+      /* This variable is to check if 'pop25 Re,imm8u' is available.  */
+      int sp_adjust;
+
+      /* Set operands[0].  */
+      operands[0] = gen_rtx_REG (SImode, re_regno);
+
+      /* Check if we can generate 'pop25 Re,imm8u',
+         otherwise, generate 'pop25 Re,0'.
+         We have to consider alloca issue as well.
+         If the function does call alloca(), the stack pointer is not fixed.
+         In that case, we cannot use 'pop25 Re,imm8u' directly.
+         We have to caculate stack pointer from frame pointer
+         and then use 'pop25 Re,0'.  */
+      sp_adjust = cfun->machine->local_size
+                 + cfun->machine->out_args_size
+                 + cfun->machine->callee_saved_area_padding_bytes;
+      if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
+         && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
+         && !cfun->calls_alloca)
+       operands[1] = GEN_INT (sp_adjust);
+      else
+       operands[1] = GEN_INT (0);
+
+      /* Create assembly code pattern.  */
+      snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
+    }
+  else
+    {
+      /* For normal stack pop multiple:
+         operands[0]: Rb
+         operands[1]: Re
+         operands[2]: En4 */
+
+      /* This variable is used to check if we only need to generate En4 field.
+         As long as Rb==Re=SP_REGNUM, we set this variable to 1.  */
+      int pop_en4_only_p = 0;
+
+      /* Set operands[0] and operands[1].  */
+      operands[0] = gen_rtx_REG (SImode, rb_regno);
+      operands[1] = gen_rtx_REG (SImode, re_regno);
+
+      /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing.  */
+      if (!cfun->machine->fp_size
+         && !cfun->machine->gp_size
+         && !cfun->machine->lp_size
+         && REGNO (operands[0]) == SP_REGNUM
+         && REGNO (operands[1]) == SP_REGNUM)
+       {
+         /* No need to generate instruction.  */
+         return "";
+       }
+      else
+       {
+         /* If Rb==Re=SP_REGNUM, we only need to generate En4 field.  */
+         if (REGNO (operands[0]) == SP_REGNUM
+             && REGNO (operands[1]) == SP_REGNUM)
+           pop_en4_only_p = 1;
+
+         /* Create assembly code pattern.
+            We need to handle the form: "Rb, Re, { $fp $gp $lp }".  */
+         snprintf (pattern, sizeof (pattern),
+                   "pop.s\t%s{%s%s%s }",
+                   pop_en4_only_p ? "" : "%0, %1, ",
+                   cfun->machine->fp_size ? " $fp" : "",
+                   cfun->machine->gp_size ? " $gp" : "",
+                   cfun->machine->lp_size ? " $lp" : "");
+       }
+    }
+
+  /* We use output_asm_insn() to output assembly code by ourself.  */
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Function to generate PC relative jump table.
+   Refer to nds32.md for more details.
+
+   The following is the sample for the case that diff value
+   can be presented in '.short' size.
+
+     addi    $r1, $r1, -(case_lower_bound)
+     slti    $ta, $r1, (case_number)
+     beqz    $ta, .L_skip_label
+
+     la      $ta, .L35             ! get jump table address
+     lh      $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
+     addi    $ta, $r1, $ta
+     jr5     $ta
+
+     ! jump table entry
+   L35:
+     .short  .L25-.L35
+     .short  .L26-.L35
+     .short  .L27-.L35
+     .short  .L28-.L35
+     .short  .L29-.L35
+     .short  .L30-.L35
+     .short  .L31-.L35
+     .short  .L32-.L35
+     .short  .L33-.L35
+     .short  .L34-.L35 */
+const char *
+nds32_output_casesi_pc_relative (rtx *operands)
+{
+  enum machine_mode mode;
+  rtx diff_vec;
+
+  diff_vec = PATTERN (NEXT_INSN (operands[1]));
+
+  gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+  /* Step C: "t <-- operands[1]".  */
+  output_asm_insn ("la\t$ta, %l1", operands);
+
+  /* Get the mode of each element in the difference vector.  */
+  mode = GET_MODE (diff_vec);
+
+  /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
+     where m is 0, 1, or 2 to load address-diff value from table.  */
+  switch (mode)
+    {
+    case QImode:
+      output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
+      break;
+    case HImode:
+      output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
+      break;
+    case SImode:
+      output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Step E: "t <-- z + t".
+     Add table label_ref with address-diff value to
+     obtain target case address.  */
+  output_asm_insn ("add\t$ta, %2, $ta", operands);
+
+  /* Step F: jump to target with register t.  */
+  if (TARGET_16_BIT)
+    return "jr5\t$ta";
+  else
+    return "jr\t$ta";
+}
+
+/* Function to generate normal jump table.  */
+const char *
+nds32_output_casesi (rtx *operands)
+{
+  /* Step C: "t <-- operands[1]".  */
+  output_asm_insn ("la\t$ta, %l1", operands);
+
+  /* Step D: "z <-- (mem (plus (operands[0] << 2) t))".  */
+  output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
+
+  /* No need to perform Step E, which is only used for
+     pc relative jump table.  */
+
+  /* Step F: jump to target with register z.  */
+  if (TARGET_16_BIT)
+    return "jr5\t%2";
+  else
+    return "jr\t%2";
+}
+
+/* ------------------------------------------------------------------------ */
index 7361912..eb3fbef 100644 (file)
@@ -1106,24 +1106,6 @@ nds32_legitimate_index_p (enum machine_mode outer_mode,
     }
 }
 
-/* A helper function to return character based on byte size.  */
-static char
-nds32_byte_to_size (int byte)
-{
-  switch (byte)
-    {
-    case 4:
-      return 'w';
-    case 2:
-      return 'h';
-    case 1:
-      return 'b';
-    default:
-      /* Normally it should not be here.  */
-      gcc_unreachable ();
-    }
-}
-
 /* A helper function to check if this function should contain prologue.  */
 static int
 nds32_have_prologue_p (void)
@@ -3436,767 +3418,6 @@ nds32_fp_as_gp_check_available (void)
   return 0;
 }
 
-
-/* Function to generate PC relative jump table.
-   Refer to nds32.md for more details.
-
-   The following is the sample for the case that diff value
-   can be presented in '.short' size.
-
-     addi    $r1, $r1, -(case_lower_bound)
-     slti    $ta, $r1, (case_number)
-     beqz    $ta, .L_skip_label
-
-     la      $ta, .L35             ! get jump table address
-     lh      $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
-     addi    $ta, $r1, $ta
-     jr5     $ta
-
-     ! jump table entry
-   L35:
-     .short  .L25-.L35
-     .short  .L26-.L35
-     .short  .L27-.L35
-     .short  .L28-.L35
-     .short  .L29-.L35
-     .short  .L30-.L35
-     .short  .L31-.L35
-     .short  .L32-.L35
-     .short  .L33-.L35
-     .short  .L34-.L35 */
-const char *
-nds32_output_casesi_pc_relative (rtx *operands)
-{
-  enum machine_mode mode;
-  rtx diff_vec;
-
-  diff_vec = PATTERN (NEXT_INSN (operands[1]));
-
-  gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
-
-  /* Step C: "t <-- operands[1]".  */
-  output_asm_insn ("la\t$ta, %l1", operands);
-
-  /* Get the mode of each element in the difference vector.  */
-  mode = GET_MODE (diff_vec);
-
-  /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
-     where m is 0, 1, or 2 to load address-diff value from table.  */
-  switch (mode)
-    {
-    case QImode:
-      output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
-      break;
-    case HImode:
-      output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
-      break;
-    case SImode:
-      output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  /* Step E: "t <-- z + t".
-     Add table label_ref with address-diff value to
-     obtain target case address.  */
-  output_asm_insn ("add\t$ta, %2, $ta", operands);
-
-  /* Step F: jump to target with register t.  */
-  if (TARGET_16_BIT)
-    return "jr5\t$ta";
-  else
-    return "jr\t$ta";
-}
-
-/* Function to generate normal jump table.  */
-const char *
-nds32_output_casesi (rtx *operands)
-{
-  /* Step C: "t <-- operands[1]".  */
-  output_asm_insn ("la\t$ta, %l1", operands);
-
-  /* Step D: "z <-- (mem (plus (operands[0] << 2) t))".  */
-  output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
-
-  /* No need to perform Step E, which is only used for
-     pc relative jump table.  */
-
-  /* Step F: jump to target with register z.  */
-  if (TARGET_16_BIT)
-    return "jr5\t%2";
-  else
-    return "jr\t%2";
-}
-
-
-/* Function to return memory format.  */
-enum nds32_16bit_address_type
-nds32_mem_format (rtx op)
-{
-  enum machine_mode mode_test;
-  int val;
-  int regno;
-
-  if (!TARGET_16_BIT)
-    return ADDRESS_NOT_16BIT_FORMAT;
-
-  mode_test = GET_MODE (op);
-
-  op = XEXP (op, 0);
-
-  /* 45 format.  */
-  if (GET_CODE (op) == REG && (mode_test == SImode))
-    return ADDRESS_REG;
-
-  /* 333 format for QI/HImode.  */
-  if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
-    return ADDRESS_LO_REG_IMM3U;
-
-  /* post_inc 333 format.  */
-  if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
-    {
-      regno = REGNO(XEXP (op, 0));
-
-      if (regno < 8)
-       return ADDRESS_POST_INC_LO_REG_IMM3U;
-    }
-
-  /* post_inc 333 format.  */
-  if ((GET_CODE (op) == POST_MODIFY)
-      && (mode_test == SImode)
-      && (REG_P (XEXP (XEXP (op, 1), 0)))
-      && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
-    {
-      regno = REGNO (XEXP (XEXP (op, 1), 0));
-      val = INTVAL (XEXP (XEXP (op, 1), 1));
-      if (regno < 8 && val < 32)
-       return ADDRESS_POST_INC_LO_REG_IMM3U;
-    }
-
-  if ((GET_CODE (op) == PLUS)
-      && (GET_CODE (XEXP (op, 0)) == REG)
-      && (GET_CODE (XEXP (op, 1)) == CONST_INT))
-    {
-      val = INTVAL (XEXP (op, 1));
-
-      regno = REGNO(XEXP (op, 0));
-
-      if (regno > 7
-         && regno != SP_REGNUM
-         && regno != FP_REGNUM)
-       return ADDRESS_NOT_16BIT_FORMAT;
-
-      switch (mode_test)
-       {
-       case QImode:
-         /* 333 format.  */
-         if (val >= 0 && val < 8 && regno < 8)
-           return ADDRESS_LO_REG_IMM3U;
-         break;
-
-       case HImode:
-         /* 333 format.  */
-         if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
-           return ADDRESS_LO_REG_IMM3U;
-         break;
-
-       case SImode:
-       case SFmode:
-       case DFmode:
-         /* fp imply 37 format.  */
-         if ((regno == FP_REGNUM) &&
-             (val >= 0 && val < 512 && (val % 4 == 0)))
-           return ADDRESS_FP_IMM7U;
-         /* sp imply 37 format.  */
-         else if ((regno == SP_REGNUM) &&
-                  (val >= 0 && val < 512 && (val % 4 == 0)))
-           return ADDRESS_SP_IMM7U;
-         /* 333 format.  */
-         else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
-           return ADDRESS_LO_REG_IMM3U;
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  return ADDRESS_NOT_16BIT_FORMAT;
-}
-
-/* Output 16-bit store.  */
-const char *
-nds32_output_16bit_store (rtx *operands, int byte)
-{
-  char pattern[100];
-  char size;
-  rtx code = XEXP (operands[0], 0);
-
-  size = nds32_byte_to_size (byte);
-
-  switch (nds32_mem_format (operands[0]))
-    {
-    case ADDRESS_REG:
-      operands[0] = code;
-      output_asm_insn ("swi450\t%1, [%0]", operands);
-      break;
-    case ADDRESS_LO_REG_IMM3U:
-      snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
-      output_asm_insn (pattern, operands);
-      break;
-    case ADDRESS_POST_INC_LO_REG_IMM3U:
-      snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
-      output_asm_insn (pattern, operands);
-      break;
-    case ADDRESS_FP_IMM7U:
-      output_asm_insn ("swi37\t%1, %0", operands);
-      break;
-    case ADDRESS_SP_IMM7U:
-      /* Get immediate value and set back to operands[1].  */
-      operands[0] = XEXP (code, 1);
-      output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
-      break;
-    default:
-      break;
-    }
-
-  return "";
-}
-
-/* Output 16-bit load.  */
-const char *
-nds32_output_16bit_load (rtx *operands, int byte)
-{
-  char pattern[100];
-  unsigned char size;
-  rtx code = XEXP (operands[1], 0);
-
-  size = nds32_byte_to_size (byte);
-
-  switch (nds32_mem_format (operands[1]))
-    {
-    case ADDRESS_REG:
-      operands[1] = code;
-      output_asm_insn ("lwi450\t%0, [%1]", operands);
-      break;
-    case ADDRESS_LO_REG_IMM3U:
-      snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
-      output_asm_insn (pattern, operands);
-      break;
-    case ADDRESS_POST_INC_LO_REG_IMM3U:
-      snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
-      output_asm_insn (pattern, operands);
-      break;
-    case ADDRESS_FP_IMM7U:
-      output_asm_insn ("lwi37\t%0, %1", operands);
-      break;
-    case ADDRESS_SP_IMM7U:
-      /* Get immediate value and set back to operands[0].  */
-      operands[1] = XEXP (code, 1);
-      output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
-      break;
-    default:
-      break;
-    }
-
-  return "";
-}
-
-/* Output 32-bit store.  */
-const char *
-nds32_output_32bit_store (rtx *operands, int byte)
-{
-  char pattern[100];
-  unsigned char size;
-  rtx code = XEXP (operands[0], 0);
-
-  size = nds32_byte_to_size (byte);
-
-  switch (GET_CODE (code))
-    {
-    case REG:
-      /* (mem (reg X))
-        => access location by using register,
-        use "sbi / shi / swi" */
-      snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
-      break;
-
-    case SYMBOL_REF:
-    case CONST:
-      /* (mem (symbol_ref X))
-        (mem (const (...)))
-        => access global variables,
-        use "sbi.gp / shi.gp / swi.gp" */
-      operands[0] = XEXP (operands[0], 0);
-      snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
-      break;
-
-    case POST_INC:
-      /* (mem (post_inc reg))
-        => access location by using register which will be post increment,
-        use "sbi.bi / shi.bi / swi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "s%ci.bi\t%%1, %%0, %d", size, byte);
-      break;
-
-    case POST_DEC:
-      /* (mem (post_dec reg))
-        => access location by using register which will be post decrement,
-        use "sbi.bi / shi.bi / swi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "s%ci.bi\t%%1, %%0, -%d", size, byte);
-      break;
-
-    case POST_MODIFY:
-      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (post_modify (reg) (plus (reg) (reg))))
-            => access location by using register which will be
-            post modified with reg,
-            use "sb.bi/ sh.bi / sw.bi" */
-         snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
-         break;
-       case CONST_INT:
-         /* (mem (post_modify (reg) (plus (reg) (const_int))))
-            => access location by using register which will be
-            post modified with const_int,
-            use "sbi.bi/ shi.bi / swi.bi" */
-         snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case PLUS:
-      switch (GET_CODE (XEXP (code, 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
-            => access location by adding two registers,
-            use "sb / sh / sw" */
-         snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
-         break;
-       case CONST_INT:
-         /* (mem (plus reg const_int))
-            => access location by adding one register with const_int,
-            use "sbi / shi / swi" */
-         snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case LO_SUM:
-      operands[2] = XEXP (code, 1);
-      operands[0] = XEXP (code, 0);
-      snprintf (pattern, sizeof (pattern),
-               "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
-      break;
-
-    default:
-      abort ();
-    }
-
-  output_asm_insn (pattern, operands);
-  return "";
-}
-
-/* Output 32-bit load.  */
-const char *
-nds32_output_32bit_load (rtx *operands, int byte)
-{
-  char pattern[100];
-  unsigned char size;
-  rtx code;
-
-  code = XEXP (operands[1], 0);
-
-  size = nds32_byte_to_size (byte);
-
-  switch (GET_CODE (code))
-    {
-    case REG:
-      /* (mem (reg X))
-        => access location by using register,
-        use "lbi / lhi / lwi" */
-      snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
-      break;
-
-    case SYMBOL_REF:
-    case CONST:
-      /* (mem (symbol_ref X))
-        (mem (const (...)))
-        => access global variables,
-        use "lbi.gp / lhi.gp / lwi.gp" */
-      operands[1] = XEXP (operands[1], 0);
-      snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
-      break;
-
-    case POST_INC:
-      /* (mem (post_inc reg))
-        => access location by using register which will be post increment,
-        use "lbi.bi / lhi.bi / lwi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "l%ci.bi\t%%0, %%1, %d", size, byte);
-      break;
-
-    case POST_DEC:
-      /* (mem (post_dec reg))
-        => access location by using register which will be post decrement,
-        use "lbi.bi / lhi.bi / lwi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "l%ci.bi\t%%0, %%1, -%d", size, byte);
-      break;
-
-    case POST_MODIFY:
-      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (post_modify (reg) (plus (reg) (reg))))
-            => access location by using register which will be
-            post modified with reg,
-            use "lb.bi/ lh.bi / lw.bi" */
-         snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
-         break;
-       case CONST_INT:
-         /* (mem (post_modify (reg) (plus (reg) (const_int))))
-            => access location by using register which will be
-            post modified with const_int,
-            use "lbi.bi/ lhi.bi / lwi.bi" */
-         snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case PLUS:
-      switch (GET_CODE (XEXP (code, 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
-            use "lb / lh / lw" */
-         snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
-         break;
-       case CONST_INT:
-         /* (mem (plus reg const_int))
-            => access location by adding one register with const_int,
-            use "lbi / lhi / lwi" */
-         snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case LO_SUM:
-      operands[2] = XEXP (code, 1);
-      operands[1] = XEXP (code, 0);
-      snprintf (pattern, sizeof (pattern),
-               "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
-      break;
-
-    default:
-      abort ();
-    }
-
-  output_asm_insn (pattern, operands);
-  return "";
-}
-
-/* Output 32-bit load with signed extension.  */
-const char *
-nds32_output_32bit_load_s (rtx *operands, int byte)
-{
-  char pattern[100];
-  unsigned char size;
-  rtx code;
-
-  code = XEXP (operands[1], 0);
-
-  size = nds32_byte_to_size (byte);
-
-  switch (GET_CODE (code))
-    {
-    case REG:
-      /* (mem (reg X))
-         => access location by using register,
-         use "lbsi / lhsi" */
-      snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
-      break;
-
-    case SYMBOL_REF:
-    case CONST:
-      /* (mem (symbol_ref X))
-         (mem (const (...)))
-         => access global variables,
-         use "lbsi.gp / lhsi.gp" */
-      operands[1] = XEXP (operands[1], 0);
-      snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
-      break;
-
-    case POST_INC:
-      /* (mem (post_inc reg))
-         => access location by using register which will be post increment,
-         use "lbsi.bi / lhsi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "l%csi.bi\t%%0, %%1, %d", size, byte);
-      break;
-
-    case POST_DEC:
-      /* (mem (post_dec reg))
-         => access location by using register which will be post decrement,
-         use "lbsi.bi / lhsi.bi" */
-      snprintf (pattern, sizeof (pattern),
-               "l%csi.bi\t%%0, %%1, -%d", size, byte);
-      break;
-
-    case POST_MODIFY:
-      switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (post_modify (reg) (plus (reg) (reg))))
-            => access location by using register which will be
-            post modified with reg,
-            use "lbs.bi/ lhs.bi" */
-         snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
-         break;
-       case CONST_INT:
-         /* (mem (post_modify (reg) (plus (reg) (const_int))))
-            => access location by using register which will be
-            post modified with const_int,
-            use "lbsi.bi/ lhsi.bi" */
-         snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case PLUS:
-      switch (GET_CODE (XEXP (code, 1)))
-       {
-       case REG:
-       case SUBREG:
-         /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
-            use "lbs / lhs" */
-         snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
-         break;
-       case CONST_INT:
-         /* (mem (plus reg const_int))
-            => access location by adding one register with const_int,
-            use "lbsi / lhsi" */
-         snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
-         break;
-       default:
-         abort ();
-       }
-      break;
-
-    case LO_SUM:
-      operands[2] = XEXP (code, 1);
-      operands[1] = XEXP (code, 0);
-      snprintf (pattern, sizeof (pattern),
-               "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
-      break;
-
-    default:
-      abort ();
-    }
-
-  output_asm_insn (pattern, operands);
-  return "";
-}
-
-/* Function to output stack push operation.
-   We need to deal with normal stack push multiple or stack v3push.  */
-const char *
-nds32_output_stack_push (void)
-{
-  /* A string pattern for output_asm_insn().  */
-  char pattern[100];
-  /* The operands array which will be used in output_asm_insn().  */
-  rtx operands[3];
-  /* Pick up callee-saved first regno and last regno for further use.  */
-  int rb_regno = cfun->machine->callee_saved_regs_first_regno;
-  int re_regno = cfun->machine->callee_saved_regs_last_regno;
-
-  if (TARGET_V3PUSH)
-    {
-      /* For stack v3push:
-           operands[0]: Re
-           operands[1]: imm8u */
-
-      /* This variable is to check if 'push25 Re,imm8u' is available.  */
-      int sp_adjust;
-
-      /* Set operands[0].  */
-      operands[0] = gen_rtx_REG (SImode, re_regno);
-
-      /* Check if we can generate 'push25 Re,imm8u',
-         otherwise, generate 'push25 Re,0'.  */
-      sp_adjust = cfun->machine->local_size
-                 + cfun->machine->out_args_size
-                 + cfun->machine->callee_saved_area_padding_bytes;
-      if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
-         && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
-       operands[1] = GEN_INT (sp_adjust);
-      else
-       operands[1] = GEN_INT (0);
-
-      /* Create assembly code pattern.  */
-      snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
-    }
-  else
-    {
-      /* For normal stack push multiple:
-         operands[0]: Rb
-         operands[1]: Re
-         operands[2]: En4 */
-
-      /* This variable is used to check if we only need to generate En4 field.
-         As long as Rb==Re=SP_REGNUM, we set this variable to 1.  */
-      int push_en4_only_p = 0;
-
-      /* Set operands[0] and operands[1].  */
-      operands[0] = gen_rtx_REG (SImode, rb_regno);
-      operands[1] = gen_rtx_REG (SImode, re_regno);
-
-      /* 'smw.adm $sp,[$sp],$sp,0' means push nothing.  */
-      if (!cfun->machine->fp_size
-         && !cfun->machine->gp_size
-         && !cfun->machine->lp_size
-         && REGNO (operands[0]) == SP_REGNUM
-         && REGNO (operands[1]) == SP_REGNUM)
-       {
-         /* No need to generate instruction.  */
-         return "";
-       }
-      else
-       {
-         /* If Rb==Re=SP_REGNUM, we only need to generate En4 field.  */
-         if (REGNO (operands[0]) == SP_REGNUM
-             && REGNO (operands[1]) == SP_REGNUM)
-           push_en4_only_p = 1;
-
-         /* Create assembly code pattern.
-            We need to handle the form: "Rb, Re, { $fp $gp $lp }".  */
-         snprintf (pattern, sizeof (pattern),
-                   "push.s\t%s{%s%s%s }",
-                   push_en4_only_p ? "" : "%0, %1, ",
-                   cfun->machine->fp_size ? " $fp" : "",
-                   cfun->machine->gp_size ? " $gp" : "",
-                   cfun->machine->lp_size ? " $lp" : "");
-       }
-    }
-
-  /* We use output_asm_insn() to output assembly code by ourself.  */
-  output_asm_insn (pattern, operands);
-  return "";
-}
-
-/* Function to output stack pop operation.
-   We need to deal with normal stack pop multiple or stack v3pop.  */
-const char *
-nds32_output_stack_pop (void)
-{
-  /* A string pattern for output_asm_insn().  */
-  char pattern[100];
-  /* The operands array which will be used in output_asm_insn().  */
-  rtx operands[3];
-  /* Pick up callee-saved first regno and last regno for further use.  */
-  int rb_regno = cfun->machine->callee_saved_regs_first_regno;
-  int re_regno = cfun->machine->callee_saved_regs_last_regno;
-
-  if (TARGET_V3PUSH)
-    {
-      /* For stack v3pop:
-           operands[0]: Re
-           operands[1]: imm8u */
-
-      /* This variable is to check if 'pop25 Re,imm8u' is available.  */
-      int sp_adjust;
-
-      /* Set operands[0].  */
-      operands[0] = gen_rtx_REG (SImode, re_regno);
-
-      /* Check if we can generate 'pop25 Re,imm8u',
-         otherwise, generate 'pop25 Re,0'.
-         We have to consider alloca issue as well.
-         If the function does call alloca(), the stack pointer is not fixed.
-         In that case, we cannot use 'pop25 Re,imm8u' directly.
-         We have to caculate stack pointer from frame pointer
-         and then use 'pop25 Re,0'.  */
-      sp_adjust = cfun->machine->local_size
-                 + cfun->machine->out_args_size
-                 + cfun->machine->callee_saved_area_padding_bytes;
-      if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
-         && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
-         && !cfun->calls_alloca)
-       operands[1] = GEN_INT (sp_adjust);
-      else
-       operands[1] = GEN_INT (0);
-
-      /* Create assembly code pattern.  */
-      snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
-    }
-  else
-    {
-      /* For normal stack pop multiple:
-         operands[0]: Rb
-         operands[1]: Re
-         operands[2]: En4 */
-
-      /* This variable is used to check if we only need to generate En4 field.
-         As long as Rb==Re=SP_REGNUM, we set this variable to 1.  */
-      int pop_en4_only_p = 0;
-
-      /* Set operands[0] and operands[1].  */
-      operands[0] = gen_rtx_REG (SImode, rb_regno);
-      operands[1] = gen_rtx_REG (SImode, re_regno);
-
-      /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing.  */
-      if (!cfun->machine->fp_size
-         && !cfun->machine->gp_size
-         && !cfun->machine->lp_size
-         && REGNO (operands[0]) == SP_REGNUM
-         && REGNO (operands[1]) == SP_REGNUM)
-       {
-         /* No need to generate instruction.  */
-         return "";
-       }
-      else
-       {
-         /* If Rb==Re=SP_REGNUM, we only need to generate En4 field.  */
-         if (REGNO (operands[0]) == SP_REGNUM
-             && REGNO (operands[1]) == SP_REGNUM)
-           pop_en4_only_p = 1;
-
-         /* Create assembly code pattern.
-            We need to handle the form: "Rb, Re, { $fp $gp $lp }".  */
-         snprintf (pattern, sizeof (pattern),
-                   "pop.s\t%s{%s%s%s }",
-                   pop_en4_only_p ? "" : "%0, %1, ",
-                   cfun->machine->fp_size ? " $fp" : "",
-                   cfun->machine->gp_size ? " $gp" : "",
-                   cfun->machine->lp_size ? " $lp" : "");
-       }
-    }
-
-  /* We use output_asm_insn() to output assembly code by ourself.  */
-  output_asm_insn (pattern, operands);
-  return "";
-}
-
 /* Return align 2 (log base 2) if the next instruction of LABEL is 4 byte.  */
 int
 nds32_target_alignment (rtx label)