aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/pa/pa.c
diff options
context:
space:
mode:
authorJohn David Anglin <dave.anglin@nrc-cnrc.gc.ca>2003-02-02 06:04:58 +0000
committerJohn David Anglin <danglin@gcc.gnu.org>2003-02-02 06:04:58 +0000
commit611ad29eedae3ce061de881cc19bd634220e0fe9 (patch)
tree6167204bfd21b05f4b23a322640996c4092e1174 /gcc/config/pa/pa.c
parent8cacda7c8bb67fdaa79d428b2fe95fdf0dd5a2f7 (diff)
downloadgcc-611ad29eedae3ce061de881cc19bd634220e0fe9.zip
gcc-611ad29eedae3ce061de881cc19bd634220e0fe9.tar.gz
gcc-611ad29eedae3ce061de881cc19bd634220e0fe9.tar.bz2
pa-protos.h (attr_length_millicode_call): Remove second argument.
* pa-protos.h (attr_length_millicode_call): Remove second argument. (attr_length_indirect_call, attr_length_indirect_call, attr_length_save_restore_dltp): New prototypes. * pa.c (attr_length_millicode_call): Remove second argument. Check INSN_ADDRESSES_SET_P in distance calculation. (output_millicode_call): Check INSN_ADDRESSES_SET_P before using INSN_ADDRESSES. (attr_length_call): Check INSN_ADDRESSES_SET_P in distance calculation. (output_call): Check INSN_ADDRESSES_SET_P before using INSN_ADDRESSES. Call attr_length_call directly. (attr_length_indirect_call, output_indirect_call, attr_length_save_restore_dltp): New functions. * pa.md (attr_length_millicode_call): Drop second argument from all patterns. (return_internal_pic): Delete. (return_external_pic): Remove use of PIC register and pic operand and flag checks. (epilogue): Use return_internal for both normal and pic code. (call, call_value): Emit new 32-bit pic patterns for symref and indirect calls. Remove uses for arg pointer and pic register. (call_symref_pic, call_symref_pic_post_reload, call_reg_pic, call_reg_pic_post_reload, call_val_symref_pic, call_val_symref_pic_post_reload, call_val_reg_pic, call_val_reg_pic_post_reload): New pre and post reload insn patterns. Implement define_split and define_peephole2 patterns for pre reload patterns. (call_symref_64bit, call_internal_reg_64bit, call_value_symref_64bit, call_value_internal_reg_64bit): Shorten names. (all call patterns): Explicitly indicate registers used and clobbered. Use attr_length_indirect_call and attr_length_save_restore_dltp for attribute length calculation. Move code generation for indirect calls to output_indirect_call. (sibcall, sibcall_value): Don't restore PIC register. (exception_receiver, builtin_setjmp_receiver): Add blockage after PIC register retore. From-SVN: r62272
Diffstat (limited to 'gcc/config/pa/pa.c')
-rw-r--r--gcc/config/pa/pa.c190
1 files changed, 158 insertions, 32 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index aeccafb..80c86e0 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -1,6 +1,6 @@
/* Subroutines for insn-output.c for HPPA.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002 Free Software Foundation, Inc.
+ 2002, 2003 Free Software Foundation, Inc.
Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
This file is part of GNU CC.
@@ -6279,37 +6279,42 @@ length_fp_args (insn)
return length;
}
-/* We include the delay slot in the returned length as it is better to
+/* Return the attribute length for the millicode call instruction INSN.
+ The length must match the code generated by output_millicode_call.
+ We include the delay slot in the returned length as it is better to
over estimate the length than to under estimate it. */
int
-attr_length_millicode_call (insn, length)
+attr_length_millicode_call (insn)
rtx insn;
- int length;
{
- unsigned long distance = total_code_bytes + INSN_ADDRESSES (INSN_UID (insn));
+ unsigned long distance = -1;
- if (distance < total_code_bytes)
- distance = -1;
+ if (INSN_ADDRESSES_SET_P ())
+ {
+ distance = (total_code_bytes + insn_current_reference_address (insn));
+ if (distance < total_code_bytes)
+ distance = -1;
+ }
if (TARGET_64BIT)
{
if (!TARGET_LONG_CALLS && distance < 7600000)
- return length + 8;
+ return 8;
- return length + 20;
+ return 20;
}
else if (TARGET_PORTABLE_RUNTIME)
- return length + 24;
+ return 24;
else
{
if (!TARGET_LONG_CALLS && distance < 240000)
- return length + 8;
+ return 8;
if (TARGET_LONG_ABS_CALL && !flag_pic)
- return length + 12;
+ return 12;
- return length + 24;
+ return 24;
}
}
@@ -6439,16 +6444,22 @@ output_millicode_call (insn, call_dest)
/* See if the return address can be adjusted. Use the containing
sequence insn's address. */
- seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
- distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
- - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
-
- if (VAL_14_BITS_P (distance))
+ if (INSN_ADDRESSES_SET_P ())
{
- xoperands[1] = gen_label_rtx ();
- output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
- (*targetm.asm_out.internal_label) (asm_out_file, "L",
- CODE_LABEL_NUMBER (xoperands[1]));
+ seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
+ distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
+ - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
+
+ if (VAL_14_BITS_P (distance))
+ {
+ xoperands[1] = gen_label_rtx ();
+ output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
+ (*targetm.asm_out.internal_label) (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xoperands[1]));
+ }
+ else
+ /* ??? This branch may not reach its target. */
+ output_asm_insn ("nop\n\tb,n %0", xoperands);
}
else
/* ??? This branch may not reach its target. */
@@ -6462,18 +6473,25 @@ output_millicode_call (insn, call_dest)
return "";
}
-/* We include the delay slot in the returned length as it is better to
- over estimate the length than to under estimate it. */
+/* Return the attribute length of the call instruction INSN. The SIBCALL
+ flag indicates whether INSN is a regular call or a sibling call. The
+ length must match the code generated by output_call. We include the delay
+ slot in the returned length as it is better to over estimate the length
+ than to under estimate it. */
int
attr_length_call (insn, sibcall)
rtx insn;
int sibcall;
{
- unsigned long distance = total_code_bytes + INSN_ADDRESSES (INSN_UID (insn));
+ unsigned long distance = -1;
- if (distance < total_code_bytes)
- distance = -1;
+ if (INSN_ADDRESSES_SET_P ())
+ {
+ distance = (total_code_bytes + insn_current_reference_address (insn));
+ if (distance < total_code_bytes)
+ distance = -1;
+ }
if (TARGET_64BIT)
{
@@ -6535,7 +6553,6 @@ output_call (insn, call_dest, sibcall)
{
int delay_insn_deleted = 0;
int delay_slot_filled = 0;
- int attr_length = get_attr_length (insn);
int seq_length = dbr_sequence_length ();
rtx xoperands[2];
@@ -6543,9 +6560,7 @@ output_call (insn, call_dest, sibcall)
/* Handle the common case where we're sure that the branch will reach
the beginning of the $CODE$ subspace. */
- if (!TARGET_LONG_CALLS
- && ((seq_length == 0 && attr_length == 12)
- || (seq_length != 0 && attr_length == 8)))
+ if (!TARGET_LONG_CALLS && attr_length_call (insn, sibcall) == 8)
{
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
output_asm_insn ("{bl|b,l} %0,%1", xoperands);
@@ -6773,7 +6788,7 @@ output_call (insn, call_dest, sibcall)
/* This call has an unconditional jump in its delay slot. */
xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
- if (!delay_slot_filled)
+ if (!delay_slot_filled && INSN_ADDRESSES_SET_P ())
{
/* See if the return address can be adjusted. Use the containing
sequence insn's address. */
@@ -6804,6 +6819,117 @@ output_call (insn, call_dest, sibcall)
return "";
}
+/* Return the attribute length of the indirect call instruction INSN.
+ The length must match the code generated by output_indirect call.
+ The returned length includes the delay slot. Currently, the delay
+ slot of an indirect call sequence is not exposed and it is used by
+ the sequence itself. */
+
+int
+attr_length_indirect_call (insn)
+ rtx insn;
+{
+ unsigned long distance = -1;
+
+ if (INSN_ADDRESSES_SET_P ())
+ {
+ distance = (total_code_bytes + insn_current_reference_address (insn));
+ if (distance < total_code_bytes)
+ distance = -1;
+ }
+
+ if (TARGET_64BIT)
+ return 12;
+
+ if (TARGET_FAST_INDIRECT_CALLS
+ || (!TARGET_PORTABLE_RUNTIME
+ && ((TARGET_PA_20 && distance < 7600000) || distance < 240000)))
+ return 8;
+
+ if (flag_pic)
+ return 24;
+
+ if (TARGET_PORTABLE_RUNTIME)
+ return 20;
+
+ /* Out of reach, can use ble. */
+ return 12;
+}
+
+const char *
+output_indirect_call (insn, call_dest)
+ rtx insn;
+ rtx call_dest;
+{
+ rtx xoperands[1];
+
+ if (TARGET_64BIT)
+ {
+ xoperands[0] = call_dest;
+ output_asm_insn ("ldd 16(%0),%%r2", xoperands);
+ output_asm_insn ("bve,l (%%r2),%%r2\n\tldd 24(%0),%%r27", xoperands);
+ return "";
+ }
+
+ /* First the special case for kernels, level 0 systems, etc. */
+ if (TARGET_FAST_INDIRECT_CALLS)
+ return "ble 0(%%sr4,%%r22)\n\tcopy %%r31,%%r2";
+
+ /* Now the normal case -- we can reach $$dyncall directly or
+ we're sure that we can get there via a long-branch stub.
+
+ No need to check target flags as the length uniquely identifies
+ the remaining cases. */
+ if (attr_length_indirect_call (insn) == 8)
+ return ".CALL\tARGW0=GR\n\t{bl|b,l} $$dyncall,%%r31\n\tcopy %%r31,%%r2";
+
+ /* Long millicode call, but we are not generating PIC or portable runtime
+ code. */
+ if (attr_length_indirect_call (insn) == 12)
+ return ".CALL\tARGW0=GR\n\tldil L'$$dyncall,%%r2\n\tble R'$$dyncall(%%sr4,%%r2)\n\tcopy %%r31,%%r2";
+
+ /* Long millicode call for portable runtime. */
+ if (attr_length_indirect_call (insn) == 20)
+ return "ldil L'$$dyncall,%%r31\n\tldo R'$$dyncall(%%r31),%%r31\n\tblr %%r0,%%r2\n\tbv,n %%r0(%%r31)\n\tnop";
+
+ /* We need a long PIC call to $$dyncall. */
+ xoperands[0] = NULL_RTX;
+ output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+ if (TARGET_SOM || !TARGET_GAS)
+ {
+ xoperands[0] = gen_label_rtx ();
+ output_asm_insn ("addil L'$$dyncall-%0,%%r1", xoperands);
+ (*targetm.asm_out.internal_label) (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xoperands[0]));
+ output_asm_insn ("ldo R'$$dyncall-%0(%%r1),%%r1", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("addil L'$$dyncall-$PIC_pcrel$0+4,%%r1", xoperands);
+ output_asm_insn ("ldo R'$$dyncall-$PIC_pcrel$0+8(%%r1),%%r1",
+ xoperands);
+ }
+ output_asm_insn ("blr %%r0,%%r2", xoperands);
+ output_asm_insn ("bv,n %%r0(%%r1)\n\tnop", xoperands);
+ return "";
+}
+
+/* Return the total length of the save and restore instructions needed for
+ the data linkage table pointer (i.e., the PIC register) across the call
+ instruction INSN. No-return calls do not require a save and restore.
+ In addition, we may be able to avoid the save and restore for calls
+ within the same translation unit. */
+
+int
+attr_length_save_restore_dltp (insn)
+ rtx insn;
+{
+ if (find_reg_note (insn, REG_NORETURN, NULL_RTX))
+ return 0;
+
+ return 8;
+}
+
/* In HPUX 8.0's shared library scheme, special relocations are needed
for function labels if they might be passed to a function
in a shared library (because shared libraries don't live in code