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
|
@ -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>
|
2000-04-11 Zack Weinberg <zack@wolery.cumb.org>
|
||||||
|
|
||||||
* cppexp.c, cpphash.c, cpphash.h, cpplex.c, cpplib.c,
|
* 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 TRUNCTFDF2_LIBCALL "_U_Qfcnvff_quad_to_dbl"
|
||||||
#define FLOATSITF2_LIBCALL "_U_Qfcnvxf_sgl_to_quad"
|
#define FLOATSITF2_LIBCALL "_U_Qfcnvxf_sgl_to_quad"
|
||||||
#define FLOATDITF2_LIBCALL "_U_Qfcnvxf_dbl_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 FIX_TRUNCTFDI2_LIBCALL "_U_Qfcnvfxt_quad_to_dbl"
|
||||||
#define EQTF2_LIBCALL "_U_Qfeq"
|
#define EQTF2_LIBCALL "_U_Qfeq"
|
||||||
#define NETF2_LIBCALL "_U_Qfne"
|
#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_movb PARAMS ((rtx *, rtx, int, int));
|
||||||
extern const char *output_parallel_movb PARAMS ((rtx *, int));
|
extern const char *output_parallel_movb PARAMS ((rtx *, int));
|
||||||
extern const char *output_parallel_addb 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_millicode_call PARAMS ((rtx, rtx));
|
||||||
extern const char *output_mul_insn PARAMS ((int, rtx));
|
extern const char *output_mul_insn PARAMS ((int, rtx));
|
||||||
extern const char *output_div_insn PARAMS ((rtx *, 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 void hppa_expand_epilogue PARAMS ((void));
|
||||||
extern int hppa_can_use_return_insn_p PARAMS ((void));
|
extern int hppa_can_use_return_insn_p PARAMS ((void));
|
||||||
extern int ior_mask_p PARAMS ((unsigned HOST_WIDE_INT));
|
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
|
#ifdef TREE_CODE
|
||||||
extern int reloc_needed PARAMS ((tree));
|
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 */
|
#endif /* TREE_CODE */
|
||||||
|
|
|
@ -189,6 +189,10 @@ override_options ()
|
||||||
write_symbols = NO_DEBUG;
|
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. */
|
/* Register global variables with the garbage collector. */
|
||||||
pa_add_gc_roots ();
|
pa_add_gc_roots ();
|
||||||
}
|
}
|
||||||
|
@ -1562,6 +1566,25 @@ emit_move_sequence (operands, mode, scratch_reg)
|
||||||
|| ! cint_ok_for_move (INTVAL (operand1)))
|
|| ! cint_ok_for_move (INTVAL (operand1)))
|
||||||
{
|
{
|
||||||
rtx temp;
|
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)
|
if (reload_in_progress || reload_completed)
|
||||||
temp = operand0;
|
temp = operand0;
|
||||||
|
@ -1571,6 +1594,17 @@ emit_move_sequence (operands, mode, scratch_reg)
|
||||||
emit_insn (gen_rtx_SET (VOIDmode, temp,
|
emit_insn (gen_rtx_SET (VOIDmode, temp,
|
||||||
gen_rtx_HIGH (mode, operand1)));
|
gen_rtx_HIGH (mode, operand1)));
|
||||||
operands[1] = gen_rtx_LO_SUM (mode, temp, 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. */
|
/* Now have insn-emit do whatever it normally does. */
|
||||||
|
@ -1729,6 +1763,46 @@ compute_zdepwi_operands (imm, op)
|
||||||
op[2] = len;
|
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
|
/* Output assembler code to perform a doubleword move insn
|
||||||
with operands OPERANDS. */
|
with operands OPERANDS. */
|
||||||
|
|
||||||
|
@ -2264,6 +2338,59 @@ output_and (operands)
|
||||||
return "and %1,%2,%0";
|
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 *
|
const char *
|
||||||
output_ior (operands)
|
output_ior (operands)
|
||||||
rtx *operands;
|
rtx *operands;
|
||||||
|
@ -2292,6 +2419,38 @@ output_ior (operands)
|
||||||
operands[3] = GEN_INT (len);
|
operands[3] = GEN_INT (len);
|
||||||
return "{depi|depwi} -1,%2,%3,%0";
|
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. */
|
/* Output an ascii string. */
|
||||||
void
|
void
|
||||||
|
@ -2676,7 +2835,8 @@ compute_frame_size (size, fregs_live)
|
||||||
|
|
||||||
/* Account for space used by the callee floating point register saves. */
|
/* 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)
|
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)
|
if (fregs_live)
|
||||||
*fregs_live = 1;
|
*fregs_live = 1;
|
||||||
|
@ -2693,8 +2853,9 @@ compute_frame_size (size, fregs_live)
|
||||||
/* Allocate space for the fixed frame marker. This space must be
|
/* Allocate space for the fixed frame marker. This space must be
|
||||||
allocated for any function that makes calls or otherwise allocates
|
allocated for any function that makes calls or otherwise allocates
|
||||||
stack space. */
|
stack space. */
|
||||||
if (! leaf_function_p () || fsize)
|
if (!current_function_is_leaf || fsize)
|
||||||
fsize += 32;
|
fsize += 32;
|
||||||
|
|
||||||
return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
|
return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2796,8 +2957,12 @@ hppa_expand_prologue()
|
||||||
size_rtx = GEN_INT (actual_fsize);
|
size_rtx = GEN_INT (actual_fsize);
|
||||||
|
|
||||||
/* Save RP first. The calling conventions manual states RP will
|
/* Save RP first. The calling conventions manual states RP will
|
||||||
always be stored into the caller's frame at sp-20. */
|
always be stored into the caller's frame at sp-20 or sp - 16
|
||||||
if (regs_ever_live[2] || profile_flag)
|
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);
|
store_reg (2, -20, STACK_POINTER_REGNUM);
|
||||||
|
|
||||||
/* Allocate the local frame and set up the frame pointer if needed. */
|
/* 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
|
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
|
we need to allocate a frame, or can we just omit the save? For
|
||||||
now we'll just omit the save. */
|
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);
|
store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM);
|
||||||
|
|
||||||
/* Profiling code.
|
/* Profiling code.
|
||||||
|
@ -2982,7 +3147,8 @@ hppa_expand_prologue()
|
||||||
/* Now actually save the FP registers. */
|
/* Now actually save the FP registers. */
|
||||||
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
|
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,
|
emit_move_insn (gen_rtx_MEM (DFmode,
|
||||||
gen_rtx_POST_INC (DFmode, tmpreg)),
|
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
|
RP gets used in the return (bv) instruction. This appears to still
|
||||||
be necessary even when we schedule the prologue and epilogue. */
|
be necessary even when we schedule the prologue and epilogue. */
|
||||||
if (frame_pointer_needed
|
if (frame_pointer_needed
|
||||||
|
&& !TARGET_64BIT
|
||||||
&& (regs_ever_live [2] || profile_flag))
|
&& (regs_ever_live [2] || profile_flag))
|
||||||
load_reg (2, -20, FRAME_POINTER_REGNUM);
|
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. */
|
/* No frame pointer, and stack is smaller than 8k. */
|
||||||
else if (! frame_pointer_needed
|
else if (! frame_pointer_needed
|
||||||
&& VAL_14_BITS_P (actual_fsize + 20)
|
&& VAL_14_BITS_P (actual_fsize + 20)
|
||||||
|
@ -3120,7 +3294,8 @@ hppa_expand_epilogue ()
|
||||||
/* Actually do the restores now. */
|
/* Actually do the restores now. */
|
||||||
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
|
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),
|
emit_move_insn (gen_rtx_REG (DFmode, i),
|
||||||
gen_rtx_MEM (DFmode,
|
gen_rtx_MEM (DFmode,
|
||||||
|
@ -3140,6 +3315,7 @@ hppa_expand_epilogue ()
|
||||||
as possible.) */
|
as possible.) */
|
||||||
if (! frame_pointer_needed
|
if (! frame_pointer_needed
|
||||||
&& ! VAL_14_BITS_P (actual_fsize + 20)
|
&& ! VAL_14_BITS_P (actual_fsize + 20)
|
||||||
|
&& ! TARGET_64BIT
|
||||||
&& (regs_ever_live[2] || profile_flag))
|
&& (regs_ever_live[2] || profile_flag))
|
||||||
{
|
{
|
||||||
set_reg_plus_d (STACK_POINTER_REGNUM,
|
set_reg_plus_d (STACK_POINTER_REGNUM,
|
||||||
|
@ -3154,6 +3330,23 @@ hppa_expand_epilogue ()
|
||||||
doesn't set %r1, just %r30. */
|
doesn't set %r1, just %r30. */
|
||||||
load_reg (2, - 20, STACK_POINTER_REGNUM);
|
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
|
/* Reset stack pointer (and possibly frame pointer). The stack
|
||||||
pointer is initially set to fp + 64 to avoid a race condition. */
|
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
|
/* First, we start off with the normal return address pointer from
|
||||||
-20[frameaddr]. */
|
-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
|
/* Get pointer to the instruction stream. We have to mask out the
|
||||||
privilege level from the two low order bits of the return address
|
privilege level from the two low order bits of the return address
|
||||||
|
@ -3824,6 +4020,13 @@ print_operand (file, x, code)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
|
case 'Q':
|
||||||
|
if (GET_CODE (x) == CONST_INT)
|
||||||
|
{
|
||||||
|
fprintf (file, "%d", 64 - (INTVAL (x) & 63));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
abort();
|
||||||
case 'L':
|
case 'L':
|
||||||
if (GET_CODE (x) == CONST_INT)
|
if (GET_CODE (x) == CONST_INT)
|
||||||
{
|
{
|
||||||
|
@ -3838,6 +4041,13 @@ print_operand (file, x, code)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
|
case 'p':
|
||||||
|
if (GET_CODE (x) == CONST_INT)
|
||||||
|
{
|
||||||
|
fprintf (file, "%d", 63 - (INTVAL (x) & 63));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
abort();
|
||||||
case 'P':
|
case 'P':
|
||||||
if (GET_CODE (x) == CONST_INT)
|
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]);
|
fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
|
||||||
return;
|
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:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
if (GET_CODE (x) == REG)
|
if (GET_CODE (x) == REG)
|
||||||
{
|
{
|
||||||
fputs (reg_names [REGNO (x)], file);
|
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);
|
fputs ("L", file);
|
||||||
}
|
}
|
||||||
else if (GET_CODE (x) == MEM)
|
else if (GET_CODE (x) == MEM)
|
||||||
|
@ -3917,12 +4141,12 @@ print_operand (file, x, code)
|
||||||
{
|
{
|
||||||
case PRE_DEC:
|
case PRE_DEC:
|
||||||
case POST_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)]);
|
fprintf (file, "-%d(%s)", size, reg_names [REGNO (base)]);
|
||||||
break;
|
break;
|
||||||
case PRE_INC:
|
case PRE_INC:
|
||||||
case POST_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)]);
|
fprintf (file, "%d(%s)", size, reg_names [REGNO (base)]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -4221,6 +4445,11 @@ output_arg_descriptor (call_insn)
|
||||||
int i, output_flag = 0;
|
int i, output_flag = 0;
|
||||||
int regno;
|
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++)
|
for (i = 0; i < 4; i++)
|
||||||
arg_regs[i] = 0;
|
arg_regs[i] = 0;
|
||||||
|
|
||||||
|
@ -4420,6 +4649,36 @@ hppa_builtin_saveregs ()
|
||||||
else
|
else
|
||||||
offset = current_function_arg_offset_rtx;
|
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. */
|
/* Store general registers on the stack. */
|
||||||
dest = gen_rtx_MEM (BLKmode,
|
dest = gen_rtx_MEM (BLKmode,
|
||||||
plus_constant (current_function_internal_arg_pointer,
|
plus_constant (current_function_internal_arg_pointer,
|
||||||
|
@ -4467,6 +4726,25 @@ hppa_va_arg (valist, type)
|
||||||
HOST_WIDE_INT align, size, ofs;
|
HOST_WIDE_INT align, size, ofs;
|
||||||
tree t, ptr, pptr;
|
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. */
|
/* Compute the rounded size of the type. */
|
||||||
align = PARM_BOUNDARY / BITS_PER_UNIT;
|
align = PARM_BOUNDARY / BITS_PER_UNIT;
|
||||||
size = int_size_in_bytes (type);
|
size = int_size_in_bytes (type);
|
||||||
|
@ -4570,6 +4848,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
||||||
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
||||||
else
|
else
|
||||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||||
|
if (GET_MODE (operands[1]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if (negated)
|
if (negated)
|
||||||
strcat (buf, "%B3");
|
strcat (buf, "%B3");
|
||||||
else
|
else
|
||||||
|
@ -4593,6 +4873,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
||||||
&& nullify)
|
&& nullify)
|
||||||
{
|
{
|
||||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||||
|
if (GET_MODE (operands[1]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if (negated)
|
if (negated)
|
||||||
strcat (buf, "%S3");
|
strcat (buf, "%S3");
|
||||||
else
|
else
|
||||||
|
@ -4609,6 +4891,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
||||||
- insn_addresses[INSN_UID (insn)] - 8))
|
- insn_addresses[INSN_UID (insn)] - 8))
|
||||||
{
|
{
|
||||||
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
strcpy (buf, "{com%I2b,|cmp%I2b,}");
|
||||||
|
if (GET_MODE (operands[1]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if (negated)
|
if (negated)
|
||||||
strcat (buf, "%B3 %2,%r1,%0%#");
|
strcat (buf, "%B3 %2,%r1,%0%#");
|
||||||
else
|
else
|
||||||
|
@ -4617,6 +4901,8 @@ output_cbranch (operands, nullify, length, negated, insn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
|
||||||
|
if (GET_MODE (operands[1]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if (negated)
|
if (negated)
|
||||||
strcat (buf, "%S3");
|
strcat (buf, "%S3");
|
||||||
else
|
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}");
|
strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+20|cmp%I2b,%S3,n %2,%r1,.+20}");
|
||||||
else
|
else
|
||||||
strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+20|cmp%I2b,%B3,n %2,%r1,.+20}");
|
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_asm_insn (buf, operands);
|
||||||
|
|
||||||
/* Output an insn to save %r1. */
|
/* 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}");
|
strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+28|cmp%I2b,%S3,n %2,%r1,.+28}");
|
||||||
else
|
else
|
||||||
strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+28|cmp%I2b,%B3,n %2,%r1,.+28}");
|
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_asm_insn (buf, operands);
|
||||||
|
|
||||||
/* Output an insn to save %r1. */
|
/* Output an insn to save %r1. */
|
||||||
|
@ -4752,6 +5054,10 @@ output_bb (operands, nullify, length, negated, insn, which)
|
||||||
strcpy (buf, "{extrs,|extrw,s,}");
|
strcpy (buf, "{extrs,|extrw,s,}");
|
||||||
else
|
else
|
||||||
strcpy (buf, "bb,");
|
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)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, ">=");
|
strcat (buf, ">=");
|
||||||
|
@ -4780,6 +5086,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
||||||
&& nullify)
|
&& nullify)
|
||||||
{
|
{
|
||||||
strcpy (buf, "bb,");
|
strcpy (buf, "bb,");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, "<");
|
strcat (buf, "<");
|
||||||
|
@ -4800,6 +5108,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
||||||
- insn_addresses[INSN_UID (insn)] - 8))
|
- insn_addresses[INSN_UID (insn)] - 8))
|
||||||
{
|
{
|
||||||
strcpy (buf, "bb,");
|
strcpy (buf, "bb,");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, ">=");
|
strcat (buf, ">=");
|
||||||
|
@ -4813,6 +5123,8 @@ output_bb (operands, nullify, length, negated, insn, which)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy (buf, "{extrs,|extrw,s,}");
|
strcpy (buf, "{extrs,|extrw,s,}");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcpy (buf, "extrd,s,*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, "<");
|
strcat (buf, "<");
|
||||||
|
@ -4890,6 +5202,10 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
||||||
strcpy (buf, "{vextrs,|extrw,s,}");
|
strcpy (buf, "{vextrs,|extrw,s,}");
|
||||||
else
|
else
|
||||||
strcpy (buf, "{bvb,|bb,}");
|
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)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, ">=");
|
strcat (buf, ">=");
|
||||||
|
@ -4918,6 +5234,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
||||||
&& nullify)
|
&& nullify)
|
||||||
{
|
{
|
||||||
strcpy (buf, "{bvb,|bb,}");
|
strcpy (buf, "{bvb,|bb,}");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, "<");
|
strcat (buf, "<");
|
||||||
|
@ -4938,6 +5256,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
||||||
- insn_addresses[INSN_UID (insn)] - 8))
|
- insn_addresses[INSN_UID (insn)] - 8))
|
||||||
{
|
{
|
||||||
strcpy (buf, "{bvb,|bb,}");
|
strcpy (buf, "{bvb,|bb,}");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcat (buf, "*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, ">=");
|
strcat (buf, ">=");
|
||||||
|
@ -4951,6 +5271,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy (buf, "{vextrs,|extrw,s,}");
|
strcpy (buf, "{vextrs,|extrw,s,}");
|
||||||
|
if (GET_MODE (operands[0]) == DImode)
|
||||||
|
strcpy (buf, "extrd,s,*");
|
||||||
if ((which == 0 && negated)
|
if ((which == 0 && negated)
|
||||||
|| (which == 1 && ! negated))
|
|| (which == 1 && ! negated))
|
||||||
strcat (buf, "<");
|
strcat (buf, "<");
|
||||||
|
@ -5206,6 +5528,10 @@ output_millicode_call (insn, call_dest)
|
||||||
rtx xoperands[4];
|
rtx xoperands[4];
|
||||||
rtx seq_insn;
|
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,
|
/* 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$
|
and we're sure that the branch will reach the beginning of the $CODE$
|
||||||
subspace. */
|
subspace. */
|
||||||
|
@ -5216,7 +5542,7 @@ output_millicode_call (insn, call_dest)
|
||||||
&& get_attr_length (insn) == 4))
|
&& get_attr_length (insn) == 4))
|
||||||
{
|
{
|
||||||
xoperands[0] = call_dest;
|
xoperands[0] = call_dest;
|
||||||
output_asm_insn ("{bl|b,l} %0,%%r31%#", xoperands);
|
output_asm_insn ("{bl|b,l} %0,%3%#", xoperands);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5224,7 +5550,6 @@ output_millicode_call (insn, call_dest)
|
||||||
if (get_attr_length (insn) > 4)
|
if (get_attr_length (insn) > 4)
|
||||||
{
|
{
|
||||||
int delay_insn_deleted = 0;
|
int delay_insn_deleted = 0;
|
||||||
rtx xoperands[2];
|
|
||||||
|
|
||||||
/* We need to emit an inline long-call branch. */
|
/* We need to emit an inline long-call branch. */
|
||||||
if (dbr_sequence_length () != 0
|
if (dbr_sequence_length () != 0
|
||||||
|
@ -5247,8 +5572,8 @@ output_millicode_call (insn, call_dest)
|
||||||
|| ! (flag_pic || TARGET_PORTABLE_RUNTIME))
|
|| ! (flag_pic || TARGET_PORTABLE_RUNTIME))
|
||||||
{
|
{
|
||||||
xoperands[0] = call_dest;
|
xoperands[0] = call_dest;
|
||||||
output_asm_insn ("ldil L%%%0,%%r31", xoperands);
|
output_asm_insn ("ldil L%%%0,%3", xoperands);
|
||||||
output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%%r31)", xoperands);
|
output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%3)", xoperands);
|
||||||
output_asm_insn ("nop", xoperands);
|
output_asm_insn ("nop", xoperands);
|
||||||
}
|
}
|
||||||
/* Pure portable runtime doesn't allow be/ble; we also don't have
|
/* 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);
|
output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
|
||||||
|
|
||||||
/* Get our return address into %r31. */
|
/* 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. */
|
/* Jump to our target address in %r29. */
|
||||||
output_asm_insn ("bv,n %%r0(%%r29)", xoperands);
|
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);
|
output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
|
||||||
|
|
||||||
/* Get the return address into %r31. */
|
/* 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. */
|
/* Branch to our target which is in %r1. */
|
||||||
output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
|
output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
|
||||||
|
@ -5330,11 +5655,11 @@ output_millicode_call (insn, call_dest)
|
||||||
xoperands[0] = call_dest;
|
xoperands[0] = call_dest;
|
||||||
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
|
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
|
||||||
if (! VAL_14_BITS_P (distance))
|
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
|
else
|
||||||
{
|
{
|
||||||
xoperands[2] = gen_label_rtx ();
|
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);
|
xoperands);
|
||||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
|
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
|
||||||
CODE_LABEL_NUMBER (xoperands[2]));
|
CODE_LABEL_NUMBER (xoperands[2]));
|
||||||
|
@ -5358,9 +5683,10 @@ extern struct obstack *current_obstack;
|
||||||
CALL_DEST is the routine we are calling. */
|
CALL_DEST is the routine we are calling. */
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
output_call (insn, call_dest)
|
output_call (insn, call_dest, sibcall)
|
||||||
rtx insn;
|
rtx insn;
|
||||||
rtx call_dest;
|
rtx call_dest;
|
||||||
|
int sibcall;
|
||||||
{
|
{
|
||||||
int distance;
|
int distance;
|
||||||
rtx xoperands[4];
|
rtx xoperands[4];
|
||||||
|
@ -5376,7 +5702,8 @@ output_call (insn, call_dest)
|
||||||
&& get_attr_length (insn) == 4))
|
&& get_attr_length (insn) == 4))
|
||||||
{
|
{
|
||||||
xoperands[0] = call_dest;
|
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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5527,8 +5854,17 @@ output_call (insn, call_dest)
|
||||||
/* Branch to our target which is in %r1. */
|
/* Branch to our target which is in %r1. */
|
||||||
output_asm_insn ("bv %%r0(%%r1)", xoperands);
|
output_asm_insn ("bv %%r0(%%r1)", xoperands);
|
||||||
|
|
||||||
/* Copy the return address into %r2 also. */
|
if (sibcall)
|
||||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
{
|
||||||
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
|
@ -5544,8 +5880,17 @@ output_call (insn, call_dest)
|
||||||
output_asm_insn ("{ble|be,l} R%%$$dyncall(%%sr4,%%r2)",
|
output_asm_insn ("{ble|be,l} R%%$$dyncall(%%sr4,%%r2)",
|
||||||
xoperands);
|
xoperands);
|
||||||
|
|
||||||
/* Copy the return pointer into both %r31 and %r2. */
|
if (sibcall)
|
||||||
output_asm_insn ("copy %%r31,%%r2", xoperands);
|
{
|
||||||
|
/* 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));
|
&& 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. */
|
/* Mark ARG (which is really a struct deferred_plabel **) for GC. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -85,7 +85,10 @@ extern int target_flags;
|
||||||
/* compile code for HP-PA 1.1 ("Snake") */
|
/* compile code for HP-PA 1.1 ("Snake") */
|
||||||
|
|
||||||
#define MASK_PA_11 1
|
#define MASK_PA_11 1
|
||||||
|
|
||||||
|
#ifndef TARGET_PA_11
|
||||||
#define TARGET_PA_11 (target_flags & MASK_PA_11)
|
#define TARGET_PA_11 (target_flags & MASK_PA_11)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Disable all FP registers (they all become fixed). This may be necessary
|
/* Disable all FP registers (they all become fixed). This may be necessary
|
||||||
for compiling kernels which perform lazy context switching of FP regs.
|
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
|
/* Generate code for the HPPA 2.0 architecture. TARGET_PA_11 should also be
|
||||||
true when this is true. */
|
true when this is true. */
|
||||||
#define MASK_PA_20 4096
|
#define MASK_PA_20 4096
|
||||||
|
#ifndef TARGET_PA_20
|
||||||
#define TARGET_PA_20 (target_flags & MASK_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.
|
/* Macro to define tables used to set the flags.
|
||||||
This is a list in braces of pairs in braces,
|
This is a list in braces of pairs in braces,
|
||||||
|
@ -248,17 +258,63 @@ extern int target_flags;
|
||||||
((GET_CODE (X) == PLUS ? OFFSET : 0) \
|
((GET_CODE (X) == PLUS ? OFFSET : 0) \
|
||||||
+ (frame_pointer_needed ? 0 : compute_frame_size (get_frame_size (), 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
|
#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_PA_11) == 0
|
||||||
#define CPP_SPEC "%{msnake:-D__hp9000s700 -D_PA_RISC1_1}\
|
#define CPP_CPU_DEFAULT_SPEC "%(cpp_pa10)"
|
||||||
%{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}"
|
|
||||||
#endif
|
#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 */
|
/* Defines for a K&R CC */
|
||||||
|
|
||||||
#define CC1_SPEC "%{pg:} %{p:}"
|
#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';
|
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.
|
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. */
|
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). */
|
/* 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.
|
/* Width in bits of a pointer.
|
||||||
See also the macro `Pmode' defined below. */
|
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,
|
GCC for the PA always rounds its stacks to a 512bit boundary,
|
||||||
but that happens late in the compilation process. */
|
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. */
|
/* 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. */
|
/* Alignment of field after `int : 0' in a structure. */
|
||||||
#define EMPTY_FIELD_BOUNDARY 32
|
#define EMPTY_FIELD_BOUNDARY 32
|
||||||
|
@ -420,17 +480,19 @@ extern int target_flags;
|
||||||
/* Register which holds offset table for position-independent
|
/* Register which holds offset table for position-independent
|
||||||
data references. */
|
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
|
#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED 1
|
||||||
|
|
||||||
/* Register into which we save the PIC_OFFEST_TABLE_REGNUM so that it
|
/* Register into which we save the PIC_OFFEST_TABLE_REGNUM so that it
|
||||||
can be restore across function calls. */
|
can be restore across function calls. */
|
||||||
#define PIC_OFFSET_TABLE_REGNUM_SAVED 4
|
#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
|
#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) \
|
#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
|
/* Register in which address to store a structure value
|
||||||
is passed to a function. */
|
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.
|
`K' is used for values that can be moved with a zdepi insn.
|
||||||
`L' is used for the 5 bit constants.
|
`L' is used for the 5 bit constants.
|
||||||
`M' is used for 0.
|
`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.
|
`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) == 'K' ? zdepi_cint_p (VALUE) \
|
||||||
: (C) == 'L' ? VAL_5_BITS_P (VALUE) \
|
: (C) == 'L' ? VAL_5_BITS_P (VALUE) \
|
||||||
: (C) == 'M' ? (VALUE) == 0 \
|
: (C) == 'M' ? (VALUE) == 0 \
|
||||||
: (C) == 'N' ? ((VALUE) & 0x7ff) == 0 \
|
: (C) == 'N' ? (((VALUE) & (unsigned long)0x7ff) == 0 \
|
||||||
: (C) == 'O' ? (((VALUE) & ((VALUE) + 1)) == 0) \
|
&& (VALUE) == ((((VALUE) & 0xffffffff) ^ (~0x7fffffff)) \
|
||||||
|
+ 0x80000000)) \
|
||||||
|
: (C) == 'O' ? (((VALUE) & ((VALUE) + (long)1)) == 0) \
|
||||||
: (C) == 'P' ? and_mask_p (VALUE) \
|
: (C) == 'P' ? and_mask_p (VALUE) \
|
||||||
: 0)
|
: 0)
|
||||||
|
|
||||||
|
@ -542,11 +608,11 @@ extern int target_flags;
|
||||||
argument, not it's beginning. To get the real offset of the first
|
argument, not it's beginning. To get the real offset of the first
|
||||||
argument, the size of the argument must be added. */
|
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
|
/* When a parameter is passed in a register, stack space is still
|
||||||
allocated for it. */
|
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
|
/* Define this if the above stack space is to be considered part of the
|
||||||
space allocated by the caller. */
|
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.
|
the stack: 16 bytes for register saves, and 32 bytes for magic.
|
||||||
This is the difference between the logical top of stack and the
|
This is the difference between the logical top of stack and the
|
||||||
actual sp. */
|
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) \
|
#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
|
/* Value is 1 if returning from a function call automatically
|
||||||
pops the arguments described by the number-of-args field in the call.
|
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
|
/* 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, ) */
|
the mode is SF or DF. Then the value is returned in fr4 (32, ) */
|
||||||
|
|
||||||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
/* This must perform the same promotions as PROMOTE_MODE, else
|
||||||
gen_rtx_REG (TYPE_MODE (VALTYPE), ((! TARGET_SOFT_FLOAT \
|
PROMOTE_FUNCTION_RETURN will not work correctly. */
|
||||||
&& (TYPE_MODE (VALTYPE) == SFmode || \
|
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||||||
TYPE_MODE (VALTYPE) == DFmode)) ? \
|
gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
|
||||||
32 : 28))
|
&& 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
|
/* Define how to find the value returned by a library function
|
||||||
assuming the value has mode MODE. */
|
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
|
/* 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. */
|
tempted to try and simply it, but I worry about breaking something. */
|
||||||
|
|
||||||
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
||||||
(4 >= ((CUM).words + FUNCTION_ARG_SIZE ((MODE), (TYPE))) \
|
function_arg (&CUM, MODE, TYPE, NAMED, 0)
|
||||||
? (!TARGET_PORTABLE_RUNTIME || (TYPE) == 0 \
|
|
||||||
|| !FLOAT_MODE_P (MODE) || TARGET_SOFT_FLOAT \
|
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
|
||||||
|| (CUM).nargs_prototype > 0) \
|
function_arg (&CUM, MODE, TYPE, NAMED, 1)
|
||||||
? 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)
|
|
||||||
|
|
||||||
/* For an arg passed partly in registers and partly in memory,
|
/* For an arg passed partly in registers and partly in memory,
|
||||||
this is the number of registers used.
|
this is the number of registers used.
|
||||||
For args passed entirely in registers or entirely in memory, zero. */
|
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
|
/* If defined, a C expression that gives the alignment boundary, in
|
||||||
bits, of an argument with the specified mode and type. If it is
|
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 */
|
/* 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) \
|
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
|
||||||
(((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
(TARGET_64BIT \
|
||||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8))
|
? 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) \
|
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
|
||||||
(((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
(TARGET_64BIT \
|
||||||
|| ((MODE) && GET_MODE_SIZE (MODE) > 8))
|
? 0 \
|
||||||
|
: (((TYPE) && int_size_in_bytes (TYPE) > 8) \
|
||||||
|
|| ((MODE) && GET_MODE_SIZE (MODE) > 8)))
|
||||||
|
|
||||||
|
|
||||||
extern struct rtx_def *hppa_compare_op0, *hppa_compare_op1;
|
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
|
It is best to keep this as small as possible to avoid having to
|
||||||
flush multiple lines in the cache. */
|
flush multiple lines in the cache. */
|
||||||
|
|
||||||
#define TRAMPOLINE_TEMPLATE(FILE) \
|
#define TRAMPOLINE_TEMPLATE(FILE) \
|
||||||
{ \
|
{ \
|
||||||
fputs ("\tldw 36(%r22),%r21\n", FILE); \
|
if (! TARGET_64BIT) \
|
||||||
fputs ("\tbb,>=,n %r21,30,.+16\n", FILE); \
|
{ \
|
||||||
if (ASSEMBLER_DIALECT == 0) \
|
fputs ("\tldw 36(%r22),%r21\n", FILE); \
|
||||||
fputs ("\tdepi 0,31,2,%r21\n", FILE); \
|
fputs ("\tbb,>=,n %r21,30,.+16\n", FILE); \
|
||||||
else \
|
if (ASSEMBLER_DIALECT == 0) \
|
||||||
fputs ("\tdepwi 0,31,2,%r21\n", FILE); \
|
fputs ("\tdepi 0,31,2,%r21\n", FILE); \
|
||||||
fputs ("\tldw 4(%r21),%r19\n", FILE); \
|
else \
|
||||||
fputs ("\tldw 0(%r21),%r21\n", FILE); \
|
fputs ("\tdepwi 0,31,2,%r21\n", FILE); \
|
||||||
fputs ("\tldsid (%r21),%r1\n", FILE); \
|
fputs ("\tldw 4(%r21),%r19\n", FILE); \
|
||||||
fputs ("\tmtsp %r1,%sr0\n", FILE); \
|
fputs ("\tldw 0(%r21),%r21\n", FILE); \
|
||||||
fputs ("\tbe 0(%sr0,%r21)\n", FILE); \
|
fputs ("\tldsid (%r21),%r1\n", FILE); \
|
||||||
fputs ("\tldw 40(%r22),%r29\n", FILE); \
|
fputs ("\tmtsp %r1,%sr0\n", FILE); \
|
||||||
fputs ("\t.word 0\n", FILE); \
|
fputs ("\tbe 0(%sr0,%r21)\n", FILE); \
|
||||||
fputs ("\t.word 0\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.
|
/* 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
|
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. */
|
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.
|
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
||||||
FNADDR is an RTX for the address of the function's pure code.
|
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 function address to the trampoline template at offset 12.
|
||||||
Move the static chain value to trampoline template at offset 16. */
|
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)); \
|
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 36)); \
|
||||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (FNADDR)); \
|
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (FNADDR)); \
|
||||||
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 40)); \
|
start_addr = memory_address (Pmode, plus_constant ((TRAMP), 40)); \
|
||||||
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (CXT)); \
|
emit_move_insn (gen_rtx_MEM (Pmode, start_addr), (CXT)); \
|
||||||
/* fdc and fic only use registers for the address to flush, \
|
/* fdc and fic only use registers for the address to flush, \
|
||||||
they do not accept integer displacements. */ \
|
they do not accept integer displacements. */ \
|
||||||
start_addr = force_reg (Pmode, (TRAMP)); \
|
start_addr = force_reg (Pmode, (TRAMP)); \
|
||||||
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
end_addr = force_reg (Pmode, plus_constant ((TRAMP), 32)); \
|
||||||
emit_insn (gen_dcacheflush (start_addr, end_addr)); \
|
emit_insn (gen_dcacheflush (start_addr, end_addr)); \
|
||||||
end_addr = force_reg (Pmode, plus_constant (start_addr, 32)); \
|
end_addr = force_reg (Pmode, plus_constant (start_addr, 32)); \
|
||||||
emit_insn (gen_icacheflush (start_addr, end_addr, start_addr, \
|
emit_insn (gen_icacheflush (start_addr, end_addr, start_addr, \
|
||||||
gen_reg_rtx (Pmode), gen_reg_rtx (Pmode)));\
|
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
|
/* 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
|
/* Include all constant integers and constant doubles, but not
|
||||||
floating-point, except for floating-point zero.
|
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
|
#ifdef NEW_HP_ASSEMBLER
|
||||||
#define LEGITIMATE_CONSTANT_P(X) \
|
#define LEGITIMATE_CONSTANT_P(X) \
|
||||||
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
||||||
|| (X) == CONST0_RTX (GET_MODE (X))) \
|
|| (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))
|
&& !function_label_operand (X, VOIDmode))
|
||||||
#else
|
#else
|
||||||
#define LEGITIMATE_CONSTANT_P(X) \
|
#define LEGITIMATE_CONSTANT_P(X) \
|
||||||
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
|
||||||
|| (X) == CONST0_RTX (GET_MODE (X))) \
|
|| (X) == CONST0_RTX (GET_MODE (X))) \
|
||||||
&& (GET_CODE (X) != LABEL_REF || TARGET_GAS)\
|
&& (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))
|
&& !function_label_operand (X, VOIDmode))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1064,8 +1168,11 @@ extern int may_call_alloca;
|
||||||
&& !(GET_CODE (XEXP (OP, 0)) == PLUS \
|
&& !(GET_CODE (XEXP (OP, 0)) == PLUS \
|
||||||
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
|
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
|
||||||
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT)))\
|
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT)))\
|
||||||
|
: ((C) == 'U' ? \
|
||||||
|
(GET_CODE (OP) == CONST_INT && INTVAL (OP) == 63) \
|
||||||
: ((C) == 'S' ? \
|
: ((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
|
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
|
||||||
and check its validity for a certain class.
|
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
|
doing so avoids losing for loading/storing a FP register at an address
|
||||||
which will not fit in 5 bits. */
|
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 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 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 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 INT_14_BITS(X) VAL_14_BITS_P (INTVAL (X))
|
||||||
|
|
||||||
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
#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
|
/* Higher than the default as we prefer to use simple move insns
|
||||||
(better scheduling and delay slot filling) and because our
|
(better scheduling and delay slot filling) and because our
|
||||||
built-in block move is really a 2X unrolled loop. */
|
built-in block move is really a 2X unrolled loop.
|
||||||
#define MOVE_RATIO 4
|
|
||||||
|
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
|
/* Define if operations between registers always perform the operation
|
||||||
on the full register even if a narrower mode is specified. */
|
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'. */
|
/* When a prototype says `char' or `short', really pass an `int'. */
|
||||||
#define PROMOTE_PROTOTYPES 1
|
#define PROMOTE_PROTOTYPES 1
|
||||||
|
#define PROMOTE_FUNCTION_RETURN 1
|
||||||
|
|
||||||
/* Specify the machine mode that pointers have.
|
/* Specify the machine mode that pointers have.
|
||||||
After generation of rtl, the compiler makes no further distinction
|
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. */
|
/* The number of Pmode words for the setjmp buffer. */
|
||||||
#define JMP_BUF_SIZE 50
|
#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 \
|
#define PREDICATE_CODES \
|
||||||
{"reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
|
{"reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
|
||||||
{"call_operand_address", {LABEL_REF, SYMBOL_REF, 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 20-22 = Temporary Registers
|
||||||
Reg 23-26 = Temporary/Parameter Registers
|
Reg 23-26 = Temporary/Parameter Registers
|
||||||
Reg 27 = Global Data Pointer (hp)
|
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 29 = Temporary/Static Chain/Return Value register #2
|
||||||
Reg 30 = stack pointer
|
Reg 30 = stack pointer
|
||||||
Reg 31 = Temporary/Millicode Return Pointer (hp)
|
Reg 31 = Temporary/Millicode Return Pointer (hp)
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
checking for TARGET_64BIT. */
|
checking for TARGET_64BIT. */
|
||||||
#define TARGET_64BIT 1
|
#define TARGET_64BIT 1
|
||||||
#define TARGET_PA_11 1
|
#define TARGET_PA_11 1
|
||||||
#defien TARGET_PA_20 1
|
#define TARGET_PA_20 1
|
||||||
|
|
Loading…
Reference in New Issue