long-double.h (FIX_TRUNCTFSI2_LIBCALL): Tweak for PA64.
* pa/long-double.h (FIX_TRUNCTFSI2_LIBCALL): Tweak for PA64. * pa/pa-protos.h (output_call): Add additional argument indicating if the call is a sibling/tail call. (compute_zdepdi_operands, output_64bit_and): Prototype new functions. (compute_64bit_ior, cmpib_comparison_operator): Likewise. (function_arg, function_arg_partial_nregs): Likewise * pa/pa.c (override_options): Always set flag_pic for TARGET_64BIT. (emit_move_sequence): Zero extend certain constants as needed for TARGET_64BIT. (compute_zdepdi_operands, output_64bit_and): New functions. (output_64bit_ior, function_arg): Likewise. (cmpib_comparison_operator, function_arg_partial_nregs): Likewise. (compute_frame_size, hppa_expand_prologue): Handle TARGET_64BIT. (hppa_expand_epilogue, return_addr_rtx, hppa_va_arg): Likewise. (hppa_builtin_saveregs, output_cbranch, output_bb): Likewise. (output_bvb): Likewise. (output_millicode_call): Return pointer is in %r2 for TARGET_64BIT. (output_call): New argument 'sibcall'. Generate sibcall sequences as needed. (print_operand); Handle cases 'Q', 'p', and 'z' for TARGET_64BIT. For (ouput_arg_descriptor): Do not emit argument descriptors for TARGET_64BIT. * pa/pa.h (TARGET_PA_11, TARGET_PA_20): Only define if not already defined. (TARGET_64BIT, PROMOTE_FUNCTION_RETURN): Define. (FUNCTION_OK_FOR_SIBALL): Define. (CPP_PA10_SPEC, CPP_PA11_SPEC, CPP_PA20_SPEC): Define. (CPP_CPU_DEFAULT_SPEC, SUBTARGET_EXTRA_SPECS, EXTRA_SPECS): Likewise. (CPP_SPEC): Use new spec infrastructure. (BITS_PER_WORD, UNITS_PER_WORD): Handle TARGET_64BIT. (STACK_BOUNDARY, FUNCTION_BOUNDARY, PIC_OFFSET_TABLE_REGNUM): Likewise. (RETURN_IN_MEMORY, EXTRA_CONSTRAINT, FIRST_PARM_OFFSET): Likewise. (REG_PARM_STACK_SPACE, STACK_POINTER_OFFSET): Likewise. (STACK_DYNAMIC_OFFSET, FUNCTION_VALUE): Likewise. (FUNCTION_ARG_PASS_BY_REFERENCE, FUNCTION_ARG_CALLEE_COPIES): Likewise. (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE): Likewise. (INITIALIZE_TRAMPOLINE, LEGITIMATE_CONSTANT_P): Likewise. (CONST_OK_FOR_LETTER_P, MOVE_RATIO): Likewise. (FUNCTION_ARG); Call out to C code. (FUNCTION_ARG_PARTIAL_NREGS): Likewise. (MAX_BITS_PER_WORD, MAX_LONG_TYPE_SIZE, MAX_WCHAR_TYPE_SIZE): Define. (MIN_UNITS_PER_WORD): Likewise. * pa/pa.md (cmpdi): New expander. (scc patterns, movstrsi): Not available for TARGET_64BIT. (64bit conditional arithmetic): New patterns. (absdi2, smindi3, umindi3, smaxdi3, umaxdi3): New patterns. (movsicc): Not available if modes on all the operands to not match. (movdicc): New expander and associated patterns. (64bit branches): New patterns. (pre_load, post_store): Generate appropriate code for TARGET_64BIT. (pre_ldd, post_std): New patterns. (64bit addil, load low part): New patterns. (special movsf constant): Not available for TARGET_64BIT. (movsf, movdf expanders): Force constants into memory. (32bit movdf/movdi patterns): Disable for TARGET_64BIT. (64bit movdf/movdi patterns): New patterns. (zero_extendqidi2, zero_extendhidi2, zero_extendsidi2): New patterns for TARGET_64BIT. (extendqidi2, extendhidi2, extendsidi2): Similarly. (adddi3 expander): Allow "arith_operand" for second input. (32bit adddi3, subdi3, uaddcm): Disable for TARGET_64BIT. (64bit adddi3, subsi3, uaddcm): New patterns for TARGET_64BIT. (mulsi3 expander): Revamp slightly so it supports TARGET_64BIT too. (muldi3): New expander for TARGET_64BIT. (divsi3, udivsi3, modsi3, umodsi3): Fourth operand must be (reg:SI 2) for TARGET_64BIT. (32bit anddi3, iordi3, xordi3, andcm, negdi2, uaddcm): Disable patterns for TARGET_64BIT. (64bit anddi3, iordi3, xordi3, andcm, negdi2, uaddcm, shadd): New patterns for TARGET_64BIT. (64bit bit insertion/extractions): New patterns for TARGET_64BIT. (64bit shifts/rotates): New patterns/expanders for TARGET_64BIT. (sibcall_epilogue): New expander. (casesi): Tweak for TARGET_64BIT. (call expanders): Set & use the outgoing argument pointer. Use the 64bit call patterns as needed. Add additional arg to output_call. (call_internal_reg_64bit, call_value_internal_reg_64bit): New pattern. (sibcall, sibcall_internal_symref): New expanders. (sibcall_value, sibcall_value_internal_symref (interspace_jump): Turn into an expander + matching patterns. (canonicalize_funcptr_for_compare): Not needed for TARGET_64BIT. * pa/pa64-regs.h: Eliminate trigraph sequences. * pa/pa64-start.h (TARGET_PA_20): Fix typo. From-SVN: r33082
This commit is contained in:
parent
cba6a0b29f
commit
520babc783
8 changed files with 2480 additions and 208 deletions
|
@ -1,3 +1,89 @@
|
|||
Tue Apr 11 09:55:59 2000 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* pa/long-double.h (FIX_TRUNCTFSI2_LIBCALL): Tweak for PA64.
|
||||
* pa/pa-protos.h (output_call): Add additional argument indicating
|
||||
if the call is a sibling/tail call.
|
||||
(compute_zdepdi_operands, output_64bit_and): Prototype new functions.
|
||||
(compute_64bit_ior, cmpib_comparison_operator): Likewise.
|
||||
(function_arg, function_arg_partial_nregs): Likewise
|
||||
* pa/pa.c (override_options): Always set flag_pic for TARGET_64BIT.
|
||||
(emit_move_sequence): Zero extend certain constants as needed
|
||||
for TARGET_64BIT.
|
||||
(compute_zdepdi_operands, output_64bit_and): New functions.
|
||||
(output_64bit_ior, function_arg): Likewise.
|
||||
(cmpib_comparison_operator, function_arg_partial_nregs): Likewise.
|
||||
(compute_frame_size, hppa_expand_prologue): Handle TARGET_64BIT.
|
||||
(hppa_expand_epilogue, return_addr_rtx, hppa_va_arg): Likewise.
|
||||
(hppa_builtin_saveregs, output_cbranch, output_bb): Likewise.
|
||||
(output_bvb): Likewise.
|
||||
(output_millicode_call): Return pointer is in %r2 for TARGET_64BIT.
|
||||
(output_call): New argument 'sibcall'. Generate sibcall sequences
|
||||
as needed.
|
||||
(print_operand); Handle cases 'Q', 'p', and 'z' for TARGET_64BIT. For
|
||||
(ouput_arg_descriptor): Do not emit argument descriptors for
|
||||
TARGET_64BIT.
|
||||
* pa/pa.h (TARGET_PA_11, TARGET_PA_20): Only define if not already
|
||||
defined.
|
||||
(TARGET_64BIT, PROMOTE_FUNCTION_RETURN): Define.
|
||||
(FUNCTION_OK_FOR_SIBALL): Define.
|
||||
(CPP_PA10_SPEC, CPP_PA11_SPEC, CPP_PA20_SPEC): Define.
|
||||
(CPP_CPU_DEFAULT_SPEC, SUBTARGET_EXTRA_SPECS, EXTRA_SPECS): Likewise.
|
||||
(CPP_SPEC): Use new spec infrastructure.
|
||||
(BITS_PER_WORD, UNITS_PER_WORD): Handle TARGET_64BIT.
|
||||
(STACK_BOUNDARY, FUNCTION_BOUNDARY, PIC_OFFSET_TABLE_REGNUM): Likewise.
|
||||
(RETURN_IN_MEMORY, EXTRA_CONSTRAINT, FIRST_PARM_OFFSET): Likewise.
|
||||
(REG_PARM_STACK_SPACE, STACK_POINTER_OFFSET): Likewise.
|
||||
(STACK_DYNAMIC_OFFSET, FUNCTION_VALUE): Likewise.
|
||||
(FUNCTION_ARG_PASS_BY_REFERENCE, FUNCTION_ARG_CALLEE_COPIES): Likewise.
|
||||
(TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE): Likewise.
|
||||
(INITIALIZE_TRAMPOLINE, LEGITIMATE_CONSTANT_P): Likewise.
|
||||
(CONST_OK_FOR_LETTER_P, MOVE_RATIO): Likewise.
|
||||
(FUNCTION_ARG); Call out to C code.
|
||||
(FUNCTION_ARG_PARTIAL_NREGS): Likewise.
|
||||
(MAX_BITS_PER_WORD, MAX_LONG_TYPE_SIZE, MAX_WCHAR_TYPE_SIZE): Define.
|
||||
(MIN_UNITS_PER_WORD): Likewise.
|
||||
* pa/pa.md (cmpdi): New expander.
|
||||
(scc patterns, movstrsi): Not available for TARGET_64BIT.
|
||||
(64bit conditional arithmetic): New patterns.
|
||||
(absdi2, smindi3, umindi3, smaxdi3, umaxdi3): New patterns.
|
||||
(movsicc): Not available if modes on all the operands to not match.
|
||||
(movdicc): New expander and associated patterns.
|
||||
(64bit branches): New patterns.
|
||||
(pre_load, post_store): Generate appropriate code for TARGET_64BIT.
|
||||
(pre_ldd, post_std): New patterns.
|
||||
(64bit addil, load low part): New patterns.
|
||||
(special movsf constant): Not available for TARGET_64BIT.
|
||||
(movsf, movdf expanders): Force constants into memory.
|
||||
(32bit movdf/movdi patterns): Disable for TARGET_64BIT.
|
||||
(64bit movdf/movdi patterns): New patterns.
|
||||
(zero_extendqidi2, zero_extendhidi2, zero_extendsidi2): New patterns
|
||||
for TARGET_64BIT.
|
||||
(extendqidi2, extendhidi2, extendsidi2): Similarly.
|
||||
(adddi3 expander): Allow "arith_operand" for second input.
|
||||
(32bit adddi3, subdi3, uaddcm): Disable for TARGET_64BIT.
|
||||
(64bit adddi3, subsi3, uaddcm): New patterns for TARGET_64BIT.
|
||||
(mulsi3 expander): Revamp slightly so it supports TARGET_64BIT too.
|
||||
(muldi3): New expander for TARGET_64BIT.
|
||||
(divsi3, udivsi3, modsi3, umodsi3): Fourth operand must be (reg:SI 2)
|
||||
for TARGET_64BIT.
|
||||
(32bit anddi3, iordi3, xordi3, andcm, negdi2, uaddcm): Disable
|
||||
patterns for TARGET_64BIT.
|
||||
(64bit anddi3, iordi3, xordi3, andcm, negdi2, uaddcm, shadd): New
|
||||
patterns for TARGET_64BIT.
|
||||
(64bit bit insertion/extractions): New patterns for TARGET_64BIT.
|
||||
(64bit shifts/rotates): New patterns/expanders for TARGET_64BIT.
|
||||
(sibcall_epilogue): New expander.
|
||||
(casesi): Tweak for TARGET_64BIT.
|
||||
(call expanders): Set & use the outgoing argument pointer. Use the
|
||||
64bit call patterns as needed. Add additional arg to output_call.
|
||||
(call_internal_reg_64bit, call_value_internal_reg_64bit): New pattern.
|
||||
(sibcall, sibcall_internal_symref): New expanders.
|
||||
(sibcall_value, sibcall_value_internal_symref
|
||||
(interspace_jump): Turn into an expander + matching patterns.
|
||||
(canonicalize_funcptr_for_compare): Not needed for TARGET_64BIT.
|
||||
* pa/pa64-regs.h: Eliminate trigraph sequences.
|
||||
* pa/pa64-start.h (TARGET_PA_20): Fix typo.
|
||||
|
||||
2000-04-11 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* cppexp.c, cpphash.c, cpphash.h, cpplex.c, cpplib.c,
|
||||
|
|
|
@ -48,7 +48,10 @@ do { long value[4]; \
|
|||
#define TRUNCTFDF2_LIBCALL "_U_Qfcnvff_quad_to_dbl"
|
||||
#define FLOATSITF2_LIBCALL "_U_Qfcnvxf_sgl_to_quad"
|
||||
#define FLOATDITF2_LIBCALL "_U_Qfcnvxf_dbl_to_quad"
|
||||
#define FIX_TRUNCTFSI2_LIBCALL "_U_Qfcnvfxt_quad_to_sgl"
|
||||
/* We need to put a wrapper function around _U_Qfcnvfxt_quad_to_sgl so that
|
||||
we can massage its return value for PA64. */
|
||||
#define FIX_TRUNCTFSI2_LIBCALL \
|
||||
(TARGET_64BIT ? "__U_Qfcnvfxt_quad_to_sgl" : "_U_Qfcnvfxt_quad_to_sgl")
|
||||
#define FIX_TRUNCTFDI2_LIBCALL "_U_Qfcnvfxt_quad_to_dbl"
|
||||
#define EQTF2_LIBCALL "_U_Qfeq"
|
||||
#define NETF2_LIBCALL "_U_Qfne"
|
||||
|
|
|
@ -50,7 +50,7 @@ extern const char *output_dbra PARAMS ((rtx *, rtx, int));
|
|||
extern const char *output_movb PARAMS ((rtx *, rtx, int, int));
|
||||
extern const char *output_parallel_movb PARAMS ((rtx *, int));
|
||||
extern const char *output_parallel_addb PARAMS ((rtx *, int));
|
||||
extern const char *output_call PARAMS ((rtx, rtx));
|
||||
extern const char *output_call PARAMS ((rtx, rtx, int));
|
||||
extern const char *output_millicode_call PARAMS ((rtx, rtx));
|
||||
extern const char *output_mul_insn PARAMS ((int, rtx));
|
||||
extern const char *output_div_insn PARAMS ((rtx *, int, rtx));
|
||||
|
@ -141,7 +141,23 @@ extern void hppa_expand_prologue PARAMS ((void));
|
|||
extern void hppa_expand_epilogue PARAMS ((void));
|
||||
extern int hppa_can_use_return_insn_p PARAMS ((void));
|
||||
extern int ior_mask_p PARAMS ((unsigned HOST_WIDE_INT));
|
||||
extern void compute_zdepdi_operands PARAMS ((unsigned HOST_WIDE_INT,
|
||||
unsigned *));
|
||||
#ifdef RTX_CODE
|
||||
extern char * output_64bit_and PARAMS ((rtx *));
|
||||
extern char * output_64bit_ior PARAMS ((rtx *));
|
||||
extern int cmpib_comparison_operator PARAMS ((rtx, enum machine_mode));
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef TREE_CODE
|
||||
extern int reloc_needed PARAMS ((tree));
|
||||
#ifdef RTX_CODE
|
||||
extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode,
|
||||
tree, int, int));
|
||||
#endif
|
||||
extern int function_arg_partial_nregs PARAMS ((CUMULATIVE_ARGS *,
|
||||
enum machine_mode,
|
||||
tree, int));
|
||||
#endif /* TREE_CODE */
|
||||
|
|
|
@ -189,6 +189,10 @@ override_options ()
|
|||
write_symbols = NO_DEBUG;
|
||||
}
|
||||
|
||||
/* We always generate PIC code when in 64bit mode. */
|
||||
if (TARGET_64BIT)
|
||||
flag_pic = 2;
|
||||
|
||||
/* Register global variables with the garbage collector. */
|
||||
pa_add_gc_roots ();
|
||||
}
|
||||
|
@ -1562,6 +1566,25 @@ emit_move_sequence (operands, mode, scratch_reg)
|
|||
|| ! cint_ok_for_move (INTVAL (operand1)))
|
||||
{
|
||||
rtx temp;
|
||||
int need_zero_extend = 0;
|
||||
|
||||
if (TARGET_64BIT && GET_CODE (operand1) == CONST_INT
|
||||
&& GET_MODE_BITSIZE (GET_MODE (operand0)) > 32)
|
||||
{
|
||||
HOST_WIDE_INT val = INTVAL (operand1);
|
||||
HOST_WIDE_INT nval = INTVAL (operand1);
|
||||
|
||||
/* If the value is the same after a 32->64bit sign
|
||||
extension, then we can use it as-is. Else we will
|
||||
need to sign extend the constant from 32->64bits
|
||||
then zero extend the result from 32->64bits. */
|
||||
nval = ((val & 0xffffffff) ^ (~0x7fffffff)) + 0x80000000;
|
||||
if (val != nval)
|
||||
{
|
||||
need_zero_extend = 1;
|
||||
operand1 = GEN_INT (nval);
|
||||
}
|
||||
}
|
||||
|
||||
if (reload_in_progress || reload_completed)
|
||||
temp = operand0;
|
||||
|
@ -1571,6 +1594,17 @@ emit_move_sequence (operands, mode, scratch_reg)
|
|||
emit_insn (gen_rtx_SET (VOIDmode, temp,
|
||||
gen_rtx_HIGH (mode, operand1)));
|
||||
operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
|
||||
emit_move_insn (operands[0], operands[1]);
|
||||
|
||||
if (need_zero_extend)
|
||||
{
|
||||
emit_insn (gen_zero_extendsidi2 (operands[0],
|
||||
gen_rtx_SUBREG (SImode,
|
||||
operands[0],
|
||||
0)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Now have insn-emit do whatever it normally does. */
|
||||
|
@ -1729,6 +1763,46 @@ compute_zdepwi_operands (imm, op)
|
|||
op[2] = len;
|
||||
}
|
||||
|
||||
/* Compute position (in OP[1]) and width (in OP[2])
|
||||
useful for copying IMM to a register using the depdi,z
|
||||
instructions. Store the immediate value to insert in OP[0]. */
|
||||
void
|
||||
compute_zdepdi_operands (imm, op)
|
||||
unsigned HOST_WIDE_INT imm;
|
||||
unsigned *op;
|
||||
{
|
||||
HOST_WIDE_INT lsb, len;
|
||||
|
||||
/* Find the least significant set bit in IMM. */
|
||||
for (lsb = 0; lsb < HOST_BITS_PER_WIDE_INT; lsb++)
|
||||
{
|
||||
if ((imm & 1) != 0)
|
||||
break;
|
||||
imm >>= 1;
|
||||
}
|
||||
|
||||
/* Choose variants based on *sign* of the 5-bit field. */
|
||||
if ((imm & 0x10) == 0)
|
||||
len = ((lsb <= HOST_BITS_PER_WIDE_INT - 4)
|
||||
? 4 : HOST_BITS_PER_WIDE_INT - lsb);
|
||||
else
|
||||
{
|
||||
/* Find the width of the bitstring in IMM. */
|
||||
for (len = 5; len < HOST_BITS_PER_WIDE_INT; len++)
|
||||
{
|
||||
if ((imm & ((unsigned HOST_WIDE_INT)1 << len)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sign extend IMM as a 5-bit value. */
|
||||
imm = (imm & 0xf) - 0x10;
|
||||
}
|
||||
|
||||
op[0] = imm;
|
||||
op[1] = 63 - lsb;
|
||||
op[2] = len;
|
||||
}
|
||||
|
||||
/* Output assembler code to perform a doubleword move insn
|
||||
with operands OPERANDS. */
|
||||
|
||||
|
@ -2264,6 +2338,59 @@ output_and (operands)
|
|||
return "and %1,%2,%0";
|
||||
}
|
||||
|
||||
/* Return a string to perform a bitwise-and of operands[1] with operands[2]
|
||||
storing the result in operands[0]. */
|
||||
char *
|
||||
output_64bit_and (operands)
|
||||
rtx *operands;
|
||||
{
|
||||
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
|
||||
unsigned HOST_WIDE_INT ls0, ls1, ms0, p, len;
|
||||
|
||||
for (ls0 = 0; ls0 < HOST_BITS_PER_WIDE_INT; ls0++)
|
||||
if ((mask & ((unsigned HOST_WIDE_INT)1 << ls0)) == 0)
|
||||
break;
|
||||
|
||||
for (ls1 = ls0; ls1 < HOST_BITS_PER_WIDE_INT; ls1++)
|
||||
if ((mask & ((unsigned HOST_WIDE_INT)1 << ls1)) != 0)
|
||||
break;
|
||||
|
||||
for (ms0 = ls1; ms0 < HOST_BITS_PER_WIDE_INT; ms0++)
|
||||
if ((mask & ((unsigned HOST_WIDE_INT)1 << ms0)) == 0)
|
||||
break;
|
||||
|
||||
if (ms0 != HOST_BITS_PER_WIDE_INT)
|
||||
abort();
|
||||
|
||||
if (ls1 == HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
len = ls0;
|
||||
|
||||
if (len == 0)
|
||||
abort ();
|
||||
|
||||
operands[2] = GEN_INT (len);
|
||||
return "extrd,u %1,63,%2,%0";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We could use this `depi' for the case above as well, but `depi'
|
||||
requires one more register file access than an `extru'. */
|
||||
|
||||
p = 63 - ls0;
|
||||
len = ls1 - ls0;
|
||||
|
||||
operands[2] = GEN_INT (p);
|
||||
operands[3] = GEN_INT (len);
|
||||
return "depdi 0,%2,%3,%0";
|
||||
}
|
||||
}
|
||||
else
|
||||
return "and %1,%2,%0";
|
||||
}
|
||||
|
||||
const char *
|
||||
output_ior (operands)
|
||||
rtx *operands;
|
||||
|
@ -2292,6 +2419,38 @@ output_ior (operands)
|
|||
operands[3] = GEN_INT (len);
|
||||
return "{depi|depwi} -1,%2,%3,%0";
|
||||
}
|
||||
|
||||
/* Return a string to perform a bitwise-and of operands[1] with operands[2]
|
||||
storing the result in operands[0]. */
|
||||
char *
|
||||
output_64bit_ior (operands)
|
||||
rtx *operands;
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
|
||||
unsigned HOST_WIDE_INT bs0, bs1, p, len;
|
||||
|
||||
if (INTVAL (operands[2]) == 0)
|
||||
return "copy %1,%0";
|
||||
|
||||
for (bs0 = 0; bs0 < HOST_BITS_PER_WIDE_INT; bs0++)
|
||||
if ((mask & ((unsigned HOST_WIDE_INT)1 << bs0)) != 0)
|
||||
break;
|
||||
|
||||
for (bs1 = bs0; bs1 < HOST_BITS_PER_WIDE_INT; bs1++)
|
||||
if ((mask & ((unsigned HOST_WIDE_INT)1 << bs1)) == 0)
|
||||
break;
|
||||
|
||||
if (bs1 != HOST_BITS_PER_WIDE_INT
|
||||
&& ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask)
|
||||
abort();
|
||||
|
||||
p = 63 - bs0;
|
||||
len = bs1 - bs0;
|
||||
|
||||
operands[2] = GEN_INT (p);
|
||||
operands[3] = GEN_INT (len);
|
||||
return "depdi -1,%2,%3,%0";
|
||||
}
|
||||
|
||||
/* Output an ascii string. */
|
||||
void
|
||||
|
@ -2676,7 +2835,8 @@ compute_frame_size (size, fregs_live)
|
|||
|
||||
/* Account for space used by the callee floating point register saves. */
|
||||
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
|
||||
if (regs_ever_live[i] || regs_ever_live[i + 1])
|
||||
if (regs_ever_live[i]
|
||||
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
|
||||
{
|
||||
if (fregs_live)
|
||||
*fregs_live = 1;
|
||||
|
@ -2693,8 +2853,9 @@ compute_frame_size (size, fregs_live)
|
|||
/* Allocate space for the fixed frame marker. This space must be
|
||||
allocated for any function that makes calls or otherwise allocates
|
||||
stack space. */
|
||||
if (! leaf_function_p () || fsize)
|
||||
if (!current_function_is_leaf || fsize)
|
||||
fsize += 32;
|
||||
|
||||
return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
|
||||
}
|
||||
|
||||
|
@ -2796,8 +2957,12 @@ hppa_expand_prologue()
|
|||
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. */
|
||||
if (regs_ever_live[2] || profile_flag)
|
||||
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] || profile_flag) && TARGET_64BIT)
|
||||
store_reg (2, -16, STACK_POINTER_REGNUM);
|
||||
|
||||
if ((regs_ever_live[2] || profile_flag) && ! TARGET_64BIT)
|
||||
store_reg (2, -20, STACK_POINTER_REGNUM);
|
||||
|
||||
/* Allocate the local frame and set up the frame pointer if needed. */
|
||||
|
@ -2856,7 +3021,7 @@ hppa_expand_prologue()
|
|||
for functions which make no calls and allocate no frame? Do
|
||||
we need to allocate a frame, or can we just omit the save? For
|
||||
now we'll just omit the save. */
|
||||
if (actual_fsize != 0 && flag_pic)
|
||||
if (actual_fsize != 0 && flag_pic && !TARGET_64BIT)
|
||||
store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM);
|
||||
|
||||
/* Profiling code.
|
||||
|
@ -2982,7 +3147,8 @@ hppa_expand_prologue()
|
|||
/* Now actually save the FP registers. */
|
||||
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
|
||||
{
|
||||
if (regs_ever_live[i] || regs_ever_live[i + 1])
|
||||
if (regs_ever_live[i]
|
||||
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
|
||||
{
|
||||
emit_move_insn (gen_rtx_MEM (DFmode,
|
||||
gen_rtx_POST_INC (DFmode, tmpreg)),
|
||||
|
@ -3066,9 +3232,17 @@ hppa_expand_epilogue ()
|
|||
RP gets used in the return (bv) instruction. This appears to still
|
||||
be necessary even when we schedule the prologue and epilogue. */
|
||||
if (frame_pointer_needed
|
||||
&& !TARGET_64BIT
|
||||
&& (regs_ever_live [2] || profile_flag))
|
||||
load_reg (2, -20, FRAME_POINTER_REGNUM);
|
||||
|
||||
else if (TARGET_64BIT && frame_pointer_needed
|
||||
&& (regs_ever_live[2] || profile_flag))
|
||||
load_reg (2, -16, FRAME_POINTER_REGNUM);
|
||||
else if (TARGET_64BIT
|
||||
&& ! frame_pointer_needed
|
||||
&& (regs_ever_live[2] || profile_flag)
|
||||
&& VAL_14_BITS_P (actual_fsize + 20))
|
||||
load_reg (2, - (actual_fsize + 16), STACK_POINTER_REGNUM);
|
||||
/* No frame pointer, and stack is smaller than 8k. */
|
||||
else if (! frame_pointer_needed
|
||||
&& VAL_14_BITS_P (actual_fsize + 20)
|
||||
|
@ -3120,7 +3294,8 @@ hppa_expand_epilogue ()
|
|||
/* Actually do the restores now. */
|
||||
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
|
||||
{
|
||||
if (regs_ever_live[i] || regs_ever_live[i + 1])
|
||||
if (regs_ever_live[i]
|
||||
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
|
||||
{
|
||||
emit_move_insn (gen_rtx_REG (DFmode, i),
|
||||
gen_rtx_MEM (DFmode,
|
||||
|
@ -3140,6 +3315,7 @@ hppa_expand_epilogue ()
|
|||
as possible.) */
|
||||
if (! frame_pointer_needed
|
||||
&& ! VAL_14_BITS_P (actual_fsize + 20)
|
||||
&& ! TARGET_64BIT
|
||||
&& (regs_ever_live[2] || profile_flag))
|
||||
{
|
||||
set_reg_plus_d (STACK_POINTER_REGNUM,
|
||||
|
@ -3154,6 +3330,23 @@ hppa_expand_epilogue ()
|
|||
doesn't set %r1, just %r30. */
|
||||
load_reg (2, - 20, STACK_POINTER_REGNUM);
|
||||
}
|
||||
else if (! frame_pointer_needed
|
||||
&& ! VAL_14_BITS_P (actual_fsize + 20)
|
||||
&& TARGET_64BIT
|
||||
&& (regs_ever_live[2] || profile_flag))
|
||||
{
|
||||
set_reg_plus_d (STACK_POINTER_REGNUM,
|
||||
STACK_POINTER_REGNUM,
|
||||
- actual_fsize);
|
||||
|
||||
/* This used to try and be clever by not depending on the value in
|
||||
%r30 and instead use the value held in %r1 (so that the 2nd insn
|
||||
which sets %r30 could be put in the delay slot of the return insn).
|
||||
|
||||
That won't work since if the stack is exactly 8k set_reg_plus_d
|
||||
doesn't set %r1, just %r30. */
|
||||
load_reg (2, - 16, STACK_POINTER_REGNUM);
|
||||
}
|
||||
|
||||
/* Reset stack pointer (and possibly frame pointer). The stack
|
||||
pointer is initially set to fp + 64 to avoid a race condition. */
|
||||
|
@ -3216,7 +3409,10 @@ return_addr_rtx (count, frameaddr)
|
|||
/* First, we start off with the normal return address pointer from
|
||||
-20[frameaddr]. */
|
||||
|
||||
emit_move_insn (saved_rp, plus_constant (frameaddr, -5 * UNITS_PER_WORD));
|
||||
if (TARGET_64BIT)
|
||||
return gen_rtx_MEM (Pmode, plus_constant (frameaddr, -16));
|
||||
else
|
||||
emit_move_insn (saved_rp, plus_constant (frameaddr, -5 * UNITS_PER_WORD));
|
||||
|
||||
/* Get pointer to the instruction stream. We have to mask out the
|
||||
privilege level from the two low order bits of the return address
|
||||
|
@ -3824,6 +4020,13 @@ print_operand (file, x, code)
|
|||
return;
|
||||
}
|
||||
abort();
|
||||
case 'Q':
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
{
|
||||
fprintf (file, "%d", 64 - (INTVAL (x) & 63));
|
||||
return;
|
||||
}
|
||||
abort();
|
||||
case 'L':
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
{
|
||||
|
@ -3838,6 +4041,13 @@ print_operand (file, x, code)
|
|||
return;
|
||||
}
|
||||
abort();
|
||||
case 'p':
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
{
|
||||
fprintf (file, "%d", 63 - (INTVAL (x) & 63));
|
||||
return;
|
||||
}
|
||||
abort();
|
||||
case 'P':
|
||||
if (GET_CODE (x) == CONST_INT)
|
||||
{
|
||||
|
@ -3900,13 +4110,27 @@ print_operand (file, x, code)
|
|||
fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
|
||||
return;
|
||||
}
|
||||
case 'z':
|
||||
{
|
||||
unsigned op[3];
|
||||
compute_zdepdi_operands (INTVAL (x), op);
|
||||
fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
if (GET_CODE (x) == REG)
|
||||
{
|
||||
fputs (reg_names [REGNO (x)], file);
|
||||
if (FP_REG_P (x) && GET_MODE_SIZE (GET_MODE (x)) <= 4 && (REGNO (x) & 1) == 0)
|
||||
if (TARGET_64BIT && FP_REG_P (x) && GET_MODE_SIZE (GET_MODE (x)) <= 4)
|
||||
{
|
||||
fputs ("R", file);
|
||||
return;
|
||||
}
|
||||
if (FP_REG_P (x)
|
||||
&& GET_MODE_SIZE (GET_MODE (x)) <= 4
|
||||
&& (REGNO (x) & 1) == 0)
|
||||
fputs ("L", file);
|
||||
}
|
||||
else if (GET_CODE (x) == MEM)
|
||||
|
@ -3917,12 +4141,12 @@ print_operand (file, x, code)
|
|||
{
|
||||
case PRE_DEC:
|
||||
case POST_DEC:
|
||||
base = XEXP (XEXP (x, 0), 0);
|
||||
base = XEXP (XEXP (x, 0), 0);
|
||||
fprintf (file, "-%d(%s)", size, reg_names [REGNO (base)]);
|
||||
break;
|
||||
case PRE_INC:
|
||||
case POST_INC:
|
||||
base = XEXP (XEXP (x, 0), 0);
|
||||
base = XEXP (XEXP (x, 0), 0);
|
||||
fprintf (file, "%d(%s)", size, reg_names [REGNO (base)]);
|
||||
break;
|
||||
default:
|
||||
|
@ -4221,6 +4445,11 @@ output_arg_descriptor (call_insn)
|
|||
int i, output_flag = 0;
|
||||
int regno;
|
||||
|
||||
/* We neither need nor want argument location descriptors for the
|
||||
64bit runtime environment. */
|
||||
if (TARGET_64BIT)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
arg_regs[i] = 0;
|
||||
|
||||
|
@ -4420,6 +4649,36 @@ hppa_builtin_saveregs ()
|
|||
else
|
||||
offset = current_function_arg_offset_rtx;
|
||||
|
||||
if (TARGET_64BIT)
|
||||
{
|
||||
int i, off;
|
||||
|
||||
/* Adjust for varargs/stdarg differences. */
|
||||
if (argadj)
|
||||
offset = plus_constant (current_function_arg_offset_rtx, -argadj);
|
||||
else
|
||||
offset = current_function_arg_offset_rtx;
|
||||
|
||||
/* We need to save %r26 .. %r19 inclusive starting at offset -64
|
||||
from the incoming arg pointer and growing to larger addresses. */
|
||||
for (i = 26, off = -64; i >= 19; i--, off += 8)
|
||||
emit_move_insn (gen_rtx_MEM (word_mode,
|
||||
plus_constant (arg_pointer_rtx, off)),
|
||||
gen_rtx_REG (word_mode, i));
|
||||
|
||||
/* The incoming args pointer points just beyond the flushback area;
|
||||
normally this is not a serious concern. Howver, when we are doing
|
||||
varargs/stdargs we want to make the arg pointer point to the start
|
||||
of the incoming argument area. */
|
||||
emit_move_insn (virtual_incoming_args_rtx,
|
||||
plus_constant (arg_pointer_rtx, -64));
|
||||
|
||||
/* Now return a pointer to the first anonymous argument. */
|
||||
return copy_to_reg (expand_binop (Pmode, add_optab,
|
||||
virtual_incoming_args_rtx,
|
||||
offset, 0, 0, OPTAB_LIB_WIDEN));
|
||||
}
|
||||
|
||||
/* Store general registers on the stack. */
|
||||
dest = gen_rtx_MEM (BLKmode,
|
||||
plus_constant (current_function_internal_arg_pointer,
|
||||
|
@ -4467,6 +4726,25 @@ hppa_va_arg (valist, type)
|
|||
HOST_WIDE_INT align, size, ofs;
|
||||
tree t, ptr, pptr;
|
||||
|
||||
if (TARGET_64BIT)
|
||||
{
|
||||
/* Every argument in PA64 is passed by value (including large structs).
|
||||
Arguments with size greater than 8 must be aligned 0 MOD 16. */
|
||||
|
||||
size = int_size_in_bytes (type);
|
||||
if (size > UNITS_PER_WORD)
|
||||
{
|
||||
t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
|
||||
build_int_2 (2 * UNITS_PER_WORD - 1, 0));
|
||||
t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
|
||||
build_int_2 (-2 * UNITS_PER_WORD, -1));
|
||||
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
|
||||
}
|
||||
return std_expand_builtin_va_arg (valist, type);
|
||||
}
|
||||
|
||||
/* Compute the rounded size of the type. */
|
||||
align = PARM_BOUNDARY / BITS_PER_UNIT;
|
||||
size = int_size_in_bytes (type);
|
||||
|
@ -4570,6 +4848,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
||||
else
|
||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if (negated)
|
||||
strcat (buf, "%B3");
|
||||
else
|
||||
|
@ -4593,6 +4873,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
&& nullify)
|
||||
{
|
||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if (negated)
|
||||
strcat (buf, "%S3");
|
||||
else
|
||||
|
@ -4609,6 +4891,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
- insn_addresses[INSN_UID (insn)] - 8))
|
||||
{
|
||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if (negated)
|
||||
strcat (buf, "%B3 %2,%r1,%0%#");
|
||||
else
|
||||
|
@ -4617,6 +4901,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
else
|
||||
{
|
||||
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if (negated)
|
||||
strcat (buf, "%S3");
|
||||
else
|
||||
|
@ -4640,6 +4926,15 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+20|cmp%I2b,%S3,n %2,%r1,.+20}");
|
||||
else
|
||||
strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+20|cmp%I2b,%B3,n %2,%r1,.+20}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
{
|
||||
if (negated)
|
||||
strcpy (buf,
|
||||
"{com%I2b,*%S3,n %2,%r1,.+20|cmp%I2b,*%S3,n %2,%r1,.+20}");
|
||||
else
|
||||
strcpy (buf,
|
||||
"{com%I2b,*%B3,n %2,%r1,.+20|cmp%I2b,*%B3,n %2,%r1,.+20}");
|
||||
}
|
||||
output_asm_insn (buf, operands);
|
||||
|
||||
/* Output an insn to save %r1. */
|
||||
|
@ -4665,6 +4960,13 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+28|cmp%I2b,%S3,n %2,%r1,.+28}");
|
||||
else
|
||||
strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+28|cmp%I2b,%B3,n %2,%r1,.+28}");
|
||||
if (GET_MODE (operands[1]) == DImode)
|
||||
{
|
||||
if (negated)
|
||||
strcpy (buf, "{com%I2b,*%S3,n %2,%r1,.+28|cmp%I2b,*%S3,n %2,%r1,.+28}");
|
||||
else
|
||||
strcpy (buf, "{com%I2b,*%B3,n %2,%r1,.+28|cmp%I2b,*%B3,n %2,%r1,.+28}");
|
||||
}
|
||||
output_asm_insn (buf, operands);
|
||||
|
||||
/* Output an insn to save %r1. */
|
||||
|
@ -4752,6 +5054,10 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
strcpy (buf, "{extrs,|extrw,s,}");
|
||||
else
|
||||
strcpy (buf, "bb,");
|
||||
if (useskip && GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "extrd,s,*");
|
||||
else if (GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "bb,*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, ">=");
|
||||
|
@ -4780,6 +5086,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
&& nullify)
|
||||
{
|
||||
strcpy (buf, "bb,");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, "<");
|
||||
|
@ -4800,6 +5108,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
- insn_addresses[INSN_UID (insn)] - 8))
|
||||
{
|
||||
strcpy (buf, "bb,");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, ">=");
|
||||
|
@ -4813,6 +5123,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
else
|
||||
{
|
||||
strcpy (buf, "{extrs,|extrw,s,}");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "extrd,s,*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, "<");
|
||||
|
@ -4890,6 +5202,10 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
|||
strcpy (buf, "{vextrs,|extrw,s,}");
|
||||
else
|
||||
strcpy (buf, "{bvb,|bb,}");
|
||||
if (useskip && GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "extrd,s,*}");
|
||||
else if (GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "bb,*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, ">=");
|
||||
|
@ -4918,6 +5234,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
|||
&& nullify)
|
||||
{
|
||||
strcpy (buf, "{bvb,|bb,}");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, "<");
|
||||
|
@ -4938,6 +5256,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
|||
- insn_addresses[INSN_UID (insn)] - 8))
|
||||
{
|
||||
strcpy (buf, "{bvb,|bb,}");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcat (buf, "*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, ">=");
|
||||
|
@ -4951,6 +5271,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
|||
else
|
||||
{
|
||||
strcpy (buf, "{vextrs,|extrw,s,}");
|
||||
if (GET_MODE (operands[0]) == DImode)
|
||||
strcpy (buf, "extrd,s,*");
|
||||
if ((which == 0 && negated)
|
||||
|| (which == 1 && ! negated))
|
||||
strcat (buf, "<");
|
||||
|
@ -5206,6 +5528,10 @@ output_millicode_call (insn, call_dest)
|
|||
rtx xoperands[4];
|
||||
rtx seq_insn;
|
||||
|
||||
xoperands[3] = gen_rtx_REG (SImode, 31);
|
||||
if (TARGET_64BIT)
|
||||
xoperands[3] = gen_rtx_REG (SImode, 2);
|
||||
|
||||
/* Handle common case -- empty delay slot or no jump in the delay slot,
|
||||
and we're sure that the branch will reach the beginning of the $CODE$
|
||||
subspace. */
|
||||
|
@ -5216,7 +5542,7 @@ output_millicode_call (insn, call_dest)
|
|||
&& get_attr_length (insn) == 4))
|
||||
{
|
||||
xoperands[0] = call_dest;
|
||||
output_asm_insn ("{bl|b,l} %0,%%r31%#", xoperands);
|
||||
output_asm_insn ("{bl|b,l} %0,%3%#", xoperands);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -5224,7 +5550,6 @@ output_millicode_call (insn, call_dest)
|
|||
if (get_attr_length (insn) > 4)
|
||||
{
|
||||
int delay_insn_deleted = 0;
|
||||
rtx xoperands[2];
|
||||
|
||||
/* We need to emit an inline long-call branch. */
|
||||
if (dbr_sequence_length () != 0
|
||||
|
@ -5247,8 +5572,8 @@ output_millicode_call (insn, call_dest)
|
|||
|| ! (flag_pic || TARGET_PORTABLE_RUNTIME))
|
||||
{
|
||||
xoperands[0] = call_dest;
|
||||
output_asm_insn ("ldil L%%%0,%%r31", xoperands);
|
||||
output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%%r31)", xoperands);
|
||||
output_asm_insn ("ldil L%%%0,%3", xoperands);
|
||||
output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%3)", xoperands);
|
||||
output_asm_insn ("nop", xoperands);
|
||||
}
|
||||
/* Pure portable runtime doesn't allow be/ble; we also don't have
|
||||
|
@ -5261,7 +5586,7 @@ output_millicode_call (insn, call_dest)
|
|||
output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
|
||||
|
||||
/* Get our return address into %r31. */
|
||||
output_asm_insn ("blr %%r0,%%r31", xoperands);
|
||||
output_asm_insn ("blr %%r0,%3", xoperands);
|
||||
|
||||
/* Jump to our target address in %r29. */
|
||||
output_asm_insn ("bv,n %%r0(%%r29)", xoperands);
|
||||
|
@ -5286,7 +5611,7 @@ output_millicode_call (insn, call_dest)
|
|||
output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
|
||||
|
||||
/* Get the return address into %r31. */
|
||||
output_asm_insn ("blr 0,%%r31", xoperands);
|
||||
output_asm_insn ("blr 0,%3", xoperands);
|
||||
|
||||
/* Branch to our target which is in %r1. */
|
||||
output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
|
||||
|
@ -5330,11 +5655,11 @@ output_millicode_call (insn, call_dest)
|
|||
xoperands[0] = call_dest;
|
||||
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
|
||||
if (! VAL_14_BITS_P (distance))
|
||||
output_asm_insn ("{bl|b,l} %0,%%r31\n\tnop\n\tb,n %1", xoperands);
|
||||
output_asm_insn ("{bl|b,l} %0,%3\n\tnop\n\tb,n %1", xoperands);
|
||||
else
|
||||
{
|
||||
xoperands[2] = gen_label_rtx ();
|
||||
output_asm_insn ("\n\t{bl|b,l} %0,%%r31\n\tldo %1-%2(%%r31),%%r31",
|
||||
output_asm_insn ("\n\t{bl|b,l} %0,%3\n\tldo %1-%2(%3),%3",
|
||||
xoperands);
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
|
||||
CODE_LABEL_NUMBER (xoperands[2]));
|
||||
|
@ -5358,9 +5683,10 @@ extern struct obstack *current_obstack;
|
|||
CALL_DEST is the routine we are calling. */
|
||||
|
||||
const char *
|
||||
output_call (insn, call_dest)
|
||||
output_call (insn, call_dest, sibcall)
|
||||
rtx insn;
|
||||
rtx call_dest;
|
||||
int sibcall;
|
||||
{
|
||||
int distance;
|
||||
rtx xoperands[4];
|
||||
|
@ -5376,7 +5702,8 @@ output_call (insn, call_dest)
|
|||
&& get_attr_length (insn) == 4))
|
||||
{
|
||||
xoperands[0] = call_dest;
|
||||
output_asm_insn ("{bl|b,l} %0,%%r2%#", xoperands);
|
||||
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
|
||||
output_asm_insn ("{bl|b,l} %0,%1%#", xoperands);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -5527,8 +5854,17 @@ output_call (insn, call_dest)
|
|||
/* Branch to our target which is in %r1. */
|
||||
output_asm_insn ("bv %%r0(%%r1)", xoperands);
|
||||
|
||||
/* Copy the return address into %r2 also. */
|
||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
||||
if (sibcall)
|
||||
{
|
||||
/* This call never returns, so we do not need to fix the
|
||||
return pointer. */
|
||||
output_asm_insn ("nop", xoperands);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the return address into %r2 also. */
|
||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5544,8 +5880,17 @@ output_call (insn, call_dest)
|
|||
output_asm_insn ("{ble|be,l} R%%$$dyncall(%%sr4,%%r2)",
|
||||
xoperands);
|
||||
|
||||
/* Copy the return pointer into both %r31 and %r2. */
|
||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
||||
if (sibcall)
|
||||
{
|
||||
/* This call never returns, so we do not need to fix the
|
||||
return pointer. */
|
||||
output_asm_insn ("nop", xoperands);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the return address into %r2 also. */
|
||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6593,6 +6938,245 @@ insn_refs_are_delayed (insn)
|
|||
&& get_attr_type (insn) == TYPE_MILLI));
|
||||
}
|
||||
|
||||
/* Return the location of a parameter that is passed in a register or NULL
|
||||
if the parameter has any component that is passed in memory.
|
||||
|
||||
This is new code and will be pushed to into the net sources after
|
||||
further testing.
|
||||
|
||||
??? We might want to restructure this so that it looks more like other
|
||||
ports. */
|
||||
rtx
|
||||
function_arg (cum, mode, type, named, incoming)
|
||||
CUMULATIVE_ARGS *cum;
|
||||
enum machine_mode mode;
|
||||
tree type;
|
||||
int named;
|
||||
int incoming;
|
||||
{
|
||||
int max_arg_words = (TARGET_64BIT ? 8 : 4);
|
||||
int fpr_reg_base;
|
||||
int gpr_reg_base;
|
||||
rtx retval;
|
||||
|
||||
if (! TARGET_64BIT)
|
||||
{
|
||||
/* If this arg would be passed partially or totally on the stack, then
|
||||
this routine should return zero. FUNCTION_ARG_PARTIAL_NREGS will
|
||||
handle arguments which are split between regs and stack slots if
|
||||
the ABI mandates split arguments. */
|
||||
if (cum->words + FUNCTION_ARG_SIZE (mode, type) > max_arg_words
|
||||
|| mode == VOIDmode)
|
||||
return NULL_RTX;
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = 0;
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
|
||||
offset = 1;
|
||||
if (cum->words + offset >= max_arg_words
|
||||
|| mode == VOIDmode)
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* The 32bit ABIs and the 64bit ABIs are rather different,
|
||||
particularly in their handling of FP registers. We might
|
||||
be able to cleverly share code between them, but I'm not
|
||||
going to bother in the hope that spltting them up results
|
||||
in code that is more easily understood.
|
||||
|
||||
The 64bit code probably is very wrong for structure passing. */
|
||||
if (TARGET_64BIT)
|
||||
{
|
||||
/* Advance the base registers to their current locations.
|
||||
|
||||
Remember, gprs grow towards smaller register numbers while
|
||||
fprs grow to higher register numbers. Also remember FP regs
|
||||
are always 4 bytes wide, while the size of an integer register
|
||||
varies based on the size of the target word. */
|
||||
gpr_reg_base = 26 - cum->words;
|
||||
fpr_reg_base = 32 + cum->words;
|
||||
|
||||
/* If the argument is more than a word long, then we need to align
|
||||
the base registers. Same caveats as above. */
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1)
|
||||
{
|
||||
if (mode != BLKmode)
|
||||
{
|
||||
/* First deal with alignment of the doubleword. */
|
||||
gpr_reg_base -= (cum->words & 1);
|
||||
|
||||
/* This seems backwards, but it is what HP specifies. We need
|
||||
gpr_reg_base to point to the smaller numbered register of
|
||||
the integer register pair. So if we have an even register
|
||||
number, then decrement the gpr base. */
|
||||
gpr_reg_base -= ((gpr_reg_base % 2) == 0);
|
||||
|
||||
/* FP values behave sanely, except that each FP reg is only
|
||||
half of word. */
|
||||
fpr_reg_base += ((fpr_reg_base % 2) == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtx loc[8];
|
||||
int i, offset = 0, ub;
|
||||
ub = FUNCTION_ARG_SIZE (mode, type);
|
||||
ub = MIN(ub,
|
||||
MAX(0, max_arg_words - cum->words - (cum->words & 1)));
|
||||
gpr_reg_base -= (cum->words & 1);
|
||||
for (i = 0; i < ub; i++)
|
||||
{
|
||||
loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode,
|
||||
gpr_reg_base),
|
||||
GEN_INT(offset));
|
||||
gpr_reg_base -= 1;
|
||||
offset += 8;
|
||||
}
|
||||
if (ub == 0)
|
||||
return NULL_RTX;
|
||||
else if (ub == 1)
|
||||
return XEXP (loc[0], 0);
|
||||
else
|
||||
return gen_rtx_PARALLEL(mode, gen_rtvec_v(ub, loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the argument is larger than a word, then we know precisely
|
||||
which registers we must use. */
|
||||
if (FUNCTION_ARG_SIZE (mode, type) > 1)
|
||||
{
|
||||
if (cum->words)
|
||||
{
|
||||
gpr_reg_base = 23;
|
||||
fpr_reg_base = 38;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr_reg_base = 25;
|
||||
fpr_reg_base = 34;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have a single word (32 bits). A simple computation
|
||||
will get us the register #s we need. */
|
||||
gpr_reg_base = 26 - cum->words;
|
||||
fpr_reg_base = 32 + 2 * cum->words;
|
||||
}
|
||||
}
|
||||
|
||||
if (TARGET_64BIT && mode == TFmode)
|
||||
{
|
||||
return
|
||||
gen_rtx_PARALLEL
|
||||
(mode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode, gpr_reg_base + 1),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (DImode, gpr_reg_base),
|
||||
GEN_INT (8))));
|
||||
}
|
||||
/* Determine if the register needs to be passed in both general and
|
||||
floating point registers. */
|
||||
if ((TARGET_PORTABLE_RUNTIME || TARGET_64BIT)
|
||||
/* If we are doing soft-float with portable runtime, then there
|
||||
is no need to worry about FP regs. */
|
||||
&& ! TARGET_SOFT_FLOAT
|
||||
/* The parameter must be some kind of float, else we can just
|
||||
pass it in integer registers. */
|
||||
&& FLOAT_MODE_P (mode)
|
||||
/* The target function must not have a prototype. */
|
||||
&& cum->nargs_prototype <= 0
|
||||
/* libcalls do not need to pass items in both FP and general
|
||||
registers. */
|
||||
&& type != NULL_TREE
|
||||
/* All this hair applies to outgoing args only. */
|
||||
&& !incoming)
|
||||
{
|
||||
retval
|
||||
= gen_rtx_PARALLEL
|
||||
(mode,
|
||||
gen_rtvec (2,
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode, fpr_reg_base),
|
||||
const0_rtx),
|
||||
gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_REG (mode, gpr_reg_base),
|
||||
const0_rtx)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* See if we should pass this parameter in a general register. */
|
||||
if (TARGET_SOFT_FLOAT
|
||||
/* Indirect calls in the normal 32bit ABI require all arguments
|
||||
to be passed in general registers. */
|
||||
|| (!TARGET_PORTABLE_RUNTIME
|
||||
&& !TARGET_64BIT
|
||||
&& cum->indirect)
|
||||
/* If the parameter is not a floating point parameter, then
|
||||
it belongs in GPRs. */
|
||||
|| !FLOAT_MODE_P (mode))
|
||||
retval = gen_rtx_REG (mode, gpr_reg_base);
|
||||
else
|
||||
retval = gen_rtx_REG (mode, fpr_reg_base);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* If this arg would be passed totally in registers or totally on the stack,
|
||||
then this routine should return zero. It is currently called only for
|
||||
the 64-bit target. */
|
||||
int
|
||||
function_arg_partial_nregs (cum, mode, type, named)
|
||||
CUMULATIVE_ARGS *cum;
|
||||
enum machine_mode mode;
|
||||
tree type;
|
||||
int named;
|
||||
{
|
||||
int max_arg_words = 8;
|
||||
int offset = 0;
|
||||
|
||||
if (FUNCTION_ARG_SIZE(mode, type) > 1 && (cum->words & 1))
|
||||
offset = 1;
|
||||
|
||||
if (cum->words + offset + FUNCTION_ARG_SIZE(mode, type) <= max_arg_words)
|
||||
/* Arg fits fully into registers. */
|
||||
return 0;
|
||||
else if (cum->words + offset >= max_arg_words)
|
||||
/* Arg fully on the stack. */
|
||||
return 0;
|
||||
else
|
||||
/* Arg is split. */
|
||||
return max_arg_words - cum->words - offset;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Return 1 if this is a comparison operator. This allows the use of
|
||||
MATCH_OPERATOR to recognize all the branch insns. */
|
||||
|
||||
int
|
||||
cmpib_comparison_operator (op, mode)
|
||||
register rtx op;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
return ((mode == VOIDmode || GET_MODE (op) == mode)
|
||||
&& (GET_CODE (op) == EQ
|
||||
|| GET_CODE (op) == NE
|
||||
|| GET_CODE (op) == GT
|
||||
|| GET_CODE (op) == GE
|
||||
|| GET_CODE (op) == GTU
|
||||
|| GET_CODE (op) == LT
|
||||
|| GET_CODE (op) == LE
|
||||
|| GET_CODE (op) == LEU));
|
||||
}
|
||||
|
||||
/* Mark ARG (which is really a struct deferred_plabel **) for GC. */
|
||||
|
||||
static void
|
||||
|
|
|
@ -85,7 +85,10 @@ extern int target_flags;
|
|||
/* compile code for HP-PA 1.1 ("Snake") */
|
||||
|
||||
#define MASK_PA_11 1
|
||||
|
||||
#ifndef TARGET_PA_11
|
||||
#define TARGET_PA_11 (target_flags & MASK_PA_11)
|
||||
#endif
|
||||
|
||||
/* Disable all FP registers (they all become fixed). This may be necessary
|
||||
for compiling kernels which perform lazy context switching of FP regs.
|
||||
|
@ -150,7 +153,14 @@ extern int target_flags;
|
|||
/* Generate code for the HPPA 2.0 architecture. TARGET_PA_11 should also be
|
||||
true when this is true. */
|
||||
#define MASK_PA_20 4096
|
||||
#ifndef TARGET_PA_20
|
||||
#define TARGET_PA_20 (target_flags & MASK_PA_20)
|
||||
#endif
|
||||
|
||||
/* Generate code for the HPPA 2.0 architecture in 64bit mode. */
|
||||
#ifndef TARGET_64BIT
|
||||
#define TARGET_64BIT 0
|
||||
#endif
|
||||
|
||||
/* Macro to define tables used to set the flags.
|
||||
This is a list in braces of pairs in braces,
|
||||
|
@ -248,17 +258,63 @@ extern int target_flags;
|
|||
((GET_CODE (X) == PLUS ? OFFSET : 0) \
|
||||
+ (frame_pointer_needed ? 0 : compute_frame_size (get_frame_size (), 0)))
|
||||
|
||||
#define CPP_PA10_SPEC ""
|
||||
#define CPP_PA11_SPEC "-D_PA_RISC1_1 -D__hp9000s700"
|
||||
#define CPP_PA20_SPEC "-D_PA_RISC2_0 -D__hp9000s800"
|
||||
#define CPP_64BIT_SPEC "-D__LP64__ -D__LONG_MAX__=9223372036854775807L"
|
||||
|
||||
#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_PA_11) == 0
|
||||
#define CPP_SPEC "%{msnake:-D__hp9000s700 -D_PA_RISC1_1}\
|
||||
%{mpa-risc-1-1:-D__hp9000s700 -D_PA_RISC1_1}\
|
||||
%{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE -D__STDC_EXT__}\
|
||||
%{threads:-D_REENTRANT -D_DCE_THREADS}"
|
||||
#else
|
||||
#define CPP_SPEC "%{!mpa-risc-1-0:%{!mnosnake:%{!msoft-float:-D__hp9000s700 -D_PA_RISC1_1}}} \
|
||||
%{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE -D__STDC_EXT__}\
|
||||
%{threads:-D_REENTRANT -D_DCE_THREADS}"
|
||||
#define CPP_CPU_DEFAULT_SPEC "%(cpp_pa10)"
|
||||
#endif
|
||||
|
||||
#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_PA_11) != 0
|
||||
#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_PA_20) != 0
|
||||
#define CPP_CPU_DEFAULT_SPEC "%(cpp_pa11) %(cpp_pa20)"
|
||||
#else
|
||||
#define CPP_CPU_DEFAULT_SPEC "%(cpp_pa11)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if TARGET_64BIT
|
||||
#define CPP_64BIT_DEFAULT_SPEC "%(cpp_64bit)"
|
||||
#else
|
||||
#define CPP_64BIT_DEFAULT_SPEC ""
|
||||
#endif
|
||||
|
||||
/* This macro defines names of additional specifications to put in the
|
||||
specs that can be used in various specifications like CC1_SPEC. Its
|
||||
definition is an initializer with a subgrouping for each command option.
|
||||
|
||||
Each subgrouping contains a string constant, that defines the
|
||||
specification name, and a string constant that used by the GNU CC driver
|
||||
program.
|
||||
|
||||
Do not define this macro if it does not need to do anything. */
|
||||
|
||||
#ifndef SUBTARGET_EXTRA_SPECS
|
||||
#define SUBTARGET_EXTRA_SPECS
|
||||
#endif
|
||||
|
||||
#define EXTRA_SPECS \
|
||||
{ "cpp_pa10", CPP_PA10_SPEC}, \
|
||||
{ "cpp_pa11", CPP_PA11_SPEC}, \
|
||||
{ "cpp_pa20", CPP_PA20_SPEC}, \
|
||||
{ "cpp_64bit", CPP_64BIT_SPEC}, \
|
||||
{ "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
|
||||
{ "cpp_64bit_default", CPP_64BIT_DEFAULT_SPEC }, \
|
||||
SUBTARGET_EXTRA_SPECS
|
||||
|
||||
#define CPP_SPEC "\
|
||||
%{mpa-risc-1-0:%(cpp_pa10)} \
|
||||
%{mpa-risc-1-1:%(cpp_pa11)} \
|
||||
%{msnake:%(cpp_pa11)} \
|
||||
%{mpa-risc-2-0:%(cpp_pa20)} \
|
||||
%{!mpa-risc-1-0:%{!mpa-risc-1-1:%{!mpa-risc-2-0:%{!msnake:%(cpp_cpu_default)}}}} \
|
||||
%{m64bit:%(cpp_64bit)} \
|
||||
%{!m64bit:%(cpp_64bit_default)} \
|
||||
%{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE -D__STDC_EXT__}\
|
||||
%{threads:-D_REENTRANT -D_DCE_THREADS}"
|
||||
|
||||
/* Defines for a K&R CC */
|
||||
|
||||
#define CC1_SPEC "%{pg:} %{p:}"
|
||||
|
@ -323,10 +379,14 @@ extern int target_flags;
|
|||
Note that this is not necessarily the width of data type `int';
|
||||
if using 16-bit ints on a 68000, this would still be 32.
|
||||
But on a machine with 16-bit registers, this would be 16. */
|
||||
#define BITS_PER_WORD 32
|
||||
#define BITS_PER_WORD (TARGET_64BIT ? 64 : 32)
|
||||
#define MAX_BITS_PER_WORD 64
|
||||
#define MAX_LONG_TYPE_SIZE 64
|
||||
#define MAX_WCHAR_TYPE_SIZE 32
|
||||
|
||||
/* Width of a word, in units (bytes). */
|
||||
#define UNITS_PER_WORD 4
|
||||
#define UNITS_PER_WORD (TARGET_64BIT ? 8 : 4)
|
||||
#define MIN_UNITS_PER_WORD 4
|
||||
|
||||
/* Width in bits of a pointer.
|
||||
See also the macro `Pmode' defined below. */
|
||||
|
@ -344,10 +404,10 @@ extern int target_flags;
|
|||
|
||||
GCC for the PA always rounds its stacks to a 512bit boundary,
|
||||
but that happens late in the compilation process. */
|
||||
#define STACK_BOUNDARY 64
|
||||
#define STACK_BOUNDARY (TARGET_64BIT ? 128 : 64)
|
||||
|
||||
/* Allocation boundary (in *bits*) for the code of a function. */
|
||||
#define FUNCTION_BOUNDARY 32
|
||||
#define FUNCTION_BOUNDARY (TARGET_64BIT ? 64 : 32)
|
||||
|
||||
/* Alignment of field after `int : 0' in a structure. */
|
||||
#define EMPTY_FIELD_BOUNDARY 32
|
||||
|
@ -420,17 +480,19 @@ extern int target_flags;
|
|||
/* Register which holds offset table for position-independent
|
||||
data references. */
|
||||
|
||||
#define PIC_OFFSET_TABLE_REGNUM 19
|
||||
#define PIC_OFFSET_TABLE_REGNUM (TARGET_64BIT ? 27 : 19)
|
||||
#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED 1
|
||||
|
||||
/* Register into which we save the PIC_OFFEST_TABLE_REGNUM so that it
|
||||
can be restore across function calls. */
|
||||
#define PIC_OFFSET_TABLE_REGNUM_SAVED 4
|
||||
|
||||
/* SOM ABI says that objects larger than 64 bits are returned in memory. */
|
||||
#define DEFAULT_PCC_STRUCT_RETURN 0
|
||||
|
||||
/* SOM ABI says that objects larger than 64 bits are returned in memory.
|
||||
PA64 ABI says that objects larger than 128 bits are returned in memory. */
|
||||
#define RETURN_IN_MEMORY(TYPE) \
|
||||
(int_size_in_bytes (TYPE) > 8)
|
||||
(TARGET_64BIT ? int_size_in_bytes (TYPE) > 16 : int_size_in_bytes (TYPE) > 8)
|
||||
|
||||
/* Register in which address to store a structure value
|
||||
is passed to a function. */
|
||||
|
@ -447,7 +509,9 @@ extern int target_flags;
|
|||
`K' is used for values that can be moved with a zdepi insn.
|
||||
`L' is used for the 5 bit constants.
|
||||
`M' is used for 0.
|
||||
`N' is used for values with the least significant 11 bits equal to zero.
|
||||
`N' is used for values with the least significant 11 bits equal to zero
|
||||
and when sign extended from 32 to 64 bits the
|
||||
value does not change.
|
||||
`O' is used for numbers n such that n+1 is a power of 2.
|
||||
*/
|
||||
|
||||
|
@ -457,8 +521,10 @@ extern int target_flags;
|
|||
: (C) == 'K' ? zdepi_cint_p (VALUE) \
|
||||
: (C) == 'L' ? VAL_5_BITS_P (VALUE) \
|
||||
: (C) == 'M' ? (VALUE) == 0 \
|
||||
: (C) == 'N' ? ((VALUE) & 0x7ff) == 0 \
|
||||
: (C) == 'O' ? (((VALUE) & ((VALUE) + 1)) == 0) \
|
||||
: (C) == 'N' ? (((VALUE) & (unsigned long)0x7ff) == 0 \
|
||||
&& (VALUE) == ((((VALUE) & 0xffffffff) ^ (~0x7fffffff)) \
|
||||
+ 0x80000000)) \
|
||||
: (C) == 'O' ? (((VALUE) & ((VALUE) + (long)1)) == 0) \
|
||||
: (C) == 'P' ? and_mask_p (VALUE) \
|
||||
: 0)
|
||||
|
||||
|
@ -542,11 +608,11 @@ extern int target_flags;
|
|||
argument, not it's beginning. To get the real offset of the first
|
||||
argument, the size of the argument must be added. */
|
||||
|
||||
#define FIRST_PARM_OFFSET(FNDECL) -32
|
||||
#define FIRST_PARM_OFFSET(FNDECL) (TARGET_64BIT ? -64 : -32)
|
||||
|
||||
/* When a parameter is passed in a register, stack space is still
|
||||
allocated for it. */
|
||||
#define REG_PARM_STACK_SPACE(DECL) 16
|
||||
#define REG_PARM_STACK_SPACE(DECL) (TARGET_64BIT ? 64 : 16)
|
||||
|
||||
/* Define this if the above stack space is to be considered part of the
|
||||
space allocated by the caller. */
|
||||
|
@ -562,10 +628,13 @@ extern int target_flags;
|
|||
the stack: 16 bytes for register saves, and 32 bytes for magic.
|
||||
This is the difference between the logical top of stack and the
|
||||
actual sp. */
|
||||
#define STACK_POINTER_OFFSET -32
|
||||
#define STACK_POINTER_OFFSET \
|
||||
(TARGET_64BIT ? -(current_function_outgoing_args_size + 16): -32)
|
||||
|
||||
#define STACK_DYNAMIC_OFFSET(FNDECL) \
|
||||
((STACK_POINTER_OFFSET) - current_function_outgoing_args_size)
|
||||
(TARGET_64BIT \
|
||||
? (STACK_POINTER_OFFSET) \
|
||||
: ((STACK_POINTER_OFFSET) - current_function_outgoing_args_size))
|
||||
|
||||
/* Value is 1 if returning from a function call automatically
|
||||
pops the arguments described by the number-of-args field in the call.
|
||||
|
@ -583,11 +652,14 @@ extern int target_flags;
|
|||
/* On the HP-PA the value is found in register(s) 28(-29), unless
|
||||
the mode is SF or DF. Then the value is returned in fr4 (32, ) */
|
||||
|
||||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||||
gen_rtx_REG (TYPE_MODE (VALTYPE), ((! TARGET_SOFT_FLOAT \
|
||||
&& (TYPE_MODE (VALTYPE) == SFmode || \
|
||||
TYPE_MODE (VALTYPE) == DFmode)) ? \
|
||||
32 : 28))
|
||||
/* This must perform the same promotions as PROMOTE_MODE, else
|
||||
PROMOTE_FUNCTION_RETURN will not work correctly. */
|
||||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||||
gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
|
||||
&& TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
|
||||
|| POINTER_TYPE_P (VALTYPE)) \
|
||||
? word_mode : TYPE_MODE (VALTYPE), \
|
||||
TREE_CODE (VALTYPE) == REAL_TYPE && !TARGET_SOFT_FLOAT ? 32 : 28)
|
||||
|
||||
/* Define how to find the value returned by a library function
|
||||
assuming the value has mode MODE. */
|
||||
|
@ -712,54 +784,20 @@ struct hppa_args {int words, nargs_prototype, indirect; };
|
|||
/* Do not expect to understand this without reading it several times. I'm
|
||||
tempted to try and simply it, but I worry about breaking something. */
|
||||
|
||||
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
||||
(4 >= ((CUM).words + FUNCTION_ARG_SIZE ((MODE), (TYPE))) \
|
||||
? (!TARGET_PORTABLE_RUNTIME || (TYPE) == 0 \
|
||||
|| !FLOAT_MODE_P (MODE) || TARGET_SOFT_FLOAT \
|
||||
|| (CUM).nargs_prototype > 0) \
|
||||
? gen_rtx_REG ((MODE), \
|
||||
(FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1 \
|
||||
? (((!(CUM).indirect \
|
||||
|| TARGET_PORTABLE_RUNTIME) \
|
||||
&& (MODE) == DFmode \
|
||||
&& ! TARGET_SOFT_FLOAT) \
|
||||
? ((CUM).words ? 38 : 34) \
|
||||
: ((CUM).words ? 23 : 25)) \
|
||||
: (((!(CUM).indirect \
|
||||
|| TARGET_PORTABLE_RUNTIME) \
|
||||
&& (MODE) == SFmode \
|
||||
&& ! TARGET_SOFT_FLOAT) \
|
||||
? (32 + 2 * (CUM).words) \
|
||||
: (27 - (CUM).words - FUNCTION_ARG_SIZE ((MODE),\
|
||||
(TYPE))))))\
|
||||
/* We are calling a non-prototyped function with floating point \
|
||||
arguments using the portable conventions. */ \
|
||||
: (gen_rtx_PARALLEL \
|
||||
((MODE), \
|
||||
gen_rtvec \
|
||||
(2, \
|
||||
gen_rtx_EXPR_LIST \
|
||||
(VOIDmode, \
|
||||
gen_rtx_REG ((MODE), \
|
||||
(FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1 \
|
||||
? ((CUM).words ? 38 : 34) : (32 + 2 * (CUM).words))), \
|
||||
const0_rtx), \
|
||||
gen_rtx_EXPR_LIST \
|
||||
(VOIDmode, \
|
||||
gen_rtx_REG ((MODE), \
|
||||
(FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1 \
|
||||
? ((CUM).words ? 23 : 25) \
|
||||
: (27 - (CUM).words - \
|
||||
FUNCTION_ARG_SIZE ((MODE), (TYPE))))), \
|
||||
const0_rtx)))) \
|
||||
/* Pass this parameter in the stack. */ \
|
||||
: 0)
|
||||
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
||||
function_arg (&CUM, MODE, TYPE, NAMED, 0)
|
||||
|
||||
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
|
||||
function_arg (&CUM, MODE, TYPE, NAMED, 1)
|
||||
|
||||
/* For an arg passed partly in registers and partly in memory,
|
||||
this is the number of registers used.
|
||||
For args passed entirely in registers or entirely in memory, zero. */
|
||||
|
||||
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
|
||||
/* For PA32 there are never split arguments. PA64, on the other hand, can
|
||||
pass arguments partially in registers and partially in memory. */
|
||||
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
|
||||
(TARGET_64BIT ? function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED) : 0)
|
||||
|
||||
/* If defined, a C expression that gives the alignment boundary, in
|
||||
bits, of an argument with the specified mode and type. If it is
|
||||
|
@ -777,13 +815,21 @@ struct hppa_args {int words, nargs_prototype, indirect; };
|
|||
|
||||
/* Arguments larger than eight bytes are passed by invisible reference */
|
||||
|
||||
/* PA64 does not pass anything by invisible reference. */
|
||||
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
|
||||
(((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8))
|
||||
(TARGET_64BIT \
|
||||
? 0 \
|
||||
: (((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8)))
|
||||
|
||||
/* PA64 does not pass anything by invisible reference.
|
||||
This should be undef'ed for 64bit, but we'll see if this works. The
|
||||
problem is that we can't test TARGET_64BIT from the preprocessor. */
|
||||
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
|
||||
(((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8))
|
||||
(TARGET_64BIT \
|
||||
? 0 \
|
||||
: (((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8)))
|
||||
|
||||
|
||||
extern struct rtx_def *hppa_compare_op0, *hppa_compare_op1;
|
||||
|
@ -869,22 +915,40 @@ extern int may_call_alloca;
|
|||
It is best to keep this as small as possible to avoid having to
|
||||
flush multiple lines in the cache. */
|
||||
|
||||
#define TRAMPOLINE_TEMPLATE(FILE) \
|
||||
{ \
|
||||
fputs ("\tldw 36(%r22),%r21\n", FILE); \
|
||||
fputs ("\tbb,>=,n %r21,30,.+16\n", FILE); \
|
||||
if (ASSEMBLER_DIALECT == 0) \
|
||||
fputs ("\tdepi 0,31,2,%r21\n", FILE); \
|
||||
else \
|
||||
fputs ("\tdepwi 0,31,2,%r21\n", FILE); \
|
||||
fputs ("\tldw 4(%r21),%r19\n", FILE); \
|
||||
fputs ("\tldw 0(%r21),%r21\n", FILE); \
|
||||
fputs ("\tldsid (%r21),%r1\n", FILE); \
|
||||
fputs ("\tmtsp %r1,%sr0\n", FILE); \
|
||||
fputs ("\tbe 0(%sr0,%r21)\n", FILE); \
|
||||
fputs ("\tldw 40(%r22),%r29\n", FILE); \
|
||||
fputs ("\t.word 0\n", FILE); \
|
||||
fputs ("\t.word 0\n", FILE); \
|
||||
#define TRAMPOLINE_TEMPLATE(FILE) \
|
||||
{ \
|
||||
if (! TARGET_64BIT) \
|
||||
{ \
|
||||
fputs ("\tldw 36(%r22),%r21\n", FILE); \
|
||||
fputs ("\tbb,>=,n %r21,30,.+16\n", FILE); \
|
||||
if (ASSEMBLER_DIALECT == 0) \
|
||||
fputs ("\tdepi 0,31,2,%r21\n", FILE); \
|
||||
else \
|
||||
fputs ("\tdepwi 0,31,2,%r21\n", FILE); \
|
||||
fputs ("\tldw 4(%r21),%r19\n", FILE); \
|
||||
fputs ("\tldw 0(%r21),%r21\n", FILE); \
|
||||
fputs ("\tldsid (%r21),%r1\n", FILE); \
|
||||
fputs ("\tmtsp %r1,%sr0\n", FILE); \
|
||||
fputs ("\tbe 0(%sr0,%r21)\n", FILE); \
|
||||
fputs ("\tldw 40(%r22),%r29\n", FILE); \
|
||||
fputs ("\t.word 0\n", FILE); \
|
||||
fputs ("\t.word 0\n", FILE); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fputs ("\t.dword 0\n", FILE); \
|
||||
fputs ("\t.dword 0\n", FILE); \
|
||||
fputs ("\t.dword 0\n", FILE); \
|
||||
fputs ("\t.dword 0\n", FILE); \
|
||||
fputs ("\tmfia %r31\n", FILE); \
|
||||
fputs ("\tldd 24(%r31),%r1\n", FILE); \
|
||||
fputs ("\tldd 24(%r1),%r27\n", FILE); \
|
||||
fputs ("\tldd 16(%r1),%r1\n", FILE); \
|
||||
fputs ("\tbve (%r1)\n", FILE); \
|
||||
fputs ("\tldd 32(%r31),%r31\n", FILE); \
|
||||
fputs ("\t.dword 0 ; fptr\n", FILE); \
|
||||
fputs ("\t.dword 0 ; static link\n", FILE); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Length in units of the trampoline for entering a nested function.
|
||||
|
@ -896,7 +960,7 @@ extern int may_call_alloca;
|
|||
If the code part of the trampoline ever grows to > 32 bytes, then it
|
||||
will become necessary to hack on the cacheflush pattern in pa.md. */
|
||||
|
||||
#define TRAMPOLINE_SIZE (11 * 4)
|
||||
#define TRAMPOLINE_SIZE (TARGET_64BIT ? 72 : 11 * 4)
|
||||
|
||||
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
||||
FNADDR is an RTX for the address of the function's pure code.
|
||||
|
@ -905,22 +969,49 @@ extern int may_call_alloca;
|
|||
Move the function address to the trampoline template at offset 12.
|
||||
Move the static chain value to trampoline template at offset 16. */
|
||||
|
||||
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
||||
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
||||
{ \
|
||||
rtx start_addr, end_addr; \
|
||||
if (! TARGET_64BIT) \
|
||||
{ \
|
||||
rtx start_addr, end_addr; \
|
||||
\
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 36)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (FNADDR)); \
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 40)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (CXT)); \
|
||||
/* fdc and fic only use registers for the address to flush, \
|
||||
they do not accept integer displacements. */ \
|
||||
start_addr = force_reg (Pmode, (TRAMP)); \
|
||||
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
||||
emit_insn (gen_dcacheflush (start_addr, end_addr)); \
|
||||
end_addr = force_reg (Pmode, plus_constant (start_addr, 32)); \
|
||||
emit_insn (gen_icacheflush (start_addr, end_addr, start_addr, \
|
||||
gen_reg_rtx (Pmode), gen_reg_rtx (Pmode)));\
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 36)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (FNADDR)); \
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 40)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (CXT)); \
|
||||
/* fdc and fic only use registers for the address to flush, \
|
||||
they do not accept integer displacements. */ \
|
||||
start_addr = force_reg (Pmode, (TRAMP)); \
|
||||
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
||||
emit_insn (gen_dcacheflush (start_addr, end_addr)); \
|
||||
end_addr = force_reg (Pmode, plus_constant (start_addr, 32)); \
|
||||
emit_insn (gen_icacheflush (start_addr, end_addr, start_addr, \
|
||||
gen_reg_rtx (Pmode), gen_reg_rtx (Pmode)));\
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
rtx start_addr, end_addr; \
|
||||
\
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 56)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (FNADDR)); \
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 64)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (CXT)); \
|
||||
/* Create a fat pointer for the trampoline. */ \
|
||||
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 16)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), end_addr); \
|
||||
end_addr = gen_rtx_REG (Pmode, 27); \
|
||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 24)); \
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), end_addr); \
|
||||
/* fdc and fic only use registers for the address to flush, \
|
||||
they do not accept integer displacements. */ \
|
||||
start_addr = force_reg (Pmode, (TRAMP)); \
|
||||
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
||||
emit_insn (gen_dcacheflush (start_addr, end_addr)); \
|
||||
end_addr = force_reg (Pmode, plus_constant (start_addr, 32)); \
|
||||
emit_insn (gen_icacheflush (start_addr, end_addr, start_addr, \
|
||||
gen_reg_rtx (Pmode), gen_reg_rtx (Pmode)));\
|
||||
} \
|
||||
}
|
||||
|
||||
/* Emit code for a call to builtin_saveregs. We must emit USE insns which
|
||||
|
@ -995,17 +1086,30 @@ extern int may_call_alloca;
|
|||
/* Include all constant integers and constant doubles, but not
|
||||
floating-point, except for floating-point zero.
|
||||
|
||||
Reject LABEL_REFs if we're not using gas or the new HP assembler. */
|
||||
Reject LABEL_REFs if we're not using gas or the new HP assembler.
|
||||
|
||||
?!? For now also reject CONST_DOUBLES in 64bit mode. This will need
|
||||
further work. */
|
||||
#ifdef NEW_HP_ASSEMBLER
|
||||
#define LEGITIMATE_CONSTANT_P(X) \
|
||||
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
||||
|| (X) == CONST0_RTX (GET_MODE (X))) \
|
||||
&& !(TARGET_64BIT && GET_CODE (X) == CONST_DOUBLE) \
|
||||
&& !(TARGET_64BIT && GET_CODE (X) == CONST_INT \
|
||||
&& !(cint_ok_for_move (INTVAL (X)) \
|
||||
|| ((INTVAL (X) & 0xffffffff80000000L) == 0xffffffff80000000L) \
|
||||
|| ((INTVAL (X) & 0xffffffff00000000L) == 0x0000000000000000L))) \
|
||||
&& !function_label_operand (X, VOIDmode))
|
||||
#else
|
||||
#define LEGITIMATE_CONSTANT_P(X) \
|
||||
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
||||
|| (X) == CONST0_RTX (GET_MODE (X))) \
|
||||
&& (GET_CODE (X) != LABEL_REF || TARGET_GAS)\
|
||||
&& !(TARGET_64BIT && GET_CODE (X) == CONST_DOUBLE) \
|
||||
&& !(TARGET_64BIT && GET_CODE (X) == CONST_INT \
|
||||
&& !(cint_ok_for_move (INTVAL (X)) \
|
||||
|| ((INTVAL (X) & 0xffffffff80000000L) == 0xffffffff80000000L) \
|
||||
|| ((INTVAL (X) & 0xffffffff00000000L) == 0x0000000000000000L))) \
|
||||
&& !function_label_operand (X, VOIDmode))
|
||||
#endif
|
||||
|
||||
|
@ -1064,8 +1168,11 @@ extern int may_call_alloca;
|
|||
&& !(GET_CODE (XEXP (OP, 0)) == PLUS \
|
||||
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
|
||||
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT)))\
|
||||
: ((C) == 'U' ? \
|
||||
(GET_CODE (OP) == CONST_INT && INTVAL (OP) == 63) \
|
||||
: ((C) == 'S' ? \
|
||||
(GET_CODE (OP) == CONST_INT && INTVAL (OP) == 31) : 0))))
|
||||
(GET_CODE (OP) == CONST_INT && INTVAL (OP) == 31) : 0)))))
|
||||
|
||||
|
||||
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
|
||||
and check its validity for a certain class.
|
||||
|
@ -1115,16 +1222,16 @@ extern int may_call_alloca;
|
|||
doing so avoids losing for loading/storing a FP register at an address
|
||||
which will not fit in 5 bits. */
|
||||
|
||||
#define VAL_5_BITS_P(X) ((unsigned)(X) + 0x10 < 0x20)
|
||||
#define VAL_5_BITS_P(X) ((unsigned HOST_WIDE_INT)(X) + 0x10 < 0x20)
|
||||
#define INT_5_BITS(X) VAL_5_BITS_P (INTVAL (X))
|
||||
|
||||
#define VAL_U5_BITS_P(X) ((unsigned)(X) < 0x20)
|
||||
#define VAL_U5_BITS_P(X) ((unsigned HOST_WIDE_INT)(X) < 0x20)
|
||||
#define INT_U5_BITS(X) VAL_U5_BITS_P (INTVAL (X))
|
||||
|
||||
#define VAL_11_BITS_P(X) ((unsigned)(X) + 0x400 < 0x800)
|
||||
#define VAL_11_BITS_P(X) ((unsigned HOST_WIDE_INT)(X) + 0x400 < 0x800)
|
||||
#define INT_11_BITS(X) VAL_11_BITS_P (INTVAL (X))
|
||||
|
||||
#define VAL_14_BITS_P(X) ((unsigned)(X) + 0x2000 < 0x4000)
|
||||
#define VAL_14_BITS_P(X) ((unsigned HOST_WIDE_INT)(X) + 0x2000 < 0x4000)
|
||||
#define INT_14_BITS(X) VAL_14_BITS_P (INTVAL (X))
|
||||
|
||||
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
||||
|
@ -1414,8 +1521,13 @@ while (0)
|
|||
|
||||
/* Higher than the default as we prefer to use simple move insns
|
||||
(better scheduling and delay slot filling) and because our
|
||||
built-in block move is really a 2X unrolled loop. */
|
||||
#define MOVE_RATIO 4
|
||||
built-in block move is really a 2X unrolled loop.
|
||||
|
||||
Believe it or not, this has to be big enough to allow for copying all
|
||||
arguments passed in registers to avoid infinite recursion during argument
|
||||
setup for a function call. Why? Consider how we copy the stack slots
|
||||
reserved for parameters when they may be trashed by a call. */
|
||||
#define MOVE_RATIO (TARGET_64BIT ? 8 : 4)
|
||||
|
||||
/* Define if operations between registers always perform the operation
|
||||
on the full register even if a narrower mode is specified. */
|
||||
|
@ -1441,6 +1553,7 @@ while (0)
|
|||
|
||||
/* When a prototype says `char' or `short', really pass an `int'. */
|
||||
#define PROMOTE_PROTOTYPES 1
|
||||
#define PROMOTE_FUNCTION_RETURN 1
|
||||
|
||||
/* Specify the machine mode that pointers have.
|
||||
After generation of rtl, the compiler makes no further distinction
|
||||
|
@ -1867,6 +1980,35 @@ while (0)
|
|||
/* The number of Pmode words for the setjmp buffer. */
|
||||
#define JMP_BUF_SIZE 50
|
||||
|
||||
/* Only direct calls to static functions are allowed to be sibling (tail)
|
||||
call optimized.
|
||||
|
||||
This restriction is necessary because some linker generated stubs will
|
||||
store return pointers into rp' in some cases which might clobber a
|
||||
live value already in rp'.
|
||||
|
||||
In a sibcall the current function and the target function share stack
|
||||
space. Thus if the path to the current function and the path to the
|
||||
target function save a value in rp', they save the value into the
|
||||
same stack slot, which has undesirable consequences.
|
||||
|
||||
Because of the deferred binding nature of shared libraries any function
|
||||
with external scope could be in a different load module and thus require
|
||||
rp' to be saved when calling that function. So sibcall optimizations
|
||||
can only be safe for static function.
|
||||
|
||||
Note that GCC never needs return value relocations, so we don't have to
|
||||
worry about static calls with return value relocations (which require
|
||||
saving rp').
|
||||
|
||||
It is safe to perform a sibcall optimization when the target function
|
||||
will never return. */
|
||||
#define FUNCTION_OK_FOR_SIBCALL(DECL) \
|
||||
(DECL \
|
||||
&& ! TARGET_64BIT \
|
||||
&& (! TREE_PUBLIC (DECL) \
|
||||
|| TREE_THIS_VOLATILE (DECL)))
|
||||
|
||||
#define PREDICATE_CODES \
|
||||
{"reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"call_operand_address", {LABEL_REF, SYMBOL_REF, CONST_INT, \
|
||||
|
|
1571
gcc/config/pa/pa.md
1571
gcc/config/pa/pa.md
File diff suppressed because it is too large
Load diff
|
@ -56,7 +56,7 @@ Boston, MA 02111-1307, USA. */
|
|||
Reg 20-22 = Temporary Registers
|
||||
Reg 23-26 = Temporary/Parameter Registers
|
||||
Reg 27 = Global Data Pointer (hp)
|
||||
Reg 28 = Temporary/???/Return Value register
|
||||
Reg 28 = Temporary/Return Value register
|
||||
Reg 29 = Temporary/Static Chain/Return Value register #2
|
||||
Reg 30 = stack pointer
|
||||
Reg 31 = Temporary/Millicode Return Pointer (hp)
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
checking for TARGET_64BIT. */
|
||||
#define TARGET_64BIT 1
|
||||
#define TARGET_PA_11 1
|
||||
#defien TARGET_PA_20 1
|
||||
#define TARGET_PA_20 1
|
||||
|
|
Loading…
Add table
Reference in a new issue