I don't know if there are any CFI experts out there but I am working on
dynamic stack alignment for MIPS.  I think I have it working in the 'normal'
case but when I try to do stack unwinding through a routine with an aligned
stack, then I have problems.  I was wondering if someone can help me understand
what CFI directives to generate to allow stack unwinding.  Using
gcc.dg/cleanup-8.c as an example (because it fails with my stack alignment
code), if I generate code with no dynamic stack alignment (but forcing the
use of the frame pointer), the routine fn2 looks like this on MIPS:

fn2:
        .frame  $fp,32,$31              # vars= 0, regs= 2/0, args= 16, gp= 8
        .mask   0xc0000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        lui     $2,%hi(null)
        addiu   $sp,$sp,-32
        .cfi_def_cfa_offset 32
        lw      $2,%lo(null)($2)
        sw      $fp,24($sp)
        .cfi_offset 30, -8
        move    $fp,$sp
        .cfi_def_cfa_register 30
        sw      $31,28($sp)
        .cfi_offset 31, -4
        jal     abort
        sb      $0,0($2)

There are .cfi directives when incrementing the stack pointer, saving the
frame pointer, and copying the stack pointer to the frame pointer.

When I generate code to dynamically align the stack my code looks like
this:

fn2:
        .frame  $fp,32,$31              # vars= 0, regs= 2/0, args= 16, gp= 8
        .mask   0xc0000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        lui     $2,%hi(null)
        li      $3,-16                  # 0xfffffffffffffff0
        lw      $2,%lo(null)($2)
        and     $sp,$sp,$3
        addiu   $sp,$sp,-32
        .cfi_def_cfa_offset 32
        sw      $fp,24($sp)
        .cfi_offset 30, -8
        move    $fp,$sp
        .cfi_def_cfa_register 30
        sw      $31,28($sp)
        .cfi_offset 31, -4
        jal     abort
        sb      $0,0($2)

The 'and' instruction is where the stack gets aligned and if I remove that
one instruction, everything works.  I think I need to put out some new CFI
psuedo-ops to handle this but I am not sure what they should be.  I am just
not very familiar with the CFI directives.

I looked at ix86_emit_save_reg_using_mov where there is some special
code for handling the drap register and for saving registers on a 
realigned stack but I don't really understand what they are trying 
to do.

Any help?

Steve Ellcey
sell...@imgtec.com

P.S. For completeness sake I have attached my current dynamic
     alignment changes in case anyone wants to see them.

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 4f9a31d..386c2ce 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -5737,6 +5737,29 @@ expand_stack_alignment (void)
   gcc_assert (targetm.calls.get_drap_rtx != NULL);
   drap_rtx = targetm.calls.get_drap_rtx ();
 
+  /* I am not doing this in get_drap_rtx because we are also calling
+     that from expand_function_end in order to get/set the drap_reg
+     and vdrap_reg variables and doing these instructions at that
+     point is not working.   */
+
+  if (drap_rtx != NULL_RTX)
+    {
+      rtx_insn *insn, *seq;
+
+      start_sequence ();
+      emit_move_insn (crtl->vdrap_reg, crtl->drap_reg);
+      seq = get_insns ();
+      insn = get_last_insn ();
+      end_sequence ();
+      emit_insn_at_entry (seq);
+      if (!optimize)
+        {
+          add_reg_note (insn, REG_CFA_SET_VDRAP, crtl->vdrap_reg);
+          RTX_FRAME_RELATED_P (insn) = 1;
+        }
+    }
+
+
   /* stack_realign_drap and drap_rtx must match.  */
   gcc_assert ((stack_realign_drap != 0) == (drap_rtx != NULL));
 
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index ce21a0f..b6ab30a 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -746,6 +746,8 @@ static const struct attribute_spec mips_attribute_table[] = {
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
   { "keep_interrupts_masked",	0, 0, false, true,  true, NULL, false },
   { "use_debug_exception_return", 0, 0, false, true,  true, NULL, false },
+  { "align_stack", 0, 0, true, false, false, NULL, false },
+  { "no_align_stack", 0, 0, true, false, false, NULL, false },
   { NULL,	   0, 0, false, false, false, NULL, false }
 };
 
@@ -1528,6 +1530,61 @@ mips_merge_decl_attributes (tree olddecl, tree newdecl)
 			   DECL_ATTRIBUTES (newdecl));
 }
 
+static bool
+mips_cfun_has_msa_p (void)
+{
+  /* For now, for testing, assume all functions use MSA
+     (and thus need alignment).  */
+#if 0
+  if (!cfun || !TARGET_MSA)
+    return FALSE;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (MSA_SUPPORTED_MODE_P (GET_MODE (insn)))
+	return TRUE;
+    }
+
+  return FALSE;
+#else
+  return TRUE;
+#endif
+}
+
+bool
+mips_align_stack_p (void)
+{
+  bool want_alignment = TARGET_ALIGN_STACK && mips_cfun_has_msa_p ();
+
+  if (current_function_decl)
+    {
+      tree attr = DECL_ATTRIBUTES (current_function_decl);
+      if (lookup_attribute ("no_align_stack", attr))
+	want_alignment = FALSE;
+      if (lookup_attribute ("align_stack", attr))
+	want_alignment = TRUE;
+
+      if (want_alignment
+	  && mips_get_compress_mode (current_function_decl) & MASK_MIPS16)
+	/* Should have warnings here ??? */
+	want_alignment = FALSE;
+    }
+
+  if (want_alignment && cfun
+      && (cfun->calls_setjmp || cfun->has_nonlocal_label))
+    /* Should have warnings here ??? */
+    want_alignment = FALSE;
+
+#if 1
+  if (want_alignment && (flag_exceptions || flag_unwind_tables))
+    want_alignment = FALSE;
+#endif
+
+  return want_alignment;
+}
+
+
+
 /* Implement TARGET_CAN_INLINE_P.  */
 
 static bool
@@ -10455,6 +10512,14 @@ mips_frame_pointer_required (void)
   if (cfun->calls_alloca)
     return true;
 
+  /* If we are going to dynamically relalign the stack, we need to use
+     a frame pointer because we cannot save/restore the stack pointer
+     with a simple addiu $sp,$sp,-N at the start and then +N at the end
+     of a function.  We need to save and restore it using the frame
+     pointer.  */
+  if (mips_align_stack_p ())
+    return true;
+
   /* In MIPS16 mode, we need a frame pointer for a large frame; otherwise,
      reload may be unable to compute the address of a local variable,
      since there is no way to add a large constant to the stack pointer
@@ -10535,6 +10600,8 @@ mips_extra_live_on_entry (bitmap regs)
       /* See the comment above load_call<mode> for details.  */
       bitmap_set_bit (regs, GOT_VERSION_REGNUM);
     }
+  if (mips_align_stack_p ())
+    bitmap_set_bit (regs, MIPS_PROLOGUE_TEMP2_REGNUM);
 }
 
 /* Implement RETURN_ADDR_RTX.  We do not support moving back to a
@@ -11382,6 +11449,48 @@ mips_expand_prologue (void)
 	mips_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
     }
 
+  /* Copy the stack pointer to drap register here, before we increment it.
+     We need drap_reg to be the 'unincremented' stack due to
+     instantiate_new_reg (in function.c) where the offset for accessing
+     arguments is reset when using a drap reg vs the normal argument pointer
+     (stack or frame).
+
+     Align the stack pointer before copying it to the frame pointer so that
+     $fp is also aligned.  local variables and spill slots are accessed
+     using $fp, not $sp when using dynamic stack alignment.
+
+     Do the alignment before saving registers so that expand_epilogue can
+     use the aligned $fp/$sp to restore registers.  */
+
+
+  if (mips_align_stack_p ())
+    {
+      rtx cfi_note;
+      rtx_insn *insn;
+      rtx (*and_insn) (rtx, rtx, rtx);
+      rtx drap_reg_rtx = MIPS_PROLOGUE_TEMP2 (Pmode);
+      insn = mips_emit_move (drap_reg_rtx, stack_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      mips_frame_barrier ();
+
+      gcc_assert (frame_pointer_needed);
+      gcc_assert (frame->hard_frame_pointer_offset == 0);
+      /* Cannot do 'and' instruction with a constant because the constant
+         would be too big.  Need to put it in a register.  */
+      and_insn = (Pmode == SImode) ? gen_andsi3 : gen_anddi3;
+      mips_emit_move (MIPS_PROLOGUE_TEMP (Pmode), GEN_INT (-16));
+      insn = emit_insn (and_insn (stack_pointer_rtx,
+				  stack_pointer_rtx,
+				  MIPS_PROLOGUE_TEMP (Pmode)));
+#if 1
+      cfi_note = alloc_reg_note (REG_CFA_DEF_CFA, stack_pointer_rtx, NULL_RTX);
+      REG_NOTES (insn) = cfi_note;
+#endif
+      RTX_FRAME_RELATED_P (insn) = 1;
+      mips_frame_barrier ();
+    }
+
   /* Save the registers.  Allocate up to MIPS_MAX_FIRST_STACK_STEP
      bytes beforehand; this is enough to cover the register save area
      without going out of range.  */
@@ -11877,6 +11986,11 @@ mips_expand_epilogue (bool sibcall_p)
 	  emit_insn (gen_cop0_move (gen_rtx_REG (SImode, COP0_STATUS_REG_NUM),
 				    gen_rtx_REG (SImode, K0_REG_NUM)));
 	}
+      else if (mips_align_stack_p ())
+	{
+	  emit_move_insn (stack_pointer_rtx, crtl->drap_reg);
+	  mips_epilogue_set_cfa (stack_pointer_rtx, 0);
+	}
       else if (TARGET_MICROMIPS
 	       && !crtl->calls_eh_return
 	       && !sibcall_p
@@ -17728,6 +17842,10 @@ mips_option_override (void)
   if (!TARGET_USE_GOT || !TARGET_EXPLICIT_RELOCS)
     target_flags &= ~MASK_RELAX_PIC_CALLS;
 
+  /* Turn off flag_optimize_sibling_calls if aligning stack.  */
+  if (mips_align_stack_p ())
+    flag_optimize_sibling_calls = 0;
+
   /* Save base state of options.  */
   mips_base_target_flags = target_flags;
   mips_base_schedule_insns = flag_schedule_insns;
@@ -17937,6 +18055,9 @@ mips_epilogue_uses (unsigned int regno)
       && mips_interrupt_extra_call_saved_reg_p (regno))
     return true;
 
+  if (mips_align_stack_p () && (regno == REGNO (crtl->drap_reg)))
+    return true; 
+
   return false;
 }
 
@@ -19384,6 +19505,53 @@ mips_ira_change_pseudo_allocno_class (int regno, reg_class_t allocno_class)
     return GR_REGS;
   return allocno_class;
 }
+
+/* Implement TARGET_GET_DRAP_RTX.  */
+static rtx
+mips_get_drap_rtx (void)
+{
+  rtx_insn *seq, *insn;
+
+  if (mips_align_stack_p ())
+    {
+      if (crtl->vdrap_reg == NULL_RTX)
+	{
+	  rtx_insn *seq, *insn;
+
+	  crtl->need_drap = true;
+	  crtl->stack_realign_needed = true;
+	  crtl->drap_reg = MIPS_PROLOGUE_TEMP2 (Pmode);
+	  crtl->vdrap_reg = gen_reg_rtx (Pmode);
+	}
+      return crtl->vdrap_reg;
+    }
+  else
+    return NULL_RTX;
+}
+
+/* Add code to copy vdrap to drap at end of a function.  */
+static void
+mips_add_exit_insns (void)
+{
+  /* Call mips_get_drap_rtx to make sure drap and vdrap regs are set.  */
+  mips_get_drap_rtx ();
+  if (crtl->drap_reg != NULL_RTX)
+    emit_move_insn (crtl->drap_reg, crtl->vdrap_reg);
+}
+
+/* Add code to copy vdrap to drap at end of a function.  */
+/* Update preferred stack boundary.  */
+
+static void
+mips_update_stack_boundary (void)
+{
+  if (mips_align_stack_p ())
+    {
+      crtl->need_drap = true;
+      crtl->preferred_stack_boundary = 128;
+      crtl->stack_realign_needed = true;
+    }
+}
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
@@ -19643,6 +19811,13 @@ mips_ira_change_pseudo_allocno_class (int regno, reg_class_t allocno_class)
 #undef TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS
 #define TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS mips_ira_change_pseudo_allocno_class
 
+#undef TARGET_GET_DRAP_RTX
+#define TARGET_GET_DRAP_RTX mips_get_drap_rtx
+#undef TARGET_ADD_EXIT_INSNS
+#define TARGET_ADD_EXIT_INSNS mips_add_exit_insns
+#undef TARGET_UPDATE_STACK_BOUNDARY
+#define TARGET_UPDATE_STACK_BOUNDARY mips_update_stack_boundary
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-mips.h"
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 7a6f917..3ba5cfb 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -2321,6 +2321,10 @@ enum reg_class
 #define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1
 
 #define STACK_BOUNDARY (TARGET_NEWABI ? 128 : 64)
+
+#define MAX_STACK_ALIGNMENT 128
+#define PREFERRED_STACK_BOUNDARY (mips_align_stack_p () ? 128 : STACK_BOUNDARY)
+#define INCOMING_STACK_BOUNDARY STACK_BOUNDARY
 
 /* Symbolic macros for the registers used to return integer and floating
    point values.  */
@@ -3109,6 +3113,7 @@ extern const struct mips_cpu_info *mips_tune_info;
 extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 extern GTY(()) struct target_globals *micromips_globals;
+extern bool mips_align_stack_p (void);
 #endif
 
 /* Enable querying of DFA units.  */
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index 348c6e0..8f15e2b 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -372,6 +372,10 @@ msplit-addresses
 Target Report Mask(SPLIT_ADDRESSES)
 Optimize lui/addiu address loads
 
+malign-stack
+Target Report Var(TARGET_ALIGN_STACK)
+Realign stack in prologue
+
 msym32
 Target Report Var(TARGET_SYM32)
 Assume all symbols have 32-bit values
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index a16cd92..55cbbc6 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11483,6 +11483,10 @@ argument list due to stack realignment.  Return @code{NULL} if no DRAP
 is needed.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_ADD_EXIT_INSNS (void)
+This hook will insert instructions at the exit point of a function.
+@end deftypefn
+
 @deftypefn {Target Hook} bool TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS (void)
 When optimization is disabled, this hook indicates whether or not
 arguments should be allocated to stack slots.  Normally, GCC allocates
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 93fb41c..f2e0576 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8181,6 +8181,8 @@ and the associated definitions of those functions.
 
 @hook TARGET_GET_DRAP_RTX
 
+@hook TARGET_ADD_EXIT_INSNS
+
 @hook TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
 
 @hook TARGET_CONST_ANCHOR
diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index b567b23..51f0818 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -1772,6 +1772,7 @@ dwarf2out_frame_debug_expr (rtx expr)
 			  == dwf_regno (XEXP (src, 0)));
               fde->stack_realign = 1;
               fde->stack_realignment = INTVAL (XEXP (src, 1));
+	      fde->stack_realignment = -16;
               cur_trace->cfa_store.offset = 0;
 
 	      if (cur_cfa->reg != dw_stack_pointer_regnum
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index f52c335..0d31393 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -120,6 +120,7 @@ struct GTY(()) rtl_data {
 
   /* Dynamic Realign Argument Pointer used for realigning stack.  */
   rtx drap_reg;
+  rtx vdrap_reg;
 
   /* Offset to end of allocated area of stack frame.
      If stack grows down, this is the address of the last stack slot allocated.
diff --git a/gcc/function.c b/gcc/function.c
index 8ee79d3..fed743d 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5460,6 +5460,10 @@ expand_function_end (void)
       emit_stack_restore (SAVE_FUNCTION, tem);
     }
 
+
+  if (targetm.calls.add_exit_insns)
+    targetm.calls.add_exit_insns ();
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
diff --git a/gcc/target.def b/gcc/target.def
index a2f3554..ec54921 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4525,6 +4525,11 @@ argument list due to stack realignment.  Return @code{NULL} if no DRAP\n\
 is needed.",
  rtx, (void), NULL)
 
+DEFHOOK
+(add_exit_insns,
+ "This hook will insert instructions at the exit point of a function.",
+ void, (void), NULL)
+
 /* Return true if all function parameters should be spilled to the
    stack.  */
 DEFHOOK
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index ebd0cfa..d11981a 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -1100,7 +1100,9 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
 	       && hard_frame_pointer_adjustment != -1
 	       && cfa_base_rtx)
 	return compute_cfa_pointer (hard_frame_pointer_adjustment);
-      gcc_checking_assert (loc != virtual_incoming_args_rtx);
+      /* On MIPS we don't need to adjust the incoming args reg.  */
+      /* gcc_checking_assert (loc != virtual_incoming_args_rtx); */
+      /* Gives abort on gcc.target/mips/fpr-moves-7.c in 64 bit mode.  */
       return loc;
     case MEM:
       mem = loc;

Reply via email to