Commit 823fbbce by John David Anglin Committed by John David Anglin

pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.

	* pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.
	(DWARF_FRAME_RETURN_COLUMN): Move.
	(ASM_PREFERRED_EH_DATA_FORMAT): Define.
	(ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Define.
	* pa.c (except.h, predict.h): Include.
	(FRP): Delete.
	(store_reg_modify, set_reg_plus_d): Revise prototypes.
	(output_ascii): Add cast.
	(store_reg_modify): Revise to add frame notes.
	(set_reg_plus_d): Likewise.
	(compute_frame_size): Include space for eh data registers in frame if
	the current function calls eh_return.
	(hppa_expand_prologue):  Ensure register %r2 is saved if the current
	function calls eh_return.  Save eh data registers if the current
	function calls eh_return.  Fix code to add frame notes.  Emit
	blockage to prevent insns with frame notes being scheduled in the
	delay slot of calls.
	(hppa_expand_epilogue): Restore eh data registers and do final stack
	adjustment if the current function calls eh_return.  Don't add frame
	notes.
	(output_call): Revise for change in length of call insn.  Don't do
	return pointer adjustment for an unconditional jump in the delay slot
	of a call when using frame notes.
	* pa.h (EH_RETURN_DATA_REGNO): Revise for TARGET_64BIT compatibility.
	(EH_RETURN_HANDLER_RTX): Use saved value on stack.
	(ARG_POINTER_CFA_OFFSET): Define.
	* pa.md (return_external_pic): New pattern.
	(prologue): Correct formatting.  Use return_external_pic if current
	function calls eh_return.
	(call_internal_symref, call_value_internal_symref,
	sibcall_internal_symref, sibcall_value_internal_symref): Change default
	lengths of short, long non-pic, and long pic calls to 8, 68, and 84,
	respectively.
	(exception_receiver): Use hppa_pic_save_rtx () to restore pic register.

	* configure.in ("assembler dwarf2 debug_line support"): Add hppa*-*-* to
	list of targets to check using "nop" insn.
	* configure: Rebuilt.

From-SVN: r51836
parent 4078e224
2002-04-03 John David Anglin <dave@hiauly1.hia.nrc.ca>
* pa-linux.h (INCOMING_RETURN_ADDR_RTX): Move.
(DWARF_FRAME_RETURN_COLUMN): Move.
(ASM_PREFERRED_EH_DATA_FORMAT): Define.
(ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Define.
* pa.c (except.h, predict.h): Include.
(FRP): Delete.
(store_reg_modify, set_reg_plus_d): Revise prototypes.
(output_ascii): Add cast.
(store_reg_modify): Revise to add frame notes.
(set_reg_plus_d): Likewise.
(compute_frame_size): Include space for eh data registers in frame if
the current function calls eh_return.
(hppa_expand_prologue): Ensure register %r2 is saved if the current
function calls eh_return. Save eh data registers if the current
function calls eh_return. Fix code to add frame notes. Emit
blockage to prevent insns with frame notes being scheduled in the
delay slot of calls.
(hppa_expand_epilogue): Restore eh data registers and do final stack
adjustment if the current function calls eh_return. Don't add frame
notes.
(output_call): Revise for change in length of call insn. Don't do
return pointer adjustment for an unconditional jump in the delay slot
of a call when using frame notes.
* pa.h (EH_RETURN_DATA_REGNO): Revise for TARGET_64BIT compatibility.
(EH_RETURN_HANDLER_RTX): Use saved value on stack.
(ARG_POINTER_CFA_OFFSET): Define.
* pa.md (return_external_pic): New pattern.
(prologue): Correct formatting. Use return_external_pic if current
function calls eh_return.
(call_internal_symref, call_value_internal_symref,
sibcall_internal_symref, sibcall_value_internal_symref): Change default
lengths of short, long non-pic, and long pic calls to 8, 68, and 84,
respectively.
(exception_receiver): Use hppa_pic_save_rtx () to restore pic register.
* configure.in ("assembler dwarf2 debug_line support"): Add hppa*-*-* to
list of targets to check using "nop" insn.
* configure: Rebuilt.
2002-04-04 Alan Modra <amodra@bigpond.net.au>
* config/rs6000/t-linux64 (EXTRA_MULTILIB_PARTS): Define.
......
......@@ -24,6 +24,39 @@ Boston, MA 02111-1307, USA. */
#define DWARF2_ASM_LINE_DEBUG_INFO 1
#define DWARF2_UNWIND_INFO 1
/* A C expression whose value is RTL representing the location of the
incoming return address at the beginning of any function, before the
prologue. You only need to define this macro if you want to support
call frame debugging information like that provided by DWARF 2. */
#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG (word_mode, 2))
#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
/* This macro chooses the encoding of pointers embedded in the exception
handling sections. If at all possible, this should be defined such
that the exception handling section will not require dynamic relocations,
and so may be read-only.
FIXME: We use DW_EH_PE_aligned to output a PLABEL constructor for
global function pointers. */
#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
(CODE == 2 && GLOBAL ? DW_EH_PE_aligned : DW_EH_PE_absptr)
/* Handle special EH pointer encodings. Absolute, pc-relative, and
indirect are handled automatically. Since pc-relative encoding is
not possible on the PA and we don't have the infrastructure for
data relative encoding, we use aligned plabels for global function
pointers. */
#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \
do { \
if (((ENCODING) & 0x0F) == DW_EH_PE_aligned) \
{ \
fputs (integer_asm_op (SIZE, FALSE), FILE); \
fputs ("P%", FILE); \
assemble_name (FILE, XSTR (ADDR, 0)); \
goto DONE; \
} \
} while (0)
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__hppa__ -Dlinux -Asystem=unix -Asystem=posix -Acpu=hppa -Amachine=hppa -Amachine=bigendian"
......@@ -64,12 +97,6 @@ Boston, MA 02111-1307, USA. */
else \
readonly_data_section ();
/* A C expression whose value is RTL representing the location of the
incoming return address at the beginning of any function, before the
prologue. */
#define INCOMING_RETURN_ADDR_RTX (gen_rtx_REG (word_mode, 2))
#define DWARF_FRAME_RETURN_COLUMN (DWARF_FRAME_REGNUM (2))
/* Define the strings used for the special svr4 .type and .size directives.
These strings generally do not vary from one system running svr4 to
another, but if a given system (e.g. m88k running svr) needs to use
......
......@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
#include "except.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
......@@ -43,6 +44,7 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "ggc.h"
#include "recog.h"
#include "predict.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
......@@ -55,18 +57,6 @@ Boston, MA 02111-1307, USA. */
#endif
#endif
#if DO_FRAME_NOTES
#define FRP(INSN) \
do \
{ \
rtx insn = INSN; \
RTX_FRAME_RELATED_P (insn) = 1; \
} \
while (0)
#else
#define FRP(INSN) INSN
#endif
#ifndef FUNC_BEGIN_PROLOG_LABEL
#define FUNC_BEGIN_PROLOG_LABEL "LFBP"
#endif
......@@ -83,8 +73,9 @@ static int compute_movstrsi_length PARAMS ((rtx));
static bool pa_assemble_integer PARAMS ((rtx, unsigned int, int));
static void remove_useless_addtr_insns PARAMS ((rtx, int));
static void store_reg PARAMS ((int, int, int));
static void store_reg_modify PARAMS ((int, int, int));
static void load_reg PARAMS ((int, int, int));
static void set_reg_plus_d PARAMS ((int, int, int));
static void set_reg_plus_d PARAMS ((int, int, int, int));
static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int pa_adjust_priority PARAMS ((rtx, int));
......@@ -2662,7 +2653,7 @@ output_ascii (file, p, size)
fputs ("\"\n\t.STRING \"", file);
chars_output = 0;
}
fwrite (partial_output, 1, co, file);
fwrite (partial_output, 1, (size_t) co, file);
chars_output += co;
co = 0;
}
......@@ -2933,15 +2924,60 @@ store_reg (reg, disp, base)
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Emit RTL to set REG to the value specified by BASE+DISP.
Handle case where DISP > 8k by using the add_high_const patterns.
/* Emit RTL to store REG at the memory location specified by BASE and then
add MOD to BASE. MOD must be <= 8k. */
Note in DISP > 8k case, we will leave the high part of the address
in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
static void
store_reg_modify (base, reg, mod)
int base, reg, mod;
{
rtx insn, basereg, srcreg, delta;
if (! VAL_14_BITS_P (mod))
abort ();
basereg = gen_rtx_REG (Pmode, base);
srcreg = gen_rtx_REG (word_mode, reg);
delta = GEN_INT (mod);
insn = emit_insn (gen_post_store (basereg, srcreg, delta));
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
/* RTX_FRAME_RELATED_P must be set on each frame related set
in a parallel with more than one element. Don't set
RTX_FRAME_RELATED_P in the first set if reg is temporary
register 1. The effect of this operation is recorded in
the initial copy. */
if (reg != 1)
{
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
}
else
{
/* The first element of a PARALLEL is always processed if it is
a SET. Thus, we need an expression list for this case. */
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, basereg,
gen_rtx_PLUS (word_mode, basereg, delta)),
REG_NOTES (insn));
}
}
}
/* Emit RTL to set REG to the value specified by BASE+DISP. Handle case
where DISP > 8k by using the add_high_const patterns. NOTE indicates
whether to add a frame note or not.
In the DISP > 8k case, we leave the high part of the address in %r1.
There is code in expand_hppa_{prologue,epilogue} that knows about this. */
static void
set_reg_plus_d (reg, base, disp)
int reg, base, disp;
set_reg_plus_d (reg, base, disp, note)
int reg, base, disp, note;
{
rtx insn;
......@@ -2963,7 +2999,7 @@ set_reg_plus_d (reg, base, disp)
delta));
}
if (DO_FRAME_NOTES && reg == STACK_POINTER_REGNUM)
if (DO_FRAME_NOTES && note)
RTX_FRAME_RELATED_P (insn) = 1;
}
......@@ -2981,6 +3017,18 @@ compute_frame_size (size, fregs_live)
of them at the same time. */
fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
/* If the current function calls __builtin_eh_return, then we need
to allocate stack space for registers that will hold data for
the exception handler. */
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i;
for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
continue;
fsize += i * UNITS_PER_WORD;
}
/* Account for space used by the callee general register saves. */
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
......@@ -3108,7 +3156,7 @@ hppa_expand_prologue ()
int size = get_frame_size ();
int merge_sp_adjust_with_store = 0;
int i, offset;
rtx tmpreg, size_rtx;
rtx insn, tmpreg;
gr_saved = 0;
fr_saved = 0;
......@@ -3126,12 +3174,11 @@ hppa_expand_prologue ()
/* Compute a few things we will use often. */
tmpreg = gen_rtx_REG (word_mode, 1);
size_rtx = GEN_INT (actual_fsize);
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp - 20 or sp - 16
depending on which ABI is in use. */
if (regs_ever_live[2])
if (regs_ever_live[2] || current_function_calls_eh_return)
store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
/* Allocate the local frame and set up the frame pointer if needed. */
......@@ -3141,36 +3188,30 @@ hppa_expand_prologue ()
{
/* Copy the old frame pointer temporarily into %r1. Set up the
new stack pointer, then store away the saved old frame pointer
into the stack at sp+actual_fsize and at the same time update
the stack pointer by actual_fsize bytes. Two versions, first
into the stack at sp and at the same time update the stack
pointer by actual_fsize bytes. Two versions, first
handles small (<8k) frames. The second handles large (>=8k)
frames. */
emit_move_insn (tmpreg, frame_pointer_rtx);
FRP (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
if (VAL_14_BITS_P (actual_fsize))
insn = emit_move_insn (tmpreg, frame_pointer_rtx);
if (DO_FRAME_NOTES)
{
rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
size_rtx));
if (DO_FRAME_NOTES)
{
rtvec vec;
RTX_FRAME_RELATED_P (insn) = 1;
vec = gen_rtvec (2,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode,
stack_pointer_rtx),
frame_pointer_rtx),
gen_rtx_SET (VOIDmode,
stack_pointer_rtx,
gen_rtx_PLUS (word_mode,
stack_pointer_rtx,
size_rtx)));
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SEQUENCE (VOIDmode, vec),
REG_NOTES (insn));
}
/* We need to record the frame pointer save here since the
new frame pointer is set in the following insn. */
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode, stack_pointer_rtx),
frame_pointer_rtx),
REG_NOTES (insn));
}
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
if (DO_FRAME_NOTES)
RTX_FRAME_RELATED_P (insn) = 1;
if (VAL_14_BITS_P (actual_fsize))
store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
else
{
/* It is incorrect to store the saved frame pointer at *sp,
......@@ -3181,32 +3222,12 @@ hppa_expand_prologue ()
finish allocating the new frame. */
int adjust1 = 8192 - 64;
int adjust2 = actual_fsize - adjust1;
rtx delta = GEN_INT (adjust1);
rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
delta));
if (DO_FRAME_NOTES)
{
rtvec vec;
RTX_FRAME_RELATED_P (insn) = 1;
vec = gen_rtvec (2,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode,
stack_pointer_rtx),
frame_pointer_rtx),
gen_rtx_SET (VOIDmode,
stack_pointer_rtx,
gen_rtx_PLUS (word_mode,
stack_pointer_rtx,
delta)));
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SEQUENCE (VOIDmode, vec),
REG_NOTES (insn));
}
store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
adjust2);
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
......@@ -3226,7 +3247,7 @@ hppa_expand_prologue ()
bytes. */
else
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
actual_fsize);
actual_fsize, 1);
}
}
......@@ -3236,7 +3257,27 @@ hppa_expand_prologue ()
was done earlier. */
if (frame_pointer_needed)
{
for (i = 18, offset = local_fsize; i >= 4; i--)
offset = local_fsize;
/* Saving the EH return data registers in the frame is the simplest
way to get the frame unwind information emitted. We put them
just before the general registers. */
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
store_reg (regno, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
......@@ -3249,18 +3290,42 @@ hppa_expand_prologue ()
/* No frame pointer needed. */
else
{
for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
offset = local_fsize - actual_fsize;
/* Saving the EH return data registers in the frame is the simplest
way to get the frame unwind information emitted. */
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first save. */
if (merge_sp_adjust_with_store)
{
store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
merge_sp_adjust_with_store = 0;
}
else
store_reg (regno, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
if (merge_sp_adjust_with_store)
{
rtx delta = GEN_INT (-offset);
store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
merge_sp_adjust_with_store = 0;
FRP (emit_insn (gen_post_store (stack_pointer_rtx,
gen_rtx_REG (word_mode, i),
delta)));
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
......@@ -3272,7 +3337,7 @@ hppa_expand_prologue ()
did any GR saves, then just emit the adjustment here. */
if (merge_sp_adjust_with_store)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
actual_fsize);
actual_fsize, 1);
}
/* The hppa calling conventions say that %r19, the pic offset
......@@ -3290,12 +3355,20 @@ hppa_expand_prologue ()
/* Floating point register store. */
if (save_fregs)
{
rtx base;
/* First get the frame or stack pointer to the start of the FP register
save area. */
if (frame_pointer_needed)
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
{
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
base = frame_pointer_rtx;
}
else
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
{
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
base = stack_pointer_rtx;
}
/* Now actually save the FP registers. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
......@@ -3310,20 +3383,49 @@ hppa_expand_prologue ()
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (DFmode,
plus_constant (stack_pointer_rtx,
offset)),
reg),
REG_NOTES (insn));
if (TARGET_64BIT)
{
rtx mem = gen_rtx_MEM (DFmode,
plus_constant (base, offset));
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, mem, reg),
REG_NOTES (insn));
}
else
{
rtx meml = gen_rtx_MEM (SFmode,
plus_constant (base, offset));
rtx memr = gen_rtx_MEM (SFmode,
plus_constant (base, offset + 4));
rtx regl = gen_rtx_REG (SFmode, i);
rtx regr = gen_rtx_REG (SFmode, i + 1);
rtx setl = gen_rtx_SET (VOIDmode, meml, regl);
rtx setr = gen_rtx_SET (VOIDmode, memr, regr);
rtvec vec;
RTX_FRAME_RELATED_P (setl) = 1;
RTX_FRAME_RELATED_P (setr) = 1;
vec = gen_rtvec (2, setl, setr);
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SEQUENCE (VOIDmode, vec),
REG_NOTES (insn));
}
}
offset += GET_MODE_SIZE (DFmode);
fr_saved++;
}
}
}
/* FIXME: expand_call and expand_millicode_call need to be fixed to
prevent insns with frame notes being scheduled in the delay slot
of calls. This causes problems because the dwarf2 output code
processes the insn list serially. For now, limit the migration
of prologue insns with a blockage. */
if (DO_FRAME_NOTES)
emit_insn (gen_blockage ());
}
/* Emit RTL to load REG from the memory location specified by BASE+DISP.
......@@ -3407,7 +3509,7 @@ hppa_expand_epilogue ()
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
if (regs_ever_live [2])
if (regs_ever_live [2] || current_function_calls_eh_return)
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
......@@ -3429,7 +3531,26 @@ hppa_expand_epilogue ()
/* General register restores. */
if (frame_pointer_needed)
{
for (i = 18, offset = local_fsize; i >= 4; i--)
offset = local_fsize;
/* If the current function calls __builtin_eh_return, then we need
to restore the saved EH data registers. */
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
load_reg (regno, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
......@@ -3438,7 +3559,34 @@ hppa_expand_epilogue ()
}
else
{
for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
offset = local_fsize - actual_fsize;
/* If the current function calls __builtin_eh_return, then we need
to restore the saved EH data registers. */
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
/* Only for the first load.
merge_sp_adjust_with_load holds the register load
with which we will merge the sp adjustment. */
if (merge_sp_adjust_with_load == 0
&& local_fsize == 0
&& VAL_14_BITS_P (-actual_fsize))
merge_sp_adjust_with_load = regno;
else
load_reg (regno, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
......@@ -3464,9 +3612,9 @@ hppa_expand_epilogue ()
{
/* Adjust the register to index off of. */
if (frame_pointer_needed)
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
else
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
/* Actually do the restores now. */
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
......@@ -3491,45 +3639,36 @@ hppa_expand_epilogue ()
if (frame_pointer_needed)
{
rtx delta = GEN_INT (-64);
rtx insn;
set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
insn = emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx,
delta));
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (word_mode, stack_pointer_rtx,
delta)),
REG_NOTES (insn));
}
set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64, 0);
emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx, delta));
}
/* If we were deferring a callee register restore, do it now. */
else if (merge_sp_adjust_with_load)
{
rtx delta = GEN_INT (-actual_fsize);
rtx dest = gen_rtx_REG (word_mode, merge_sp_adjust_with_load);
rtx insn = emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (word_mode, stack_pointer_rtx,
delta)),
REG_NOTES (insn));
}
emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
}
else if (actual_fsize != 0)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- actual_fsize, 0);
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */
if (ret_off != 0)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
rtx sa = EH_RETURN_STACKADJ_RTX;
emit_insn (gen_blockage ());
emit_insn (TARGET_64BIT
? gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
: gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
}
}
rtx
......@@ -6029,10 +6168,10 @@ output_call (insn, call_dest, sibcall)
and we're sure that the branch will reach the beginning of the $CODE$
subspace. */
if ((dbr_sequence_length () == 0
&& get_attr_length (insn) == 8)
&& get_attr_length (insn) == 12)
|| (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
&& get_attr_length (insn) == 4))
&& get_attr_length (insn) == 8))
{
xoperands[0] = call_dest;
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
......@@ -6041,7 +6180,7 @@ output_call (insn, call_dest, sibcall)
}
/* This call may not reach the beginning of the $CODE$ subspace. */
if (get_attr_length (insn) > 8)
if (get_attr_length (insn) > 12)
{
int delay_insn_deleted = 0;
rtx xoperands[2];
......@@ -6241,14 +6380,16 @@ output_call (insn, call_dest, sibcall)
- INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
/* If the branch was too far away, emit a normal call followed
by a nop, followed by the unconditional branch.
by a nop, followed by the unconditional branch. We also don't
adjust %r2 when generating dwarf2 frame or unwind info since
the adjustment confuses the dwarf2 output.
If the branch is close, then adjust %r2 from within the
call's delay slot. */
xoperands[0] = call_dest;
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
if (! VAL_14_BITS_P (distance))
if (DO_FRAME_NOTES || ! VAL_14_BITS_P (distance))
output_asm_insn ("{bl|b,l} %0,%%r2\n\tnop\n\tb,n %1", xoperands);
else
{
......
......@@ -506,10 +506,22 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
#define STRUCT_VALUE_REGNUM 28
/* Describe how we implement __builtin_eh_return. */
/* FIXME: What's a good choice for the EH data registers on TARGET_64BIT? */
#define EH_RETURN_DATA_REGNO(N) \
((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM)
(TARGET_64BIT \
? ((N) < 4 ? (N) + 4 : INVALID_REGNUM) \
: ((N) < 3 ? (N) + 20 : (N) == 4 ? 31 : INVALID_REGNUM))
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 29)
#define EH_RETURN_HANDLER_RTX gen_rtx_REG (Pmode, 2)
#define EH_RETURN_HANDLER_RTX \
gen_rtx_MEM (word_mode, \
gen_rtx_PLUS (word_mode, frame_pointer_rtx, \
TARGET_64BIT ? GEN_INT (-16) : GEN_INT (-20)))
/* Offset from the argument pointer register value to the top of
stack. This is different from FIRST_PARM_OFFSET because of the
frame marker. */
#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
......
......@@ -5568,6 +5568,21 @@
[(set_attr "type" "branch")
(set_attr "length" "4")])
;; Use the PIC register to ensure it's restored after a
;; call in PIC mode. This is used for eh returns which
;; bypass the return stub.
(define_insn "return_external_pic"
[(return)
(use (match_operand 0 "register_operand" "r"))
(use (reg:SI 2))
(clobber (reg:SI 1))]
"flag_pic
&& current_function_calls_eh_return
&& true_regnum (operands[0]) == PIC_OFFSET_TABLE_REGNUM"
"ldsid (%%sr0,%%r2),%%r1\;mtsp %%r1,%%sr0\;be%* 0(%%sr0,%%r2)"
[(set_attr "type" "branch")
(set_attr "length" "12")])
(define_expand "prologue"
[(const_int 0)]
""
......@@ -5590,15 +5605,24 @@
/* Try to use the trivial return first. Else use the full
epilogue. */
if (hppa_can_use_return_insn_p ())
emit_jump_insn (gen_return ());
emit_jump_insn (gen_return ());
else
{
rtx x;
hppa_expand_epilogue ();
if (flag_pic)
x = gen_return_internal_pic (gen_rtx_REG (word_mode,
PIC_OFFSET_TABLE_REGNUM));
{
rtx pic = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
/* EH returns bypass the normal return stub. Thus, we must do an
interspace branch to return from functions that call eh_return.
This is only a problem for returns from shared code. */
if (current_function_calls_eh_return)
x = gen_return_external_pic (pic);
else
x = gen_return_internal_pic (pic);
}
else
x = gen_return_internal ();
emit_jump_insn (x);
......@@ -5856,18 +5880,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;; linker can use a long-branch stub, then the length is at most
;; 8 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; For long-calls the length will be at most 68 bytes (non-pic)
;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(const_int 4)
(const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
(const_int 52)
(const_int 68))))])
(const_int 68)
(const_int 84))))])
(define_insn "call_internal_reg_64bit"
[(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
......@@ -6029,18 +6054,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;; linker can use a long-branch stub, then the length is at most
;; 8 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; For long-calls the length will be at most 68 bytes (non-pic)
;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(const_int 4)
(const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
(const_int 52)
(const_int 68))))])
(const_int 68)
(const_int 84))))])
(define_insn "call_value_internal_reg_64bit"
[(set (match_operand 0 "" "=rf")
......@@ -6200,18 +6226,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;; linker can use a long-branch stub, then the length is at most
;; 8 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; For long-calls the length will be at most 68 bytes (non-pic)
;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(const_int 4)
(const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
(const_int 52)
(const_int 68))))])
(const_int 68)
(const_int 84))))])
(define_expand "sibcall_value"
[(parallel [(set (match_operand 0 "" "")
......@@ -6258,18 +6285,19 @@
[(set_attr "type" "call")
(set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;; linker can use a long-branch stub, then the length is at most
;; 8 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; For long-calls the length will be at most 68 bytes (non-pic)
;; or 84 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(const_int 4)
(const_int 8)
(if_then_else (eq (symbol_ref "flag_pic")
(const_int 0))
(const_int 52)
(const_int 68))))])
(const_int 68)
(const_int 84))))])
(define_insn "nop"
[(const_int 0)]
......@@ -7216,16 +7244,12 @@
;; restore the PIC register.
(define_expand "exception_receiver"
[(const_int 4)]
"!TARGET_PORTABLE_RUNTIME && flag_pic"
"flag_pic"
"
{
/* Load the PIC register from the stack slot (in our caller's
frame). */
emit_move_insn (pic_offset_table_rtx,
gen_rtx_MEM (SImode,
plus_constant (stack_pointer_rtx, -32)));
emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
emit_insn (gen_blockage ());
/* Restore the PIC register using hppa_pic_save_rtx (). The
PIC register is not saved in the frame in 64-bit ABI. */
emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
DONE;
}")
......
......@@ -2229,7 +2229,7 @@ EOF
fi
# Find some useful tools
for ac_prog in gawk mawk nawk awk
for ac_prog in mawk gawk nawk awk
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
......@@ -7480,7 +7480,7 @@ EOF
fi
echo $ac_n "checking assembler and linker support unaligned pc related relocs against hidden symbols""... $ac_c" 1>&6
echo "configure:7430: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
echo "configure:7484: checking assembler and linker support unaligned pc related relocs against hidden symbols" >&5
if eval "test \"`echo '$''{'gcc_cv_as_sparc_ua_pcrel_hidden'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7522,7 +7522,7 @@ EOF
case "$tm_file" in
*64*)
echo $ac_n "checking for 64 bit support in assembler ($gcc_cv_as)""... $ac_c" 1>&6
echo "configure:7487: checking for 64 bit support in assembler ($gcc_cv_as)" >&5
echo "configure:7526: checking for 64 bit support in assembler ($gcc_cv_as)" >&5
if eval "test \"`echo '$''{'gcc_cv_as_flags64'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7567,7 +7567,7 @@ EOF
if test "x$gcc_cv_as_flags64" != xno; then
echo $ac_n "checking for assembler offsetable %lo() support""... $ac_c" 1>&6
echo "configure:7532: checking for assembler offsetable %lo() support" >&5
echo "configure:7571: checking for assembler offsetable %lo() support" >&5
if eval "test \"`echo '$''{'gcc_cv_as_offsetable_lo10'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7607,7 +7607,7 @@ EOF
i[34567]86-*-* | x86_64-*-*)
echo $ac_n "checking assembler instructions""... $ac_c" 1>&6
echo "configure:7572: checking assembler instructions" >&5
echo "configure:7611: checking assembler instructions" >&5
gcc_cv_as_instructions=
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x; then
if test "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 9 -o "$gcc_cv_gas_major_version" -gt 2; then
......@@ -7634,7 +7634,7 @@ EOF
echo "$ac_t""$gcc_cv_as_instructions" 1>&6
echo $ac_n "checking assembler GOTOFF in data directives""... $ac_c" 1>&6
echo "configure:7599: checking assembler GOTOFF in data directives" >&5
echo "configure:7638: checking assembler GOTOFF in data directives" >&5
gcc_cv_as_gotoff_in_data=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
then
......@@ -7664,7 +7664,7 @@ EOF
esac
echo $ac_n "checking assembler dwarf2 debug_line support""... $ac_c" 1>&6
echo "configure:7629: checking assembler dwarf2 debug_line support" >&5
echo "configure:7668: checking assembler dwarf2 debug_line support" >&5
gcc_cv_as_dwarf2_debug_line=no
# ??? Not all targets support dwarf2 debug_line, even within a version
# of gas. Moreover, we need to emit a valid instruction to trigger any
......@@ -7673,7 +7673,7 @@ gcc_cv_as_dwarf2_debug_line=no
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$target" in
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-*)
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-* | hppa*-*-*)
insn="nop"
;;
ia64*-*-*)
......@@ -7720,7 +7720,7 @@ fi
echo "$ac_t""$gcc_cv_as_dwarf2_debug_line" 1>&6
echo $ac_n "checking assembler --gdwarf2 support""... $ac_c" 1>&6
echo "configure:7685: checking assembler --gdwarf2 support" >&5
echo "configure:7724: checking assembler --gdwarf2 support" >&5
gcc_cv_as_gdwarf2_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
......@@ -7749,7 +7749,7 @@ fi
echo "$ac_t""$gcc_cv_as_gdwarf2_flag" 1>&6
echo $ac_n "checking assembler --gstabs support""... $ac_c" 1>&6
echo "configure:7714: checking assembler --gstabs support" >&5
echo "configure:7753: checking assembler --gstabs support" >&5
gcc_cv_as_gstabs_flag=no
if test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x;
then
......@@ -7777,7 +7777,7 @@ fi
echo "$ac_t""$gcc_cv_as_gstabs_flag" 1>&6
echo $ac_n "checking linker PT_GNU_EH_FRAME support""... $ac_c" 1>&6
echo "configure:7742: checking linker PT_GNU_EH_FRAME support" >&5
echo "configure:7781: checking linker PT_GNU_EH_FRAME support" >&5
gcc_cv_ld_eh_frame_hdr=no
if test x$gcc_cv_gld_major_version != x -a x$gcc_cv_gld_minor_version != x; then
if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 12 -o "$gcc_cv_gld_major_version" -gt 2 && grep 'EMUL = elf' ../ld/Makefile > /dev/null; then
......@@ -7940,7 +7940,7 @@ fi
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
echo "configure:7905: checking whether to enable maintainer-specific portions of Makefiles" >&5
echo "configure:7944: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode"
......
......@@ -1929,7 +1929,7 @@ gcc_cv_as_dwarf2_debug_line=no
# ??? Once 2.11 is released, probably need to add first known working
# version to the per-target configury.
case "$target" in
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-*)
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* | x86_64*-*-* | hppa*-*-*)
insn="nop"
;;
ia64*-*-*)
......
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