diff options
author | John David Anglin <dave@hiauly1.hia.nrc.ca> | 2002-04-04 02:48:18 +0000 |
---|---|---|
committer | John David Anglin <danglin@gcc.gnu.org> | 2002-04-04 02:48:18 +0000 |
commit | 823fbbce5c867613d9a1417d77970ab0ea5f41b4 (patch) | |
tree | 581f501853359286f80b37739491cd24a96a7357 | |
parent | 4078e2240c57c6d1ad5737de12b724f90d79a612 (diff) | |
download | gcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.zip gcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.tar.gz gcc-823fbbce5c867613d9a1417d77970ab0ea5f41b4.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 41 | ||||
-rw-r--r-- | gcc/config/pa/pa-linux.h | 39 | ||||
-rw-r--r-- | gcc/config/pa/pa.c | 395 | ||||
-rw-r--r-- | gcc/config/pa/pa.h | 16 | ||||
-rw-r--r-- | gcc/config/pa/pa.md | 94 | ||||
-rwxr-xr-x | gcc/configure | 24 | ||||
-rw-r--r-- | gcc/configure.in | 2 |
7 files changed, 428 insertions, 183 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7bec6d5..7446680 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,44 @@ +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. diff --git a/gcc/config/pa/pa-linux.h b/gcc/config/pa/pa-linux.h index f30a187..16599ef 100644 --- a/gcc/config/pa/pa-linux.h +++ b/gcc/config/pa/pa-linux.h @@ -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 diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 16f6533..7890958 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -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 { diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index 5d0955f..1390cae 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -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. diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index aa0c305..ec83b1f 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -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; }") diff --git a/gcc/configure b/gcc/configure index 1270996..0c546ab 100755 --- a/gcc/configure +++ b/gcc/configure @@ -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" diff --git a/gcc/configure.in b/gcc/configure.in index 7abf01b..0e48cb4 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -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*-*-*) |