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:
Jeffrey A Law 2000-04-11 20:02:46 +00:00 committed by Jeff Law
parent cba6a0b29f
commit 520babc783
8 changed files with 2480 additions and 208 deletions

View File

@ -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,

View File

@ -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"

View File

@ -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 */

View File

@ -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

View File

@ -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, \

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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