[NDS32] Refine prologue and epilogue code generation.
authorMonk Chiang <sh.chiang04@gmail.com>
Mon, 12 Mar 2018 01:21:57 +0000 (01:21 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Mon, 12 Mar 2018 01:21:57 +0000 (01:21 +0000)
gcc/
* config/nds32/nds32.c (nds32_compute_stack_frame,
nds32_emit_stack_push_multiple, nds32_emit_stack_pop_multiple,
nds32_emit_stack_v3push, nds32_emit_stack_v3pop,
nds32_emit_adjust_frame, nds32_expand_prologue, nds32_expand_epilogue,
nds32_expand_prologue_v3push, nds32_expand_epilogue_v3pop): Refine.
* config/nds32/nds32.h (NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM,
NDS32_LAST_CALLEE_SAVE_GPR_REGNUM, NDS32_V3PUSH_AVAILABLE_P): New.
* config/nds32/nds32.md (prologue, epilogue): Use macro
NDS32_V3PUSH_AVAILABLE_P to do checking.

Co-Authored-By: Chung-Ju Wu <jasonwucj@gmail.com>
Co-Authored-By: Kito Cheng <kito.cheng@gmail.com>
From-SVN: r258442

gcc/ChangeLog
gcc/config/nds32/nds32.c
gcc/config/nds32/nds32.h
gcc/config/nds32/nds32.md

index 85062c0..aad7f0e 100644 (file)
@@ -1,3 +1,17 @@
+2018-03-11  Monk Chiang  <sh.chiang04@gmail.com>
+           Kito Cheng  <kito.cheng@gmail.com>
+           Chung-Ju Wu  <jasonwucj@gmail.com>
+
+       * config/nds32/nds32.c (nds32_compute_stack_frame,
+       nds32_emit_stack_push_multiple, nds32_emit_stack_pop_multiple,
+       nds32_emit_stack_v3push, nds32_emit_stack_v3pop,
+       nds32_emit_adjust_frame, nds32_expand_prologue, nds32_expand_epilogue,
+       nds32_expand_prologue_v3push, nds32_expand_epilogue_v3pop): Refine.
+       * config/nds32/nds32.h (NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM,
+       NDS32_LAST_CALLEE_SAVE_GPR_REGNUM, NDS32_V3PUSH_AVAILABLE_P): New.
+       * config/nds32/nds32.md (prologue, epilogue): Use macro
+       NDS32_V3PUSH_AVAILABLE_P to do checking.
+
 2018-03-11  Jakub Jelinek  <jakub@redhat.com>
 
        PR debug/58150
index 3536411..2d644b7 100644 (file)
@@ -144,6 +144,7 @@ nds32_compute_stack_frame (void)
 {
   int r;
   int block_size;
+  bool v3pushpop_p;
 
   /* Because nds32_compute_stack_frame() will be called from different place,
      everytime we enter this function, we have to assume this function
@@ -264,6 +265,8 @@ nds32_compute_stack_frame (void)
       return;
     }
 
+  v3pushpop_p = NDS32_V3PUSH_AVAILABLE_P;
+
   /* Adjustment for v3push instructions:
      If we are using v3push (push25/pop25) instructions,
      we need to make sure Rb is $r6 and Re is
@@ -271,9 +274,7 @@ nds32_compute_stack_frame (void)
      Some results above will be discarded and recomputed.
      Note that it is only available under V3/V3M ISA and we
      DO NOT setup following stuff for isr or variadic function.  */
-  if (TARGET_V3PUSH
-      && !nds32_isr_function_p (current_function_decl)
-      && (cfun->machine->va_args_size == 0))
+  if (v3pushpop_p)
     {
       /* Recompute:
           cfun->machine->fp_size
@@ -323,6 +324,39 @@ nds32_compute_stack_frame (void)
        }
     }
 
+  int sp_adjust = cfun->machine->local_size
+                 + cfun->machine->out_args_size
+                 + cfun->machine->callee_saved_area_gpr_padding_bytes;
+
+  if (!v3pushpop_p
+      && sp_adjust == 0
+      && !frame_pointer_needed)
+    {
+      block_size = cfun->machine->fp_size
+                  + cfun->machine->gp_size
+                  + cfun->machine->lp_size
+                  + (4 * (cfun->machine->callee_saved_last_gpr_regno
+                          - cfun->machine->callee_saved_first_gpr_regno
+                          + 1));
+
+      if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size))
+       {
+         /* $r14 is last callee save register.  */
+         if (cfun->machine->callee_saved_last_gpr_regno
+             < NDS32_LAST_CALLEE_SAVE_GPR_REGNUM)
+           {
+             cfun->machine->callee_saved_last_gpr_regno++;
+           }
+         else if (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM)
+           {
+             cfun->machine->callee_saved_first_gpr_regno
+               = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM;
+             cfun->machine->callee_saved_last_gpr_regno
+               = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM;
+           }
+       }
+    }
+
   /* We have correctly set callee_saved_first_gpr_regno
      and callee_saved_last_gpr_regno.
      Initially, the callee_saved_gpr_regs_size is supposed to be 0.
@@ -368,14 +402,15 @@ nds32_compute_stack_frame (void)
      "push registers to memory",
      "adjust stack pointer".  */
 static void
-nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
+nds32_emit_stack_push_multiple (unsigned Rb, unsigned Re,
+                               bool save_fp_p, bool save_gp_p, bool save_lp_p,
+                               bool vaarg_p)
 {
-  int regno;
+  unsigned regno;
   int extra_count;
   int num_use_regs;
   int par_index;
   int offset;
-  int save_fp, save_gp, save_lp;
 
   rtx reg;
   rtx mem;
@@ -403,24 +438,19 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
                (set (reg:SI SP_REGNUM)
                     (plus (reg:SI SP_REGNUM) (const_int -32)))]) */
 
-  /* Determine whether we need to save $fp, $gp, or $lp.  */
-  save_fp = INTVAL (En4) & 0x8;
-  save_gp = INTVAL (En4) & 0x4;
-  save_lp = INTVAL (En4) & 0x2;
-
   /* Calculate the number of registers that will be pushed.  */
   extra_count = 0;
-  if (save_fp)
+  if (save_fp_p)
     extra_count++;
-  if (save_gp)
+  if (save_gp_p)
     extra_count++;
-  if (save_lp)
+  if (save_lp_p)
     extra_count++;
   /* Note that Rb and Re may be SP_REGNUM.  DO NOT count it in.  */
-  if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
+  if (Rb == SP_REGNUM && Re == SP_REGNUM)
     num_use_regs = extra_count;
   else
-    num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count;
+    num_use_regs = Re - Rb + 1 + extra_count;
 
   /* In addition to used registers,
      we need one more space for (set sp sp-x) rtx.  */
@@ -432,7 +462,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
   offset = -(num_use_regs * 4);
 
   /* Create (set mem regX) from Rb, Rb+1 up to Re.  */
-  for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
+  for (regno = Rb; regno <= Re; regno++)
     {
       /* Rb and Re may be SP_REGNUM.
         We need to break this loop immediately.  */
@@ -451,7 +481,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
     }
 
   /* Create (set mem fp), (set mem gp), and (set mem lp) if necessary.  */
-  if (save_fp)
+  if (save_fp_p)
     {
       reg = gen_rtx_REG (SImode, FP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -463,7 +493,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
       offset = offset + 4;
       par_index++;
     }
-  if (save_gp)
+  if (save_gp_p)
     {
       reg = gen_rtx_REG (SImode, GP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -475,7 +505,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
       offset = offset + 4;
       par_index++;
     }
-  if (save_lp)
+  if (save_lp_p)
     {
       reg = gen_rtx_REG (SImode, LP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -521,14 +551,14 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
      "pop registers from memory",
      "adjust stack pointer".  */
 static void
-nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
+nds32_emit_stack_pop_multiple (unsigned Rb, unsigned Re,
+                              bool save_fp_p, bool save_gp_p, bool save_lp_p)
 {
-  int regno;
+  unsigned regno;
   int extra_count;
   int num_use_regs;
   int par_index;
   int offset;
-  int save_fp, save_gp, save_lp;
 
   rtx reg;
   rtx mem;
@@ -556,24 +586,19 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
                (set (reg:SI SP_REGNUM)
                     (plus (reg:SI SP_REGNUM) (const_int 32)))]) */
 
-  /* Determine whether we need to restore $fp, $gp, or $lp.  */
-  save_fp = INTVAL (En4) & 0x8;
-  save_gp = INTVAL (En4) & 0x4;
-  save_lp = INTVAL (En4) & 0x2;
-
   /* Calculate the number of registers that will be poped.  */
   extra_count = 0;
-  if (save_fp)
+  if (save_fp_p)
     extra_count++;
-  if (save_gp)
+  if (save_gp_p)
     extra_count++;
-  if (save_lp)
+  if (save_lp_p)
     extra_count++;
   /* Note that Rb and Re may be SP_REGNUM.  DO NOT count it in.  */
-  if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
+  if (Rb == SP_REGNUM && Re == SP_REGNUM)
     num_use_regs = extra_count;
   else
-    num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count;
+    num_use_regs = Re - Rb + 1 + extra_count;
 
   /* In addition to used registers,
      we need one more space for (set sp sp+x) rtx.  */
@@ -585,7 +610,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
   offset = 0;
 
   /* Create (set regX mem) from Rb, Rb+1 up to Re.  */
-  for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
+  for (regno = Rb; regno <= Re; regno++)
     {
       /* Rb and Re may be SP_REGNUM.
         We need to break this loop immediately.  */
@@ -606,7 +631,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
     }
 
   /* Create (set fp mem), (set gp mem), and (set lp mem) if necessary.  */
-  if (save_fp)
+  if (save_fp_p)
     {
       reg = gen_rtx_REG (SImode, FP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -620,7 +645,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
 
       dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
     }
-  if (save_gp)
+  if (save_gp_p)
     {
       reg = gen_rtx_REG (SImode, GP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -634,7 +659,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
 
       dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
     }
-  if (save_lp)
+  if (save_lp_p)
     {
       reg = gen_rtx_REG (SImode, LP_REGNUM);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -677,12 +702,11 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
      "push registers to memory",
      "adjust stack pointer".  */
 static void
-nds32_emit_stack_v3push (rtx Rb,
-                        rtx Re,
-                        rtx En4 ATTRIBUTE_UNUSED,
-                        rtx imm8u)
+nds32_emit_stack_v3push (unsigned Rb,
+                        unsigned Re,
+                        unsigned imm8u)
 {
-  int regno;
+  unsigned regno;
   int num_use_regs;
   int par_index;
   int offset;
@@ -717,7 +741,7 @@ nds32_emit_stack_v3push (rtx Rb,
      we need to count these three registers.
      Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
      So there is no need to worry about Rb=Re=SP_REGNUM case.  */
-  num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3;
+  num_use_regs = Re - Rb + 1 + 3;
 
   /* In addition to used registers,
      we need one more space for (set sp sp-x-imm8u) rtx.  */
@@ -731,7 +755,7 @@ nds32_emit_stack_v3push (rtx Rb,
   /* Create (set mem regX) from Rb, Rb+1 up to Re.
      Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
      So there is no need to worry about Rb=Re=SP_REGNUM case.  */
-  for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
+  for (regno = Rb; regno <= Re; regno++)
     {
       reg = gen_rtx_REG (SImode, regno);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -783,7 +807,7 @@ nds32_emit_stack_v3push (rtx Rb,
     = gen_rtx_SET (stack_pointer_rtx,
                   plus_constant (Pmode,
                                  stack_pointer_rtx,
-                                 offset - INTVAL (imm8u)));
+                                 offset - imm8u));
   XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
   RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
 
@@ -801,12 +825,11 @@ nds32_emit_stack_v3push (rtx Rb,
      "pop registers from memory",
      "adjust stack pointer".  */
 static void
-nds32_emit_stack_v3pop (rtx Rb,
-                       rtx Re,
-                       rtx En4 ATTRIBUTE_UNUSED,
-                       rtx imm8u)
+nds32_emit_stack_v3pop (unsigned Rb,
+                       unsigned Re,
+                       unsigned imm8u)
 {
-  int regno;
+  unsigned regno;
   int num_use_regs;
   int par_index;
   int offset;
@@ -842,7 +865,7 @@ nds32_emit_stack_v3pop (rtx Rb,
      we need to count these three registers.
      Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
      So there is no need to worry about Rb=Re=SP_REGNUM case.  */
-  num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3;
+  num_use_regs = Re - Rb + 1 + 3;
 
   /* In addition to used registers,
      we need one more space for (set sp sp+x+imm8u) rtx.  */
@@ -856,7 +879,7 @@ nds32_emit_stack_v3pop (rtx Rb,
   /* Create (set regX mem) from Rb, Rb+1 up to Re.
      Under v3pop, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
      So there is no need to worry about Rb=Re=SP_REGNUM case.  */
-  for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
+  for (regno = Rb; regno <= Re; regno++)
     {
       reg = gen_rtx_REG (SImode, regno);
       mem = gen_frame_mem (SImode, plus_constant (Pmode,
@@ -914,11 +937,24 @@ nds32_emit_stack_v3pop (rtx Rb,
     = gen_rtx_SET (stack_pointer_rtx,
                   plus_constant (Pmode,
                                  stack_pointer_rtx,
-                                 offset + INTVAL (imm8u)));
+                                 offset + imm8u));
   XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
 
-  /* Tell gcc we adjust SP in this insn.  */
-  dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf);
+  if (frame_pointer_needed)
+    {
+      /* (expr_list:REG_CFA_DEF_CFA (plus:SI (reg/f:SI $sp)
+                                            (const_int 0))
+        mean reset frame pointer to $sp and reset to offset 0.  */
+      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                        const0_rtx);
+      dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
+    }
+  else
+    {
+      /* Tell gcc we adjust SP in this insn.  */
+      dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA,
+                             copy_rtx (adjust_sp_rtx), dwarf);
+    }
 
   parallel_insn = emit_insn (parallel_insn);
 
@@ -940,18 +976,18 @@ nds32_emit_stack_v3pop (rtx Rb,
    the adjustment value is not able to be fit in the 'addi' instruction.
    One solution is to move value into a register
    and then use 'add' instruction.
-   In practice, we use TA_REGNUM ($r15) to accomplish this purpose.
-   Also, we need to return zero for sp adjustment so that
-   proglogue/epilogue knows there is no need to create 'addi' instruction.  */
-static int
-nds32_force_addi_stack_int (int full_value)
+   In practice, we use TA_REGNUM ($r15) to accomplish this purpose.  */
+static void
+nds32_emit_adjust_frame (rtx to_reg, rtx from_reg, int adjust_value)
 {
-  int adjust_value;
-
   rtx tmp_reg;
-  rtx sp_adjust_insn;
+  rtx frame_adjust_insn;
+  rtx adjust_value_rtx = GEN_INT (adjust_value);
 
-  if (!satisfies_constraint_Is15 (GEN_INT (full_value)))
+  if (adjust_value == 0)
+    return;
+
+  if (!satisfies_constraint_Is15 (adjust_value_rtx))
     {
       /* The value is not able to fit in single addi instruction.
         Create more instructions of moving value into a register
@@ -962,52 +998,43 @@ nds32_force_addi_stack_int (int full_value)
 
       /* Create one more instruction to move value
         into the temporary register.  */
-      emit_move_insn (tmp_reg, GEN_INT (full_value));
+      emit_move_insn (tmp_reg, adjust_value_rtx);
 
       /* Create new 'add' rtx.  */
-      sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                  stack_pointer_rtx,
-                                  tmp_reg);
+      frame_adjust_insn = gen_addsi3 (to_reg,
+                                     from_reg,
+                                     tmp_reg);
       /* Emit rtx into insn list and receive its transformed insn rtx.  */
-      sp_adjust_insn = emit_insn (sp_adjust_insn);
+      frame_adjust_insn = emit_insn (frame_adjust_insn);
 
-      /* At prologue, we need to tell GCC that this is frame related insn,
-         so that we can consider this instruction to output debug information.
-         If full_value is NEGATIVE, it means this function
-         is invoked by expand_prologue.  */
-      if (full_value < 0)
-       {
-         /* Because (tmp_reg <- full_value) may be split into two
-            rtl patterns, we can not set its RTX_FRAME_RELATED_P.
-            We need to construct another (sp <- sp + full_value)
-            and then insert it into sp_adjust_insn's reg note to
-            represent a frame related expression.
-            GCC knows how to refer it and output debug information.  */
-
-         rtx plus_rtx;
-         rtx set_rtx;
+      /* Because (tmp_reg <- full_value) may be split into two
+        rtl patterns, we can not set its RTX_FRAME_RELATED_P.
+        We need to construct another (sp <- sp + full_value)
+        and then insert it into sp_adjust_insn's reg note to
+        represent a frame related expression.
+        GCC knows how to refer it and output debug information.  */
 
-         plus_rtx = plus_constant (Pmode, stack_pointer_rtx, full_value);
-         set_rtx = gen_rtx_SET (stack_pointer_rtx, plus_rtx);
-         add_reg_note (sp_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx);
+      rtx plus_rtx;
+      rtx set_rtx;
 
-         RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
-       }
-
-      /* We have used alternative way to adjust stack pointer value.
-         Return zero so that prologue/epilogue
-         will not generate other instructions.  */
-      return 0;
+      plus_rtx = plus_constant (Pmode, from_reg, adjust_value);
+      set_rtx = gen_rtx_SET (to_reg, plus_rtx);
+      add_reg_note (frame_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx);
     }
   else
     {
-      /* The value is able to fit in addi instruction.
-         However, remember to make it to be positive value
-         because we want to return 'adjustment' result.  */
-      adjust_value = (full_value < 0) ? (-full_value) : (full_value);
-
-      return adjust_value;
+      /* Generate sp adjustment instruction if and only if sp_adjust != 0.  */
+      frame_adjust_insn = gen_addsi3 (to_reg,
+                                     from_reg,
+                                     adjust_value_rtx);
+      /* Emit rtx into instructions list and receive INSN rtx form.  */
+      frame_adjust_insn = emit_insn (frame_adjust_insn);
     }
+
+    /* The insn rtx 'sp_adjust_insn' will change frame layout.
+       We need to use RTX_FRAME_RELATED_P so that GCC is able to
+       generate CFI (Call Frame Information) stuff.  */
+    RTX_FRAME_RELATED_P (frame_adjust_insn) = 1;
 }
 
 /* Return true if MODE/TYPE need double word alignment.  */
@@ -2965,10 +2992,7 @@ nds32_expand_prologue (void)
 {
   int fp_adjust;
   int sp_adjust;
-  int en4_const;
-
-  rtx Rb, Re;
-  rtx fp_adjust_insn, sp_adjust_insn;
+  unsigned Rb, Re;
 
   /* Compute and setup stack frame size.
      The result will be in cfun->machine.  */
@@ -2978,10 +3002,10 @@ nds32_expand_prologue (void)
      registers that hold the unnamed argument value.  */
   if (cfun->machine->va_args_size != 0)
     {
-      Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno);
-      Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno);
-      /* No need to push $fp, $gp, or $lp, so use GEN_INT(0).  */
-      nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true);
+      Rb = cfun->machine->va_args_first_regno;
+      Re = cfun->machine->va_args_last_regno;
+      /* No need to push $fp, $gp, or $lp.  */
+      nds32_emit_stack_push_multiple (Rb, Re, false, false, false, true);
 
       /* We may also need to adjust stack pointer for padding bytes
          because varargs may cause $sp not 8-byte aligned.  */
@@ -2989,17 +3013,10 @@ nds32_expand_prologue (void)
        {
          /* Generate sp adjustment instruction.  */
          sp_adjust = cfun->machine->va_args_area_padding_bytes;
-         sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (-1 * sp_adjust));
-
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         sp_adjust_insn = emit_insn (sp_adjust_insn);
 
-         /* The insn rtx 'sp_adjust_insn' will change frame layout.
-            We need to use RTX_FRAME_RELATED_P so that GCC is able to
-            generate CFI (Call Frame Information) stuff.  */
-         RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+         nds32_emit_adjust_frame (stack_pointer_rtx,
+                                  stack_pointer_rtx,
+                                  -1 * sp_adjust);
        }
     }
 
@@ -3009,28 +3026,22 @@ nds32_expand_prologue (void)
     return;
 
   /* Get callee_first_regno and callee_last_regno.  */
-  Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
-  Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
-
-  /* nds32_emit_stack_push_multiple(first_regno, last_regno),
-     the pattern 'stack_push_multiple' is implemented in nds32.md.
-     For En4 field, we have to calculate its constant value.
-     Refer to Andes ISA for more information.  */
-  en4_const = 0;
-  if (cfun->machine->fp_size)
-    en4_const += 8;
-  if (cfun->machine->gp_size)
-    en4_const += 4;
-  if (cfun->machine->lp_size)
-    en4_const += 2;
+  Rb = cfun->machine->callee_saved_first_gpr_regno;
+  Re = cfun->machine->callee_saved_last_gpr_regno;
 
   /* If $fp, $gp, $lp, and all callee-save registers are NOT required
      to be saved, we don't have to create multiple push instruction.
      Otherwise, a multiple push instruction is needed.  */
-  if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
+  if (!(Rb == SP_REGNUM && Re == SP_REGNUM
+       && cfun->machine->fp_size == 0
+       && cfun->machine->gp_size == 0
+       && cfun->machine->lp_size == 0))
     {
       /* Create multiple push instruction rtx.  */
-      nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (en4_const), false);
+      nds32_emit_stack_push_multiple (
+       Rb, Re,
+       cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size,
+       false);
     }
 
   /* Check frame_pointer_needed to see
@@ -3047,14 +3058,10 @@ nds32_expand_prologue (void)
                  + cfun->machine->gp_size
                  + cfun->machine->lp_size
                  + cfun->machine->callee_saved_gpr_regs_size;
-      fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
-                                  stack_pointer_rtx,
-                                  GEN_INT (fp_adjust));
-      /* Emit rtx into instructions list and receive INSN rtx form.  */
-      fp_adjust_insn = emit_insn (fp_adjust_insn);
 
-      /* The insn rtx 'fp_adjust_insn' will change frame layout.  */
-      RTX_FRAME_RELATED_P (fp_adjust_insn) = 1;
+      nds32_emit_adjust_frame (hard_frame_pointer_rtx,
+                              stack_pointer_rtx,
+                              fp_adjust);
     }
 
   /* Adjust $sp = $sp - local_size - out_args_size
@@ -3065,21 +3072,9 @@ nds32_expand_prologue (void)
   /* sp_adjust value may be out of range of the addi instruction,
      create alternative add behavior with TA_REGNUM if necessary,
      using NEGATIVE value to tell that we are decreasing address.  */
-  sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust);
-  if (sp_adjust)
-    {
-      /* Generate sp adjustment instruction if and only if sp_adjust != 0.  */
-      sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                  stack_pointer_rtx,
-                                  GEN_INT (-1 * sp_adjust));
-      /* Emit rtx into instructions list and receive INSN rtx form.  */
-      sp_adjust_insn = emit_insn (sp_adjust_insn);
-
-      /* The insn rtx 'sp_adjust_insn' will change frame layout.
-         We need to use RTX_FRAME_RELATED_P so that GCC is able to
-         generate CFI (Call Frame Information) stuff.  */
-      RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
-    }
+  nds32_emit_adjust_frame (stack_pointer_rtx,
+                          stack_pointer_rtx,
+                          -1 * sp_adjust);
 
   /* Prevent the instruction scheduler from
      moving instructions across the boundary.  */
@@ -3091,10 +3086,7 @@ void
 nds32_expand_epilogue (bool sibcall_p)
 {
   int sp_adjust;
-  int en4_const;
-
-  rtx Rb, Re;
-  rtx sp_adjust_insn;
+  unsigned Rb, Re;
 
   /* Compute and setup stack frame size.
      The result will be in cfun->machine.  */
@@ -3119,16 +3111,10 @@ nds32_expand_epilogue (bool sibcall_p)
             We  need to consider padding bytes here.  */
          sp_adjust = cfun->machine->va_args_size
                      + cfun->machine->va_args_area_padding_bytes;
-         sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (sp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         sp_adjust_insn = emit_insn (sp_adjust_insn);
-
-         /* The insn rtx 'sp_adjust_insn' will change frame layout.
-            We need to use RTX_FRAME_RELATED_P so that GCC is able to
-            generate CFI (Call Frame Information) stuff.  */
-         RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+
+         nds32_emit_adjust_frame (stack_pointer_rtx,
+                                  stack_pointer_rtx,
+                                  sp_adjust);
        }
 
       /* Generate return instruction by using 'return_internal' pattern.
@@ -3150,71 +3136,47 @@ nds32_expand_epilogue (bool sibcall_p)
                  + cfun->machine->gp_size
                  + cfun->machine->lp_size
                  + cfun->machine->callee_saved_gpr_regs_size;
-      sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                  hard_frame_pointer_rtx,
-                                  GEN_INT (-1 * sp_adjust));
-      /* Emit rtx into instructions list and receive INSN rtx form.  */
-      sp_adjust_insn = emit_insn (sp_adjust_insn);
 
-      /* The insn rtx 'sp_adjust_insn' will change frame layout.  */
-      RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+      nds32_emit_adjust_frame (stack_pointer_rtx,
+                              hard_frame_pointer_rtx,
+                              -1 * sp_adjust);
     }
   else
     {
       /* If frame pointer is NOT needed,
         we cannot calculate the sp adjustment from frame pointer.
         Instead, we calculate the adjustment by local_size,
-        out_args_size, and callee_saved_area_padding_bytes.
+        out_args_size, and callee_saved_area_gpr_padding_bytes.
         Notice that such sp adjustment value may be out of range,
         so we have to deal with it as well.  */
 
       /* Adjust $sp = $sp + local_size + out_args_size
-                         + callee_saved_area_padding_bytes.  */
+                         + callee_saved_area_gpr_padding_bytes.  */
       sp_adjust = cfun->machine->local_size
                  + cfun->machine->out_args_size
                  + cfun->machine->callee_saved_area_gpr_padding_bytes;
-      /* sp_adjust value may be out of range of the addi instruction,
-        create alternative add behavior with TA_REGNUM if necessary,
-        using POSITIVE value to tell that we are increasing address.  */
-      sp_adjust = nds32_force_addi_stack_int (sp_adjust);
-      if (sp_adjust)
-       {
-         /* Generate sp adjustment instruction
-            if and only if sp_adjust != 0.  */
-         sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (sp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         sp_adjust_insn = emit_insn (sp_adjust_insn);
-
-         /* The insn rtx 'sp_adjust_insn' will change frame layout.  */
-         RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
-       }
+
+      nds32_emit_adjust_frame (stack_pointer_rtx,
+                              stack_pointer_rtx,
+                              sp_adjust);
     }
 
   /* Get callee_first_regno and callee_last_regno.  */
-  Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
-  Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
-
-  /* nds32_emit_stack_pop_multiple(first_regno, last_regno),
-     the pattern 'stack_pop_multiple' is implementad in nds32.md.
-     For En4 field, we have to calculate its constant value.
-     Refer to Andes ISA for more information.  */
-  en4_const = 0;
-  if (cfun->machine->fp_size)
-    en4_const += 8;
-  if (cfun->machine->gp_size)
-    en4_const += 4;
-  if (cfun->machine->lp_size)
-    en4_const += 2;
+  Rb = cfun->machine->callee_saved_first_gpr_regno;
+  Re = cfun->machine->callee_saved_last_gpr_regno;
 
   /* If $fp, $gp, $lp, and all callee-save registers are NOT required
      to be saved, we don't have to create multiple pop instruction.
      Otherwise, a multiple pop instruction is needed.  */
-  if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
+  if (!(Rb == SP_REGNUM && Re == SP_REGNUM
+       && cfun->machine->fp_size == 0
+       && cfun->machine->gp_size == 0
+       && cfun->machine->lp_size == 0))
     {
       /* Create multiple pop instruction rtx.  */
-      nds32_emit_stack_pop_multiple (Rb, Re, GEN_INT (en4_const));
+      nds32_emit_stack_pop_multiple (
+       Rb, Re,
+       cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size);
     }
 
   /* If this is a variadic function, we do not have to restore argument
@@ -3226,16 +3188,10 @@ nds32_expand_epilogue (bool sibcall_p)
         We need to consider padding bytes here.  */
       sp_adjust = cfun->machine->va_args_size
                  + cfun->machine->va_args_area_padding_bytes;
-      sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                  stack_pointer_rtx,
-                                  GEN_INT (sp_adjust));
-      /* Emit rtx into instructions list and receive INSN rtx form.  */
-      sp_adjust_insn = emit_insn (sp_adjust_insn);
 
-      /* The insn rtx 'sp_adjust_insn' will change frame layout.
-        We need to use RTX_FRAME_RELATED_P so that GCC is able to
-        generate CFI (Call Frame Information) stuff.  */
-      RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
+      nds32_emit_adjust_frame (stack_pointer_rtx,
+                              stack_pointer_rtx,
+                              sp_adjust);
     }
 
   /* Generate return instruction.  */
@@ -3249,22 +3205,23 @@ nds32_expand_prologue_v3push (void)
 {
   int fp_adjust;
   int sp_adjust;
-
-  rtx Rb, Re;
-  rtx fp_adjust_insn, sp_adjust_insn;
+  unsigned Rb, Re;
 
   /* Compute and setup stack frame size.
      The result will be in cfun->machine.  */
   nds32_compute_stack_frame ();
 
+  if (cfun->machine->callee_saved_gpr_regs_size > 0)
+    df_set_regs_ever_live (FP_REGNUM, 1);
+
   /* If the function is 'naked',
      we do not have to generate prologue code fragment.  */
   if (cfun->machine->naked_p)
     return;
 
   /* Get callee_first_regno and callee_last_regno.  */
-  Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
-  Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
+  Rb = cfun->machine->callee_saved_first_gpr_regno;
+  Re = cfun->machine->callee_saved_last_gpr_regno;
 
   /* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available,
      where imm8u has to be 8-byte alignment.  */
@@ -3278,11 +3235,8 @@ nds32_expand_prologue_v3push (void)
       /* We can use 'push25 Re,imm8u'.  */
 
       /* nds32_emit_stack_v3push(last_regno, sp_adjust),
-        the pattern 'stack_v3push' is implemented in nds32.md.
-         The (const_int 14) means v3push always push { $fp $gp $lp }.  */
-      nds32_emit_stack_v3push (Rb, Re,
-                              GEN_INT (14), GEN_INT (sp_adjust));
-
+        the pattern 'stack_v3push' is implemented in nds32.md.  */
+      nds32_emit_stack_v3push (Rb, Re, sp_adjust);
       /* Check frame_pointer_needed to see
         if we shall emit fp adjustment instruction.  */
       if (frame_pointer_needed)
@@ -3302,11 +3256,10 @@ nds32_expand_prologue_v3push (void)
                      + cfun->machine->lp_size
                      + cfun->machine->callee_saved_gpr_regs_size
                      + sp_adjust;
-         fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (fp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         fp_adjust_insn = emit_insn (fp_adjust_insn);
+
+         nds32_emit_adjust_frame (hard_frame_pointer_rtx,
+                                  stack_pointer_rtx,
+                                  fp_adjust);
        }
     }
   else
@@ -3315,10 +3268,8 @@ nds32_expand_prologue_v3push (void)
         expand one more instruction to adjust $sp later.  */
 
       /* nds32_emit_stack_v3push(last_regno, sp_adjust),
-        the pattern 'stack_v3push' is implemented in nds32.md.
-        The (const_int 14) means v3push always push { $fp $gp $lp }.  */
-      nds32_emit_stack_v3push (Rb, Re,
-                              GEN_INT (14), GEN_INT (0));
+        the pattern 'stack_v3push' is implemented in nds32.md.  */
+      nds32_emit_stack_v3push (Rb, Re, 0);
 
       /* Check frame_pointer_needed to see
         if we shall emit fp adjustment instruction.  */
@@ -3336,34 +3287,18 @@ nds32_expand_prologue_v3push (void)
                      + cfun->machine->gp_size
                      + cfun->machine->lp_size
                      + cfun->machine->callee_saved_gpr_regs_size;
-         fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (fp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         fp_adjust_insn = emit_insn (fp_adjust_insn);
+
+         nds32_emit_adjust_frame (hard_frame_pointer_rtx,
+                                  stack_pointer_rtx,
+                                  fp_adjust);
        }
 
       /* Because we use 'push25 Re,0',
         we need to expand one more instruction to adjust $sp.
-        However, sp_adjust value may be out of range of the addi instruction,
-        create alternative add behavior with TA_REGNUM if necessary,
         using NEGATIVE value to tell that we are decreasing address.  */
-      sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust);
-      if (sp_adjust)
-       {
-         /* Generate sp adjustment instruction
-            if and only if sp_adjust != 0.  */
-         sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                      stack_pointer_rtx,
-                                      GEN_INT (-1 * sp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         sp_adjust_insn = emit_insn (sp_adjust_insn);
-
-         /* The insn rtx 'sp_adjust_insn' will change frame layout.
-            We need to use RTX_FRAME_RELATED_P so that GCC is able to
-            generate CFI (Call Frame Information) stuff.  */
-         RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
-       }
+      nds32_emit_adjust_frame (stack_pointer_rtx,
+                              stack_pointer_rtx,
+                              -1 * sp_adjust);
     }
 
   /* Prevent the instruction scheduler from
@@ -3376,9 +3311,7 @@ void
 nds32_expand_epilogue_v3pop (bool sibcall_p)
 {
   int sp_adjust;
-
-  rtx Rb, Re;
-  rtx sp_adjust_insn;
+  unsigned Rb, Re;
 
   /* Compute and setup stack frame size.
      The result will be in cfun->machine.  */
@@ -3400,8 +3333,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
     }
 
   /* Get callee_first_regno and callee_last_regno.  */
-  Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
-  Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
+  Rb = cfun->machine->callee_saved_first_gpr_regno;
+  Re = cfun->machine->callee_saved_last_gpr_regno;
 
   /* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available,
      where imm8u has to be 8-byte alignment.  */
@@ -3423,10 +3356,8 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
       /* We can use 'pop25 Re,imm8u'.  */
 
       /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
-        the pattern 'stack_v3pop' is implementad in nds32.md.
-         The (const_int 14) means v3pop always pop { $fp $gp $lp }.  */
-      nds32_emit_stack_v3pop (Rb, Re,
-                             GEN_INT (14), GEN_INT (sp_adjust));
+        the pattern 'stack_v3pop' is implementad in nds32.md.  */
+      nds32_emit_stack_v3pop (Rb, Re, sp_adjust);
     }
   else
     {
@@ -3447,11 +3378,10 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
                      + cfun->machine->gp_size
                      + cfun->machine->lp_size
                      + cfun->machine->callee_saved_gpr_regs_size;
-         sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                      hard_frame_pointer_rtx,
-                                      GEN_INT (-1 * sp_adjust));
-         /* Emit rtx into instructions list and receive INSN rtx form.  */
-         sp_adjust_insn = emit_insn (sp_adjust_insn);
+
+         nds32_emit_adjust_frame (stack_pointer_rtx,
+                                  hard_frame_pointer_rtx,
+                                  -1 * sp_adjust);
        }
       else
        {
@@ -3463,31 +3393,22 @@ nds32_expand_epilogue_v3pop (bool sibcall_p)
             so we have to deal with it as well.  */
 
          /* Adjust $sp = $sp + local_size + out_args_size
-                             + callee_saved_area_gpr_padding_bytes.  */
+                              + callee_saved_area_gpr_padding_bytes.  */
          sp_adjust = cfun->machine->local_size
                      + cfun->machine->out_args_size
                      + cfun->machine->callee_saved_area_gpr_padding_bytes;
-         /* sp_adjust value may be out of range of the addi instruction,
-            create alternative add behavior with TA_REGNUM if necessary,
-            using POSITIVE value to tell that we are increasing address.  */
-         sp_adjust = nds32_force_addi_stack_int (sp_adjust);
-         if (sp_adjust)
-           {
-             /* Generate sp adjustment instruction
-                if and only if sp_adjust != 0.  */
-             sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
-                                          stack_pointer_rtx,
-                                          GEN_INT (sp_adjust));
-             /* Emit rtx into instructions list and receive INSN rtx form.  */
-             sp_adjust_insn = emit_insn (sp_adjust_insn);
-           }
+          /* sp_adjust value may be out of range of the addi instruction,
+             create alternative add behavior with TA_REGNUM if necessary,
+             using POSITIVE value to tell that we are increasing
+             address.  */
+         nds32_emit_adjust_frame (stack_pointer_rtx,
+                                  stack_pointer_rtx,
+                                  sp_adjust);
        }
 
       /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
         the pattern 'stack_v3pop' is implementad in nds32.md.  */
-      /* The (const_int 14) means v3pop always pop { $fp $gp $lp }.  */
-      nds32_emit_stack_v3pop (Rb, Re,
-                             GEN_INT (14), GEN_INT (0));
+      nds32_emit_stack_v3pop (Rb, Re, 0);
     }
 
   /* Generate return instruction.  */
index 6846aef..dc40735 100644 (file)
@@ -130,6 +130,10 @@ enum nds32_16bit_address_type
 /* Define the last integer register number.  */
 #define NDS32_LAST_GPR_REGNUM 31
 
+#define NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM 6
+#define NDS32_LAST_CALLEE_SAVE_GPR_REGNUM \
+  (TARGET_REDUCED_REGS ? 10 : 14)
+
 /* Define double word alignment bits.  */
 #define NDS32_DOUBLE_WORD_ALIGNMENT 64
 
@@ -196,6 +200,19 @@ enum nds32_16bit_address_type
 #define NDS32_REQUIRED_CALLEE_SAVED_P(regno)                  \
   ((!call_used_regs[regno]) && (df_regs_ever_live_p (regno)))
 
+/* This macro is to check if the push25/pop25 are available to be used
+   for code generation.  Because pop25 also performs return behavior,
+   the instructions may not be available for some cases.
+   If we want to use push25/pop25, all the following conditions must
+   be satisfied:
+     1. TARGET_V3PUSH is set.
+     2. Current function is not an ISR function.
+     3. Current function is not a variadic function.*/
+#define NDS32_V3PUSH_AVAILABLE_P  \
+  (TARGET_V3PUSH \
+   && !nds32_isr_function_p (current_function_decl) \
+   && (cfun->machine->va_args_size == 0))
+
 /* ------------------------------------------------------------------------ */
 
 /* A C structure for machine-specific, per-function data.
index 71736f6..58a13c1 100644 (file)
@@ -2093,11 +2093,8 @@ create_template:
   ""
 {
   /* Note that only under V3/V3M ISA, we could use v3push prologue.
-     In addition, we do not want to use v3push for isr function
-     and variadic function.  */
-  if (TARGET_V3PUSH
-      && !nds32_isr_function_p (current_function_decl)
-      && (cfun->machine->va_args_size == 0))
+     In addition, we need to check if v3push is indeed available.  */
+  if (NDS32_V3PUSH_AVAILABLE_P)
     nds32_expand_prologue_v3push ();
   else
     nds32_expand_prologue ();
@@ -2108,11 +2105,8 @@ create_template:
   ""
 {
   /* Note that only under V3/V3M ISA, we could use v3pop epilogue.
-     In addition, we do not want to use v3pop for isr function
-     and variadic function.  */
-  if (TARGET_V3PUSH
-      && !nds32_isr_function_p (current_function_decl)
-      && (cfun->machine->va_args_size == 0))
+     In addition, we need to check if v3push is indeed available.  */
+  if (NDS32_V3PUSH_AVAILABLE_P)
     nds32_expand_epilogue_v3pop (false);
   else
     nds32_expand_epilogue (false);
@@ -2125,10 +2119,7 @@ create_template:
   /* Pass true to indicate that this is sibcall epilogue and
      exit from a function without the final branch back to the
      calling function.  */
-  if (TARGET_V3PUSH && !nds32_isr_function_p (current_function_decl))
-    nds32_expand_epilogue_v3pop (true);
-  else
-    nds32_expand_epilogue (true);
+  nds32_expand_epilogue (true);
 
   DONE;
 })