summaryrefslogtreecommitdiff
path: root/gcc/config/pa
diff options
context:
space:
mode:
authordanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>2003-03-19 04:41:48 +0000
committerdanglin <danglin@138bc75d-0d04-0410-961f-82ee72b054a4>2003-03-19 04:41:48 +0000
commite9ec370e36b7c4ca140202deab4aff94817683c5 (patch)
tree8cab564fd46594fddefc2c1e4e53ef844b33310a /gcc/config/pa
parent3a32429b826bfb2575ba0b7eb1d652c5a820632a (diff)
downloadgcc-e9ec370e36b7c4ca140202deab4aff94817683c5.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@64570 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/pa')
-rw-r--r--gcc/config/pa/pa-hpux.h5
-rw-r--r--gcc/config/pa/pa-protos.h1
-rw-r--r--gcc/config/pa/pa.c277
-rw-r--r--gcc/config/pa/pa.h17
-rw-r--r--gcc/config/pa/pa.md93
5 files changed, 253 insertions, 140 deletions
diff --git a/gcc/config/pa/pa-hpux.h b/gcc/config/pa/pa-hpux.h
index a4ed77f983e..d6e15164013 100644
--- a/gcc/config/pa/pa-hpux.h
+++ b/gcc/config/pa/pa-hpux.h
@@ -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
diff --git a/gcc/config/pa/pa-protos.h b/gcc/config/pa/pa-protos.h
index 248e1a7d05e..16c9fbf079a 100644
--- a/gcc/config/pa/pa-protos.h
+++ b/gcc/config/pa/pa-protos.h
@@ -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));
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 921e606edb7..83205ba2568 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -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
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 86590583139..177cae33ddc 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -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 \
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index 2673739849f..0f50c8ff71d 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -5721,8 +5721,6 @@
""
"*
{
- extern int optimize;
-
if (GET_MODE (insn) == SImode)
return \"b %l0%#\";
@@ -5731,61 +5729,7 @@
&& 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")
@@ -8053,3 +7997,38 @@
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;
+}")