#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
+#include "except.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
#include "toplev.h"
#include "ggc.h"
#include "recog.h"
+#include "predict.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
#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
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));
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;
}
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;
delta));
}
- if (DO_FRAME_NOTES && reg == STACK_POINTER_REGNUM)
+ if (DO_FRAME_NOTES && note)
RTX_FRAME_RELATED_P (insn) = 1;
}
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])
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;
/* 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. */
{
/* 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,
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
bytes. */
else
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- actual_fsize);
+ actual_fsize, 1);
}
}
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);
/* 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);
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
/* 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)
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.
/* 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)
/* 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);
}
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])
{
{
/* 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)
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
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);
}
/* 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];
- 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
{
[(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)]
""
/* 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);
[(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"))
[(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")
[(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 "" "")
[(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)]
;; 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;
}")