Commit 685d0e07 by John David Anglin Committed by John David Anglin

re PR target/10062 (internal compiler error: in output_cbranch, at config/pa/pa.c: 5515)

	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.

From-SVN: r64570
parent 6788f5ca
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
......
......@@ -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
......@@ -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));
......
......@@ -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
......
......@@ -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 \
......
......@@ -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;
}")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment