This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Don't use lib2funcs.asm on PA
- From: "John David Anglin" <dave at hiauly1 dot hia dot nrc dot ca>
- To: hainque at ACT-Europe dot FR (Olivier Hainque)
- Cc: law at redhat dot com, gcc-patches at gcc dot gnu dot org
- Date: Mon, 18 Feb 2002 11:12:43 -0500 (EST)
- Subject: Re: Don't use lib2funcs.asm on PA
> It is very likely that what you are seeing is related to some problems we
> also "experimented". In the current state of things, we have added an
> eh_return pattern to the machine description and a "for_eh_return" argument
> to hppa_expand_epilogue.
Thanks for the input. The stack adjust was one thing that was missing.
Last night, I arrived at a set of modifications that allow the "stdexceptions"
test in libstdc++ to PASS when linked statically. It still doesn't work
when linked with a shared libstdc++. There were also more issues with the
frame note code and saving and restoring the eh data registers.
I believe that we need an eh_return pattern and use an interspace jump
to return from shared code. I also need to figure out if an eh_return
can return a value. If it can then the data registers need to be revised.
Now on the PA, external calls usually go via a stub. One of the functions
of the stub is to message the outgoing arguments and the return value
so that the caller and callee agree on their location. There could be
a problem with return values because I suspect we bypass the stub on
an eh_return.
I enclosed my latest work. Comments appreciated. I am going to try
to looked at the shared return today.
Dave
--
J. David Anglin dave.anglin@nrc.ca
National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
Index: config/pa/pa-linux.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa-linux.h,v
retrieving revision 1.12
diff -u -3 -p -r1.12 pa-linux.h
--- config/pa/pa-linux.h 15 Feb 2002 19:11:01 -0000 1.12
+++ config/pa/pa-linux.h 18 Feb 2002 04:32:28 -0000
@@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */
#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
#define DWARF2_ASM_LINE_DEBUG_INFO 1
#define DWARF2_UNWIND_INFO 1
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-D__ELF__ -Dunix -D__hppa__ -Dlinux -Asystem=unix -Asystem=posix -Acpu=hppa -Amachine=hppa -Amachine=bigendian"
Index: config/pa/pa.md
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.md,v
retrieving revision 1.101
diff -u -3 -p -r1.101 pa.md
--- config/pa/pa.md 4 Feb 2002 21:05:25 -0000 1.101
+++ config/pa/pa.md 18 Feb 2002 04:32:29 -0000
@@ -7216,14 +7216,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)));
+ /* 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 ());
emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
emit_insn (gen_blockage ());
DONE;
Index: config/pa/pa.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.148
diff -u -3 -p -r1.148 pa.c
--- config/pa/pa.c 12 Feb 2002 15:21:04 -0000 1.148
+++ config/pa/pa.c 18 Feb 2002 04:32:30 -0000
@@ -55,18 +55,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,6 +71,7 @@ static int compute_movstrsi_length PARAM
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 pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
@@ -2662,7 +2651,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,6 +2922,50 @@ store_reg (reg, disp, base)
RTX_FRAME_RELATED_P (insn) = 1;
}
+/* Emit RTL to store REG at the memory location specified by BASE and then
+ add MOD to BASE. MOD must be <= 8k. */
+
+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.
@@ -2981,6 +3014,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 +3153,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,7 +3171,6 @@ 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
@@ -3141,36 +3185,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 +3219,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);
}
+
/* 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
@@ -3236,7 +3254,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 +3287,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);
@@ -3290,12 +3352,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);
+ base = frame_pointer_rtx;
+ }
else
- set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ {
+ set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
+ 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)
@@ -3313,9 +3383,7 @@ hppa_expand_prologue ()
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)),
+ gen_rtx_MEM (DFmode, plus_constant (base, offset)),
reg),
REG_NOTES (insn));
}
@@ -3429,7 +3497,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,6 +3525,33 @@ hppa_expand_epilogue ()
}
else
{
+ 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, offset = local_fsize - actual_fsize; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
@@ -3525,6 +3639,14 @@ hppa_expand_epilogue ()
}
else if (actual_fsize != 0)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, - actual_fsize);
+
+ if (DO_FRAME_NOTES && current_function_calls_eh_return)
+ {
+ rtx sa = EH_RETURN_STACKADJ_RTX;
+ emit_insn (Pmode == SImode
+ ? gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
+ : gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
+ }
/* If we haven't restored %r2 yet (no frame pointer, and a stack
frame greater than 8k), do so now. */