OSDN Git Service

PR 10062
authordanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Mar 2003 04:41:48 +0000 (04:41 +0000)
committerdanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 19 Mar 2003 04:41:48 +0000 (04:41 +0000)
* config/pa/pa-hpux.h (TARGET_HPUX_UNWIND_LIBRARY): Redefine.
* pa-protos.h (output_lbranch): New prototype.
* pa.c (compute_frame_size): Change size of the frame marker on the
64-bit ports to 48 bytes.
(pa_output_function_prologue): Document why SAVE_SP is set.
(hppa_expand_prologue): Save previous stack pointer into frame marker
on targets which use the hpux unwind library.
(output_cbranch): Use output_lbranch.
(output_lbranch): New function to output long unconditional branches.
* pa.h (TARGET_HPUX_UNWIND_LIBRARY): Define.
(STACK_POINTER_OFFSET): Update offset for 48-byte frame marker on
64-bit ports.
* pa.md (jump): Use output_lbranch.
(allocate_stack): New expander for dynamic stack allocation.

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

gcc/ChangeLog
gcc/config/pa/pa-hpux.h
gcc/config/pa/pa-protos.h
gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/config/pa/pa.md

index 4c8d0b4..c6d7f90 100644 (file)
@@ -1,3 +1,21 @@
+2003-03-18  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
+
+       PR 10062
+       * config/pa/pa-hpux.h (TARGET_HPUX_UNWIND_LIBRARY): Redefine.
+       * pa-protos.h (output_lbranch): New prototype.
+       * pa.c (compute_frame_size): Change size of the frame marker on the
+       64-bit ports to 48 bytes.
+       (pa_output_function_prologue): Document why SAVE_SP is set.
+       (hppa_expand_prologue): Save previous stack pointer into frame marker
+       on targets which use the hpux unwind library.
+       (output_cbranch): Use output_lbranch.
+       (output_lbranch): New function to output long unconditional branches.
+       * pa.h (TARGET_HPUX_UNWIND_LIBRARY): Define.
+       (STACK_POINTER_OFFSET): Update offset for 48-byte frame marker on
+       64-bit ports.
+       * pa.md (jump): Use output_lbranch.
+       (allocate_stack): New expander for dynamic stack allocation.
+
 2003-03-19  Alan Modra  <amodra@bigpond.net.au>
 
        * config/rs6000/rs6000.c (rs6000_stack_info): Only require a frame
index a4ed77f..d6e1516 100644 (file)
@@ -100,3 +100,8 @@ Boston, MA 02111-1307, USA.  */
 /* hpux11 and earlier don't have fputc_unlocked, so we must inhibit the
    transformation of fputs_unlocked and fprintf_unlocked to fputc_unlocked.  */
 #define DONT_HAVE_FPUTC_UNLOCKED
+
+/* We want the entry value of SP saved in the frame marker for
+   compatibility with the HP-UX unwind library.  */
+#undef TARGET_HPUX_UNWIND_LIBRARY
+#define TARGET_HPUX_UNWIND_LIBRARY 1
index 248e1a7..16c9fbf 100644 (file)
@@ -44,6 +44,7 @@ extern const char *output_move_double PARAMS ((rtx *));
 extern const char *output_fp_move_double PARAMS ((rtx *));
 extern const char *output_block_move PARAMS ((rtx *, int));
 extern const char *output_cbranch PARAMS ((rtx *, int, int, int, rtx));
+extern const char *output_lbranch PARAMS ((rtx, rtx));
 extern const char *output_bb PARAMS ((rtx *, int, int, int, rtx, int));
 extern const char *output_bvb PARAMS ((rtx *, int, int, int, rtx, int));
 extern const char *output_dbra PARAMS ((rtx *, rtx, int));
index 921e606..83205ba 100644 (file)
@@ -3270,10 +3270,10 @@ compute_frame_size (size, fregs_live)
   size += current_function_outgoing_args_size;
 
   /* Allocate space for the fixed frame marker.  This space must be
-     allocated for any function that makes calls or otherwise allocates
+     allocated for any function that makes calls or allocates
      stack space.  */
   if (!current_function_is_leaf || size)
-    size += TARGET_64BIT ? 16 : 32;
+    size += TARGET_64BIT ? 48 : 32;
 
   /* Finally, round to the preferred stack boundary.  */
   return ((size + PREFERRED_STACK_BOUNDARY / 8 - 1)
@@ -3317,6 +3317,15 @@ pa_output_function_prologue (file, size)
   else
     fputs (",NO_CALLS", file);
 
+  /* The SAVE_SP flag is used to indicate that register %r3 is stored
+     at the beginning of the frame and that it is used as the frame
+     pointer for the frame.  We do this because our current frame
+     layout doesn't conform to that specified in the the HP runtime
+     documentation and we need a way to indicate to programs such as
+     GDB where %r3 is saved.  The SAVE_SP flag was chosen because it
+     isn't used by HP compilers but is supported by the assembler.
+     However, SAVE_SP is supposed to indicate that the previous stack
+     pointer has been saved in the frame marker.  */
   if (frame_pointer_needed)
     fputs (",SAVE_SP", file);
 
@@ -3416,11 +3425,32 @@ hppa_expand_prologue ()
                              adjust2, 1);
            }
 
-         /* Prevent register spills from being scheduled before the
-            stack pointer is raised.  Necessary as we will be storing
-            registers using the frame pointer as a base register, and
-            we happen to set fp before raising sp.  */
-         emit_insn (gen_blockage ());
+         /* We set SAVE_SP in frames that need a frame pointer.  Thus,
+            we need to store the previous stack pointer (frame pointer)
+            into the frame marker on targets that use the HP unwind
+            library.  This allows the HP unwind library to be used to
+            unwind GCC frames.  However, we are not fully compatible
+            with the HP library because our frame layout differs from
+            that specified in the HP runtime specification.
+
+            We don't want a frame note on this instruction as the frame
+            marker moves during dynamic stack allocation.
+
+            This instruction also serves as a blockage to prevent
+            register spills from being scheduled before the stack
+            pointer is raised.  This is necessary as we store
+            registers using the frame pointer as a base register,
+            and the frame pointer is set before sp is raised.  */
+         if (TARGET_HPUX_UNWIND_LIBRARY)
+           {
+             rtx addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+                                      GEN_INT (TARGET_64BIT ? -8 : -4));
+
+             emit_move_insn (gen_rtx_MEM (word_mode, addr),
+                             frame_pointer_rtx);
+           }
+         else
+           emit_insn (gen_blockage ());
        }
       /* no frame pointer needed.  */
       else
@@ -5517,6 +5547,7 @@ output_cbranch (operands, nullify, length, negated, insn)
 {
   static char buf[100];
   int useskip = 0;
+  rtx xoperands[5];
 
   /* A conditional branch to the following instruction (eg the delay slot) is
      asking for a disaster.  This can happen when not optimizing.
@@ -5622,98 +5653,182 @@ output_cbranch (operands, nullify, length, negated, insn)
        break;
 
       case 20:
-       /* Very long branch.  Right now we only handle these when not
-          optimizing.  See "jump" pattern in pa.md for details.  */
-       if (optimize)
-         abort ();
+      case 28:
+       xoperands[0] = operands[0];
+       xoperands[1] = operands[1];
+       xoperands[2] = operands[2];
+       xoperands[3] = operands[3];
+
+       /* The reversed conditional branch must branch over one additional
+          instruction if the delay slot is filled.  If the delay slot
+          is empty, the instruction after the reversed condition branch
+          must be nullified.  */
+       nullify = dbr_sequence_length () == 0;
+       xoperands[4] = nullify ? GEN_INT (length) : GEN_INT (length + 4);
 
        /* Create a reversed conditional branch which branches around
           the following insns.  */
-       if (negated)
-         strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+20|cmp%I2b,%S3,n %2,%r1,.+20}");
+       if (GET_MODE (operands[1]) != DImode)
+         {
+           if (nullify)
+             {
+               if (negated)
+                 strcpy (buf,
+                   "{com%I2b,%S3,n %2,%r1,.+%4|cmp%I2b,%S3,n %2,%r1,.+%4}");
+               else
+                 strcpy (buf,
+                   "{com%I2b,%B3,n %2,%r1,.+%4|cmp%I2b,%B3,n %2,%r1,.+%4}");
+             }
+           else
+             {
+               if (negated)
+                 strcpy (buf,
+                   "{com%I2b,%S3 %2,%r1,.+%4|cmp%I2b,%S3 %2,%r1,.+%4}");
+               else
+                 strcpy (buf,
+                   "{com%I2b,%B3 %2,%r1,.+%4|cmp%I2b,%B3 %2,%r1,.+%4}");
+             }
+         }
        else
-         strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+20|cmp%I2b,%B3,n %2,%r1,.+20}");
-       if (GET_MODE (operands[1]) == DImode)
          {
-           if (negated)
-             strcpy (buf,
-                     "{com%I2b,*%S3,n %2,%r1,.+20|cmp%I2b,*%S3,n %2,%r1,.+20}");
+           if (nullify)
+             {
+               if (negated)
+                 strcpy (buf,
+                   "{com%I2b,*%S3,n %2,%r1,.+%4|cmp%I2b,*%S3,n %2,%r1,.+%4}");
+               else
+                 strcpy (buf,
+                   "{com%I2b,*%B3,n %2,%r1,.+%4|cmp%I2b,*%B3,n %2,%r1,.+%4}");
+             }
            else
-             strcpy (buf,
-                     "{com%I2b,*%B3,n %2,%r1,.+20|cmp%I2b,*%B3,n %2,%r1,.+20}");
+             {
+               if (negated)
+                 strcpy (buf,
+                   "{com%I2b,*%S3 %2,%r1,.+%4|cmp%I2b,*%S3 %2,%r1,.+%4}");
+               else
+                 strcpy (buf,
+                   "{com%I2b,*%B3 %2,%r1,.+%4|cmp%I2b,*%B3 %2,%r1,.+%4}");
+             }
          }
-       output_asm_insn (buf, operands);
 
-       /* Output an insn to save %r1.  */
-       output_asm_insn ("stw %%r1,-16(%%r30)", operands);
+       output_asm_insn (buf, xoperands);
+       return output_lbranch (operands[0], insn);
 
-       /* Now output a very long branch to the original target.  */
-       output_asm_insn ("ldil L'%l0,%%r1\n\tbe R'%l0(%%sr4,%%r1)", operands);
+      default:
+       abort ();
+    }
+  return buf;
+}
 
-       /* Now restore the value of %r1 in the delay slot.  We're not
-          optimizing so we know nothing else can be in the delay slot.  */
-       return "ldw -16(%%r30),%%r1";
+/* This routine handles long unconditional branches that exceed the
+   maximum range of a simple branch instruction.  */
 
-      case 28:
-       /* Very long branch when generating PIC code.  Right now we only
-          handle these when not optimizing.  See "jump" pattern in pa.md
-          for details.  */
-       if (optimize)
-         abort ();
+const char *
+output_lbranch (dest, insn)
+     rtx dest, insn;
+{
+  rtx xoperands[2];
+  xoperands[0] = dest;
 
-       /* Create a reversed conditional branch which branches around
-          the following insns.  */
-       if (negated)
-         strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+28|cmp%I2b,%S3,n %2,%r1,.+28}");
-       else
-         strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+28|cmp%I2b,%B3,n %2,%r1,.+28}");
-       if (GET_MODE (operands[1]) == DImode)
-         {
-           if (negated)
-             strcpy (buf, "{com%I2b,*%S3,n %2,%r1,.+28|cmp%I2b,*%S3,n %2,%r1,.+28}");
-           else
-             strcpy (buf, "{com%I2b,*%B3,n %2,%r1,.+28|cmp%I2b,*%B3,n %2,%r1,.+28}");
-         }
-       output_asm_insn (buf, operands);
+  /* First, free up the delay slot.  */
+  if (dbr_sequence_length () != 0)
+    {
+      /* We can't handle a jump in the delay slot.  */
+      if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
+       abort ();
 
-       /* Output an insn to save %r1.  */
-       output_asm_insn ("stw %%r1,-16(%%r30)", operands);
+      final_scan_insn (NEXT_INSN (insn), asm_out_file,
+                      optimize, 0, 0);
+
+      /* Now delete the delay insn.  */
+      PUT_CODE (NEXT_INSN (insn), NOTE);
+      NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
+      NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+    }
+
+  /* Output an insn to save %r1.  The runtime documentation doesn't
+     specify whether the "Clean Up" slot in the callers frame can
+     be clobbered by the callee.  It isn't copied by HP's builtin
+     alloca, so this suggests that it can be clobbered if necessary.
+     The "Static Link" location is copied by HP builtin alloca, so
+     we avoid using it.  Using the cleanup slot might be a problem
+     if we have to interoperate with languages that pass cleanup
+     information.  However, it should be possible to handle these
+     situations with GCC's asm feature.
+
+     The "Current RP" slot is reserved for the called procedure, so
+     we try to use it when we don't have a frame of our own.  It's
+     rather unlikely that we won't have a frame when we need to emit
+     a very long branch.
+
+     Really the way to go long term is a register scavenger; goto
+     the target of the jump and find a register which we can use
+     as a scratch to hold the value in %r1.  Then, we wouldn't have
+     to free up the delay slot or clobber a slot that may be needed
+     for other purposes.  */
+  if (TARGET_64BIT)
+    {
+      if (actual_fsize == 0 && !regs_ever_live[2])
+       /* Use the return pointer slot in the frame marker.  */
+       output_asm_insn ("std %%r1,-16(%%r30)", xoperands);
+      else
+       /* Use the slot at -40 in the frame marker since HP builtin
+          alloca doesn't copy it.  */
+       output_asm_insn ("std %%r1,-40(%%r30)", xoperands);
+    }
+  else
+    {
+      if (actual_fsize == 0 && !regs_ever_live[2])
+       /* Use the return pointer slot in the frame marker.  */
+       output_asm_insn ("stw %%r1,-20(%%r30)", xoperands);
+      else
+       /* Use the "Clean Up" slot in the frame marker.  In GCC,
+          the only other use of this location is for copying a
+          floating point double argument from a floating-point
+          register to two general registers.  The copy is done
+          as an "atomic" operation when outputing a call, so it
+          won't interfere with our using the location here.  */
+       output_asm_insn ("stw %%r1,-12(%%r30)", xoperands);
+    }
 
-       /* Now output a very long PIC branch to the original target.  */
+  if (flag_pic)
+    {
+      output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+      if (TARGET_SOM || !TARGET_GAS)
        {
-         rtx xoperands[5];
-
-         xoperands[0] = operands[0];
-         xoperands[1] = operands[1];
-         xoperands[2] = operands[2];
-         xoperands[3] = operands[3];
-
-         output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
-         if (TARGET_SOM || !TARGET_GAS)
-           {
-             xoperands[4] = gen_label_rtx ();
-             output_asm_insn ("addil L'%l0-%l4,%%r1", xoperands);
-             (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                        CODE_LABEL_NUMBER (xoperands[4]));
-             output_asm_insn ("ldo R'%l0-%l4(%%r1),%%r1", xoperands);
-           }
-         else
-           {
-             output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands);
-             output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1",
-                              xoperands);
-           }
-         output_asm_insn ("bv %%r0(%%r1)", xoperands);
+         xoperands[1] = gen_label_rtx ();
+         output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands);
+         (*targetm.asm_out.internal_label) (asm_out_file, "L",
+                                            CODE_LABEL_NUMBER (xoperands[1]));
+         output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands);
        }
+      else
+       {
+         output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands);
+         output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
+       }
+      output_asm_insn ("bv %%r0(%%r1)", xoperands);
+    }
+  else
+    /* Now output a very long branch to the original target.  */
+    output_asm_insn ("ldil L'%l0,%%r1\n\tbe R'%l0(%%sr4,%%r1)", xoperands);
 
-       /* Now restore the value of %r1 in the delay slot.  We're not
-          optimizing so we know nothing else can be in the delay slot.  */
-       return "ldw -16(%%r30),%%r1";
-
-      default:
-       abort ();
+  /* Now restore the value of %r1 in the delay slot.  */
+  if (TARGET_64BIT)
+    {
+      if (actual_fsize == 0 && !regs_ever_live[2])
+       return "ldd -16(%%r30),%%r1";
+      else
+       return "ldd -40(%%r30),%%r1";
+    }
+  else
+    {
+      if (actual_fsize == 0 && !regs_ever_live[2])
+       return "ldw -20(%%r30),%%r1";
+      else
+       return "ldw -12(%%r30),%%r1";
     }
-  return buf;
 }
 
 /* This routine handles all the branch-on-bit conditional branch sequences we
index 8659058..177cae3 100644 (file)
@@ -211,6 +211,15 @@ extern int target_flags;
    definition symbols is buggy prior to HP-UX 11.X.  */
 #define TARGET_SOM_SDEF 0
 
+/* Define to a C expression evaluating to true to save the entry value
+   of SP in the current frame marker.  This is normally unnecessary.
+   However, the HP-UX unwind library looks at the SAVE_SP callinfo flag.
+   HP compilers don't use this flag but it is supported by the assembler.
+   We set this flag to indicate that register %r3 has been saved at the
+   start of the frame.  Thus, when the HP unwind library is used, we
+   need to generate additional code to save SP into the frame marker.  */
+#define TARGET_HPUX_UNWIND_LIBRARY 0
+
 /* Macro to define tables used to set the flags.  This is a
    list in braces of target switches with each switch being
    { "NAME", VALUE, "HELP_STRING" }.  VALUE is the bits to set,
@@ -714,9 +723,13 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
 /* The weird HPPA calling conventions require a minimum of 48 bytes on
    the stack: 16 bytes for register saves, and 32 bytes for magic.
    This is the difference between the logical top of stack and the
-   actual sp.  */
+   actual sp.
+
+   On the 64-bit port, the HP C compiler allocates a 48-byte frame
+   marker, although the runtime documentation only describes a 16
+   byte marker.  For compatibility, we allocate 48 bytes.  */
 #define STACK_POINTER_OFFSET \
-  (TARGET_64BIT ? -(current_function_outgoing_args_size + 16): -32)
+  (TARGET_64BIT ? -(current_function_outgoing_args_size + 48): -32)
 
 #define STACK_DYNAMIC_OFFSET(FNDECL)   \
   (TARGET_64BIT                                \
index 2673739..0f50c8f 100644 (file)
   ""
   "*
 {
-  extern int optimize;
-
   if (GET_MODE (insn) == SImode)
     return \"b %l0%#\";
 
       && get_attr_length (insn) != 16)
     return \"b%* %l0\";
 
-  /* An unconditional branch which can not reach its target.
-
-     We need to be able to use %r1 as a scratch register; however,
-     we can never be sure whether or not it's got a live value in
-     it.  Therefore, we must restore its original value after the
-     jump.
-
-     To make matters worse, we don't have a stack slot which we
-     can always clobber.  sp-12/sp-16 shouldn't ever have a live
-     value during a non-optimizing compilation, so we use those
-     slots for now.  We don't support very long branches when
-     optimizing -- they should be quite rare when optimizing.
-
-     Really the way to go long term is a register scavenger; goto
-     the target of the jump and find a register which we can use
-     as a scratch to hold the value in %r1.  */
-
-  /* We don't know how to register scavenge yet.  */
-  if (optimize)
-    abort ();
-
-  /* First store %r1 into the stack.  */
-  output_asm_insn (\"stw %%r1,-16(%%r30)\", operands);
-
-  /* Now load the target address into %r1 and do an indirect jump
-     to the value specified in %r1.  Be careful to generate PIC
-     code as needed.  */
-  if (flag_pic)
-    {
-      rtx xoperands[2];
-      xoperands[0] = operands[0];
-      if (TARGET_SOM || ! TARGET_GAS)
-       {
-         xoperands[1] = gen_label_rtx ();
-
-         output_asm_insn (\"{bl|b,l} .+8,%%r1\\n\\taddil L'%l0-%l1,%%r1\",
-                          xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
-                                    CODE_LABEL_NUMBER (xoperands[1]));
-         output_asm_insn (\"ldo R'%l0-%l1(%%r1),%%r1\", xoperands);
-       }
-      else
-       {
-         output_asm_insn (\"{bl|b,l} .+8,%%r1\", xoperands);
-         output_asm_insn (\"addil L'%l0-$PIC_pcrel$0+4,%%r1\", xoperands);
-         output_asm_insn (\"ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1\", xoperands);
-       }
-      output_asm_insn (\"bv %%r0(%%r1)\", xoperands);
-    }
-  else
-    output_asm_insn (\"ldil L'%l0,%%r1\\n\\tbe R'%l0(%%sr4,%%r1)\", operands);;
-
-  /* And restore the value of %r1 in the delay slot.  We're not optimizing,
-     so we know nothing else can be in the delay slot.  */
-  return \"ldw -16(%%r30),%%r1\";
+  return output_lbranch (operands[0], insn);
 }"
   [(set_attr "type" "uncond_branch")
    (set_attr "pa_combine_type" "uncond_branch")
   emit_insn (gen_blockage ());
   DONE;
 }")
+
+;; Allocate new stack space and update the saved stack pointer in the
+;; frame marker.  The HP C compilers also copy additional words in the
+;; frame marker.  The 64-bit compiler copies words at -48, -32 and -24.
+;; The 32-bit compiler copies the word at -16 (Static Link).  We
+;; currently don't copy these values.
+;;
+;; Since the copy of the frame marker can't be done atomically, I
+;; suspect that using it for unwind purposes may be somewhat unreliable.
+;; The HP compilers appear to raise the stack and copy the frame
+;; marker in a strict instruction sequence.  This suggests that the
+;; unwind library may check for an alloca sequence when ALLOCA_FRAME
+;; is set in the callinfo data.  We currently don't set ALLOCA_FRAME
+;; as GAS doesn't support it, or try to keep the instructions emitted
+;; here in strict sequence.
+(define_expand "allocate_stack"
+  [(match_operand 0 "" "")
+   (match_operand 1 "" "")]
+  ""
+  "
+{
+  /* Since the stack grows upward, we need to store virtual_stack_dynamic_rtx
+     in operand 0 before adjusting the stack.  */
+  emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+  anti_adjust_stack (operands[1]);
+  if (TARGET_HPUX_UNWIND_LIBRARY)
+    {
+      rtx dst = gen_rtx_MEM (word_mode,
+                            gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+                                          GEN_INT (TARGET_64BIT ? -8 : -4)));
+
+      emit_move_insn (dst, frame_pointer_rtx);
+    }
+  DONE;
+}")