diff options
author | John David Anglin <dave.anglin@nrc-cnrc.gc.ca> | 2003-02-02 06:04:58 +0000 |
---|---|---|
committer | John David Anglin <danglin@gcc.gnu.org> | 2003-02-02 06:04:58 +0000 |
commit | 611ad29eedae3ce061de881cc19bd634220e0fe9 (patch) | |
tree | 6167204bfd21b05f4b23a322640996c4092e1174 /gcc/config/pa/pa.c | |
parent | 8cacda7c8bb67fdaa79d428b2fe95fdf0dd5a2f7 (diff) | |
download | gcc-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.c | 190 |
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 |