#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-attr.h"
#include "flags.h"
#include "tree.h"
#include "output.h"
#include "except.h"
#include "expr.h"
#include "optabs.h"
#include "reload.h"
#include "integrate.h"
#include "function.h"
#include "toplev.h"
#include "ggc.h"
#include "recog.h"
#include "predict.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
int
hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
{
enum machine_mode store_mode;
enum machine_mode other_mode;
rtx set;
if (recog_memoized (in_insn) < 0
|| get_attr_type (in_insn) != TYPE_FPSTORE
|| recog_memoized (out_insn) < 0)
return 0;
store_mode = GET_MODE (SET_SRC (PATTERN (in_insn)));
set = single_set (out_insn);
if (!set)
return 0;
other_mode = GET_MODE (SET_SRC (set));
return (GET_MODE_SIZE (store_mode) == GET_MODE_SIZE (other_mode));
}
#ifndef DO_FRAME_NOTES
#ifdef INCOMING_RETURN_ADDR_RTX
#define DO_FRAME_NOTES 1
#else
#define DO_FRAME_NOTES 0
#endif
#endif
static void copy_reg_pointer (rtx, rtx);
static void fix_range (const char *);
static int hppa_address_cost (rtx);
static bool hppa_rtx_costs (rtx, int, int, int *);
static inline rtx force_mode (enum machine_mode, rtx);
static void pa_reorg (void);
static void pa_combine_instructions (void);
static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx);
static int forward_branch_p (rtx);
static int shadd_constant_p (int);
static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *);
static int compute_movmem_length (rtx);
static int compute_clrmem_length (rtx);
static bool pa_assemble_integer (rtx, unsigned int, int);
static void remove_useless_addtr_insns (int);
static void store_reg (int, HOST_WIDE_INT, int);
static void store_reg_modify (int, int, HOST_WIDE_INT);
static void load_reg (int, HOST_WIDE_INT, int);
static void set_reg_plus_d (int, int, HOST_WIDE_INT, int);
static void pa_output_function_prologue (FILE *, HOST_WIDE_INT);
static void update_total_code_bytes (int);
static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT);
static int pa_adjust_cost (rtx, rtx, rtx, int);
static int pa_adjust_priority (rtx, int);
static int pa_issue_rate (void);
static void pa_select_section (tree, int, unsigned HOST_WIDE_INT)
ATTRIBUTE_UNUSED;
static void pa_encode_section_info (tree, rtx, int);
static const char *pa_strip_name_encoding (const char *);
static bool pa_function_ok_for_sibcall (tree, tree);
static void pa_globalize_label (FILE *, const char *)
ATTRIBUTE_UNUSED;
static void pa_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
#if !defined(USE_COLLECT2)
static void pa_asm_out_constructor (rtx, int);
static void pa_asm_out_destructor (rtx, int);
#endif
static void pa_init_builtins (void);
static rtx hppa_builtin_saveregs (void);
static tree hppa_gimplify_va_arg_expr (tree, tree, tree *, tree *);
static bool pa_scalar_mode_supported_p (enum machine_mode);
static void copy_fp_args (rtx) ATTRIBUTE_UNUSED;
static int length_fp_args (rtx) ATTRIBUTE_UNUSED;
static struct deferred_plabel *get_plabel (rtx) ATTRIBUTE_UNUSED;
static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED;
static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED;
static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED;
static inline void pa_file_start_mcount (const char*) ATTRIBUTE_UNUSED;
static void pa_elf_file_start (void) ATTRIBUTE_UNUSED;
static void pa_som_file_start (void) ATTRIBUTE_UNUSED;
static void pa_linux_file_start (void) ATTRIBUTE_UNUSED;
static void pa_hpux64_gas_file_start (void) ATTRIBUTE_UNUSED;
static void pa_hpux64_hpas_file_start (void) ATTRIBUTE_UNUSED;
static void output_deferred_plabels (void);
#ifdef ASM_OUTPUT_EXTERNAL_REAL
static void pa_hpux_file_end (void);
#endif
#ifdef HPUX_LONG_DOUBLE_LIBRARY
static void pa_hpux_init_libfuncs (void);
#endif
static rtx pa_struct_value_rtx (tree, int);
static bool pa_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
static int pa_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
static struct machine_function * pa_init_machine_status (void);
rtx hppa_compare_op0, hppa_compare_op1;
enum cmp_type hppa_branch_type;
enum architecture_type pa_arch;
const char *pa_arch_string;
const char *pa_fixed_range_string;
enum processor_type pa_cpu;
const char *pa_cpu_string;
const char *pa_unix_string;
int flag_pa_unix;
static int gr_saved, fr_saved;
static rtx find_addr_reg (rtx);
unsigned long total_code_bytes;
static int last_address;
struct deferred_plabel GTY(())
{
rtx internal_label;
rtx symbol;
};
static GTY((length ("n_deferred_plabels"))) struct deferred_plabel *
deferred_plabels;
static size_t n_deferred_plabels = 0;
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
#undef TARGET_ASM_ALIGNED_DI_OP
#define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
#undef TARGET_ASM_UNALIGNED_HI_OP
#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_UNALIGNED_SI_OP
#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
#undef TARGET_ASM_UNALIGNED_DI_OP
#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER pa_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE pa_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST pa_adjust_cost
#undef TARGET_SCHED_ADJUST_PRIORITY
#define TARGET_SCHED_ADJUST_PRIORITY pa_adjust_priority
#undef TARGET_SCHED_ISSUE_RATE
#define TARGET_SCHED_ISSUE_RATE pa_issue_rate
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO pa_encode_section_info
#undef TARGET_STRIP_NAME_ENCODING
#define TARGET_STRIP_NAME_ENCODING pa_strip_name_encoding
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL pa_function_ok_for_sibcall
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK pa_asm_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
#undef TARGET_ASM_FILE_END
#ifdef ASM_OUTPUT_EXTERNAL_REAL
#define TARGET_ASM_FILE_END pa_hpux_file_end
#else
#define TARGET_ASM_FILE_END output_deferred_plabels
#endif
#if !defined(USE_COLLECT2)
#undef TARGET_ASM_CONSTRUCTOR
#define TARGET_ASM_CONSTRUCTOR pa_asm_out_constructor
#undef TARGET_ASM_DESTRUCTOR
#define TARGET_ASM_DESTRUCTOR pa_asm_out_destructor
#endif
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS pa_init_builtins
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS hppa_rtx_costs
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hppa_address_cost
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG pa_reorg
#ifdef HPUX_LONG_DOUBLE_LIBRARY
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS pa_hpux_init_libfuncs
#endif
#undef TARGET_PROMOTE_FUNCTION_RETURN
#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY pa_return_in_memory
#undef TARGET_MUST_PASS_IN_STACK
#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE pa_pass_by_reference
#undef TARGET_CALLEE_COPIES
#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES pa_arg_partial_bytes
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
#define TARGET_EXPAND_BUILTIN_SAVEREGS hppa_builtin_saveregs
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR hppa_gimplify_va_arg_expr
#undef TARGET_SCALAR_MODE_SUPPORTED_P
#define TARGET_SCALAR_MODE_SUPPORTED_P pa_scalar_mode_supported_p
struct gcc_target targetm = TARGET_INITIALIZER;
static void
fix_range (const char *const_str)
{
int i, first, last;
char *str, *dash, *comma;
i = strlen (const_str);
str = (char *) alloca (i + 1);
memcpy (str, const_str, i + 1);
while (1)
{
dash = strchr (str, '-');
if (!dash)
{
warning ("value of -mfixed-range must have form REG1-REG2");
return;
}
*dash = '\0';
comma = strchr (dash + 1, ',');
if (comma)
*comma = '\0';
first = decode_reg_name (str);
if (first < 0)
{
warning ("unknown register name: %s", str);
return;
}
last = decode_reg_name (dash + 1);
if (last < 0)
{
warning ("unknown register name: %s", dash + 1);
return;
}
*dash = '-';
if (first > last)
{
warning ("%s-%s is an empty range", str, dash + 1);
return;
}
for (i = first; i <= last; ++i)
fixed_regs[i] = call_used_regs[i] = 1;
if (!comma)
break;
*comma = ',';
str = comma + 1;
}
for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
if (!fixed_regs[i])
break;
if (i > FP_REG_LAST)
target_flags |= MASK_DISABLE_FPREGS;
}
void
override_options (void)
{
if (pa_cpu_string == NULL)
pa_cpu_string = TARGET_SCHED_DEFAULT;
if (! strcmp (pa_cpu_string, "8000"))
{
pa_cpu_string = "8000";
pa_cpu = PROCESSOR_8000;
}
else if (! strcmp (pa_cpu_string, "7100"))
{
pa_cpu_string = "7100";
pa_cpu = PROCESSOR_7100;
}
else if (! strcmp (pa_cpu_string, "700"))
{
pa_cpu_string = "700";
pa_cpu = PROCESSOR_700;
}
else if (! strcmp (pa_cpu_string, "7100LC"))
{
pa_cpu_string = "7100LC";
pa_cpu = PROCESSOR_7100LC;
}
else if (! strcmp (pa_cpu_string, "7200"))
{
pa_cpu_string = "7200";
pa_cpu = PROCESSOR_7200;
}
else if (! strcmp (pa_cpu_string, "7300"))
{
pa_cpu_string = "7300";
pa_cpu = PROCESSOR_7300;
}
else
{
warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
}
if (pa_arch_string && ! strcmp (pa_arch_string, "1.0"))
{
pa_arch_string = "1.0";
pa_arch = ARCHITECTURE_10;
target_flags &= ~(MASK_PA_11 | MASK_PA_20);
}
else if (pa_arch_string && ! strcmp (pa_arch_string, "1.1"))
{
pa_arch_string = "1.1";
pa_arch = ARCHITECTURE_11;
target_flags &= ~MASK_PA_20;
target_flags |= MASK_PA_11;
}
else if (pa_arch_string && ! strcmp (pa_arch_string, "2.0"))
{
pa_arch_string = "2.0";
pa_arch = ARCHITECTURE_20;
target_flags |= MASK_PA_11 | MASK_PA_20;
}
else if (pa_arch_string)
{
warning ("unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
}
if (TARGET_HPUX)
{
if (pa_unix_string == NULL)
pa_unix_string
= TARGET_HPUX_11_11 ? "98" : (TARGET_HPUX_10_10 ? "95" : "93");
if (!strcmp (pa_unix_string, "93"))
flag_pa_unix = 1993;
else if (!strcmp (pa_unix_string, "95"))
flag_pa_unix = 1995;
else if (TARGET_HPUX_11_11)
{
if (!strcmp (pa_unix_string, "98"))
flag_pa_unix = 1998;
else
warning ("unknown -munix= option (%s).\n"
"Valid options are 93, 95 and 98.\n",
pa_unix_string);
}
else if (TARGET_HPUX_10_10)
warning ("unknown -munix= option (%s)."
"\nValid options are 93 and 95.\n",
pa_unix_string);
else
warning ("unknown -munix= option (%s).\nValid option is 93.\n",
pa_unix_string);
}
if (pa_fixed_range_string)
fix_range (pa_fixed_range_string);
if (pa_cpu >= PROCESSOR_8000
|| (! USING_SJLJ_EXCEPTIONS && flag_exceptions)
|| flag_unwind_tables)
target_flags &= ~MASK_JUMP_IN_DELAY;
if (flag_pic && TARGET_PORTABLE_RUNTIME)
{
warning ("PIC code generation is not supported in the portable runtime model\n");
}
if (flag_pic && TARGET_FAST_INDIRECT_CALLS)
{
warning ("PIC code generation is not compatible with fast indirect calls\n");
}
if (! TARGET_GAS && write_symbols != NO_DEBUG)
{
warning ("-g is only supported when using GAS on this processor,");
warning ("-g option disabled");
write_symbols = NO_DEBUG;
}
if (flag_pic == 1 || TARGET_64BIT)
flag_pic = 2;
if (UNITS_PER_WORD == 4)
targetm.asm_out.aligned_op.di = NULL;
if (!TARGET_GAS)
{
targetm.asm_out.unaligned_op.hi = NULL;
targetm.asm_out.unaligned_op.si = NULL;
targetm.asm_out.unaligned_op.di = NULL;
}
init_machine_status = pa_init_machine_status;
}
static void
pa_init_builtins (void)
{
#ifdef DONT_HAVE_FPUTC_UNLOCKED
built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED] = NULL_TREE;
implicit_built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED] = NULL_TREE;
#endif
}
static struct machine_function *
pa_init_machine_status (void)
{
return ggc_alloc_cleared (sizeof (machine_function));
}
static void
copy_reg_pointer (rtx to, rtx from)
{
if (REG_POINTER (from))
mark_reg_pointer (to, REGNO_POINTER_ALIGN (REGNO (from)));
}
int
reg_or_0_operand (rtx op, enum machine_mode mode)
{
return (op == CONST0_RTX (mode) || register_operand (op, mode));
}
int
call_operand_address (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_MODE (op) == word_mode
&& CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
}
int
symbolic_expression_p (rtx x)
{
if (GET_CODE (x) == HIGH)
x = XEXP (x, 0);
return (symbolic_operand (x, VOIDmode));
}
int
symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
int
symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
}
int
reg_or_0_or_nonsymb_mem_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (op == CONST0_RTX (mode))
return 1;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return (!symbolic_memory_operand (op, mode)
&& memory_address_p (mode, XEXP (op, 0)));
}
int
reg_before_reload_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == SUBREG)
return 0;
if (register_operand (op, mode))
return 1;
if (reload_completed
&& memory_operand (op, mode)
&& !symbolic_memory_operand (op, mode))
return 1;
return 0;
}
int
cint_ok_for_move (HOST_WIDE_INT intval)
{
return (CONST_OK_FOR_LETTER_P (intval, 'J')
|| CONST_OK_FOR_LETTER_P (intval, 'N')
|| CONST_OK_FOR_LETTER_P (intval, 'K'));
}
int
indexed_memory_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode)
return 0;
if (reload_completed && GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op) && IS_INDEX_ADDR_P (op));
}
int
move_dest_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op)
&& !IS_INDEX_ADDR_P (op)
&& !IS_LO_SUM_DLT_ADDR_P (op));
}
int
move_src_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) == CONST_INT)
return cint_ok_for_move (INTVAL (op));
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return memory_address_p (mode, XEXP (op, 0));
}
int
prefetch_cc_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
if (op == virtual_incoming_args_rtx
|| op == virtual_stack_vars_rtx
|| op == virtual_stack_dynamic_rtx
|| op == virtual_outgoing_args_rtx
|| op == virtual_cfa_rtx)
return 0;
if (!REG_P (op) && !IS_INDEX_ADDR_P (op))
return 0;
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0)))
return 0;
return memory_address_p (mode, op);
}
int
prefetch_nocc_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0))
&& REG_P (XEXP (op, 1)))
return 0;
return memory_address_p (mode, op);
}
int
reg_or_cint_move_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
return (GET_CODE (op) == CONST_INT && cint_ok_for_move (INTVAL (op)));
}
int
pic_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (!flag_pic)
return 0;
switch (GET_CODE (op))
{
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return (GET_CODE (XEXP (op, 0)) == LABEL_REF
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
int
fp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return reg_renumber && FP_REG_P (op);
}
int
arith_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
}
int
arith11_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
}
int
adddi3_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT
&& (TARGET_64BIT ? INT_14_BITS (op) : INT_11_BITS (op))));
}
int
pre_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);
}
int
post_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);
}
int
arith_double_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == mode
&& VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
&& ((CONST_DOUBLE_HIGH (op) >= 0)
== ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
}
int
ireg_or_int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
|| (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
}
int
ireg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32);
}
int
int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
}
int
uint5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
}
int
int11_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
}
int
uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if HOST_BITS_PER_WIDE_INT > 32
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= 0 && INTVAL (op) < (HOST_WIDE_INT) 1 << 32));
#else
return (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0));
#endif
}
int
arith5_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || int5_operand (op, mode);
}
int
zdepi_cint_p (unsigned HOST_WIDE_INT x)
{
unsigned HOST_WIDE_INT lsb_mask, t;
lsb_mask = x & -x;
t = ((x >> 4) + lsb_mask) & ~(lsb_mask - 1);
return ((t & (t - 1)) == 0);
}
int
and_mask_p (unsigned HOST_WIDE_INT mask)
{
mask = ~mask;
mask += mask & -mask;
return (mask & (mask - 1)) == 0;
}
int
and_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op))));
}
int
ior_mask_p (unsigned HOST_WIDE_INT mask)
{
mask += mask & -mask;
return (mask & (mask - 1)) == 0;
}
int
ior_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op)));
}
int
lhs_lshift_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode);
}
int
lhs_lshift_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
unsigned HOST_WIDE_INT x;
if (GET_CODE (op) != CONST_INT)
return 0;
x = INTVAL (op) >> 4;
return (x & (x + 1)) == 0;
}
int
arith32_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
}
int
pc_or_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
}
rtx
legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
{
rtx pic_ref = orig;
if (pic_label_operand (orig, mode))
{
mark_reg_pointer (reg, BITS_PER_UNIT);
emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
current_function_uses_pic_offset_table = 1;
return reg;
}
if (GET_CODE (orig) == SYMBOL_REF)
{
rtx insn, tmp_reg;
if (reg == 0)
abort ();
tmp_reg = ((reload_in_progress || reload_completed)
? reg : gen_reg_rtx (Pmode));
emit_move_insn (tmp_reg,
gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
gen_rtx_HIGH (word_mode, orig)));
pic_ref
= gen_const_mem (Pmode,
gen_rtx_LO_SUM (Pmode, tmp_reg,
gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, orig),
UNSPEC_DLTIND14R)));
current_function_uses_pic_offset_table = 1;
mark_reg_pointer (reg, BITS_PER_UNIT);
insn = emit_move_insn (reg, pic_ref);
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn));
return reg;
}
else if (GET_CODE (orig) == CONST)
{
rtx base;
if (GET_CODE (XEXP (orig, 0)) == PLUS
&& XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
return orig;
if (reg == 0)
abort ();
if (GET_CODE (XEXP (orig, 0)) == PLUS)
{
base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
base == reg ? 0 : reg);
}
else
abort ();
if (GET_CODE (orig) == CONST_INT)
{
if (INT_14_BITS (orig))
return plus_constant (base, INTVAL (orig));
orig = force_reg (Pmode, orig);
}
pic_ref = gen_rtx_PLUS (Pmode, base, orig);
}
return pic_ref;
}
rtx
hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode)
{
rtx orig = x;
if (!TARGET_NO_SPACE_REGS
&& GET_CODE (x) == PLUS
&& GET_MODE (x) == Pmode
&& REG_P (XEXP (x, 0))
&& REG_P (XEXP (x, 1))
&& REG_POINTER (XEXP (x, 0))
&& !REG_POINTER (XEXP (x, 1)))
return gen_rtx_PLUS (Pmode, XEXP (x, 1), XEXP (x, 0));
if (flag_pic)
return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
{
rtx reg = force_reg (Pmode, XEXP (x, 1));
return force_reg (Pmode, gen_rtx_PLUS (Pmode, reg, XEXP (x, 0)));
}
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& ((GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& !FUNCTION_NAME_P (XSTR (XEXP (x, 0), 0)))
|| GET_CODE (XEXP (x, 0)) == REG))
{
rtx int_part, ptr_reg;
int newoffset;
int offset = INTVAL (XEXP (x, 1));
int mask;
mask = (GET_MODE_CLASS (mode) == MODE_FLOAT
? (TARGET_PA_20 ? 0x3fff : 0x1f) : 0x3fff);
if ((offset & mask) >= ((mask + 1) / 2))
newoffset = (offset & ~ mask) + mask + 1;
else
newoffset = (offset & ~ mask);
if (! VAL_14_BITS_P (newoffset)
&& GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
{
rtx const_part = plus_constant (XEXP (x, 0), newoffset);
rtx tmp_reg
= force_reg (Pmode,
gen_rtx_HIGH (Pmode, const_part));
ptr_reg
= force_reg (Pmode,
gen_rtx_LO_SUM (Pmode,
tmp_reg, const_part));
}
else
{
if (! VAL_14_BITS_P (newoffset))
int_part = force_reg (Pmode, GEN_INT (newoffset));
else
int_part = GEN_INT (newoffset);
ptr_reg = force_reg (Pmode,
gen_rtx_PLUS (Pmode,
force_reg (Pmode, XEXP (x, 0)),
int_part));
}
return plus_constant (ptr_reg, offset - newoffset);
}
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))
&& (OBJECT_P (XEXP (x, 1))
|| GET_CODE (XEXP (x, 1)) == SUBREG)
&& GET_CODE (XEXP (x, 1)) != CONST)
{
int val = INTVAL (XEXP (XEXP (x, 0), 1));
rtx reg1, reg2;
reg1 = XEXP (x, 1);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
reg2 = XEXP (XEXP (x, 0), 0);
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
return force_reg (Pmode, gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode,
reg2,
GEN_INT (val)),
reg1));
}
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
&& shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
&& (mode == SFmode || mode == DFmode))
{
rtx reg1, reg2, base, idx, orig_base;
reg1 = XEXP (XEXP (x, 0), 1);
reg2 = XEXP (x, 1);
base = NULL_RTX;
idx = NULL_RTX;
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
if (GET_CODE (reg1) == REG
&& REG_POINTER (reg1))
{
base = reg1;
orig_base = XEXP (XEXP (x, 0), 1);
idx = gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode,
XEXP (XEXP (XEXP (x, 0), 0), 0),
XEXP (XEXP (XEXP (x, 0), 0), 1)),
XEXP (x, 1));
}
else if (GET_CODE (reg2) == REG
&& REG_POINTER (reg2))
{
base = reg2;
orig_base = XEXP (x, 1);
idx = XEXP (x, 0);
}
if (base == 0)
return orig;
if (GET_CODE (XEXP (idx, 1)) == CONST_INT
&& VAL_14_BITS_P (INTVAL (XEXP (idx, 1))
/ INTVAL (XEXP (XEXP (idx, 0), 1)))
&& INTVAL (XEXP (idx, 1)) % INTVAL (XEXP (XEXP (idx, 0), 1)) == 0)
{
int val = INTVAL (XEXP (idx, 1));
val /= INTVAL (XEXP (XEXP (idx, 0), 1));
reg1 = XEXP (XEXP (idx, 0), 0);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
reg1 = force_reg (Pmode, gen_rtx_PLUS (Pmode, reg1, GEN_INT (val)));
return
force_reg
(Pmode, gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, reg1,
XEXP (XEXP (idx, 0), 1)),
base));
}
if (GET_CODE (XEXP (idx, 1)) == CONST_INT
&& INTVAL (XEXP (idx, 1)) <= 4096
&& INTVAL (XEXP (idx, 1)) >= -4096)
{
int val = INTVAL (XEXP (XEXP (idx, 0), 1));
rtx reg1, reg2;
reg1 = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, XEXP (idx, 1)));
reg2 = XEXP (XEXP (idx, 0), 0);
if (GET_CODE (reg2) != CONST_INT)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
return force_reg (Pmode, gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode,
reg2,
GEN_INT (val)),
reg1));
}
reg1 = XEXP (XEXP (idx, 0), 0);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
reg2 = XEXP (idx, 1);
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
reg1 = force_reg (Pmode,
gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, reg1,
XEXP (XEXP (idx, 0), 1)),
reg2));
return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, reg1));
}
if (GET_CODE (x) == PLUS
&& symbolic_expression_p (XEXP (x, 1)))
{
rtx regx1, regx2, regy1, regy2, y;
y = XEXP (x, 1);
if (GET_CODE (y) == CONST)
y = XEXP (y, 0);
if (GET_CODE (y) == PLUS || GET_CODE (y) == MINUS)
{
if (GET_CODE (XEXP (y, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (x, 0)) == MULT
&& GET_CODE (XEXP (y, 1)) == CONST_INT
&& INTVAL (XEXP (y, 1)) >= -4096
&& INTVAL (XEXP (y, 1)) <= 4095
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
{
int val = INTVAL (XEXP (XEXP (x, 0), 1));
rtx reg1, reg2;
reg1 = XEXP (x, 1);
if (GET_CODE (reg1) != REG)
reg1 = force_reg (Pmode, force_operand (reg1, 0));
reg2 = XEXP (XEXP (x, 0), 0);
if (GET_CODE (reg2) != REG)
reg2 = force_reg (Pmode, force_operand (reg2, 0));
return force_reg (Pmode,
gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode,
reg2,
GEN_INT (val)),
reg1));
}
else if ((mode == DFmode || mode == SFmode)
&& GET_CODE (XEXP (y, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (x, 0)) == MULT
&& GET_CODE (XEXP (y, 1)) == CONST_INT
&& INTVAL (XEXP (y, 1)) % INTVAL (XEXP (XEXP (x, 0), 1)) == 0
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
{
regx1
= force_reg (Pmode, GEN_INT (INTVAL (XEXP (y, 1))
/ INTVAL (XEXP (XEXP (x, 0), 1))));
regx2 = XEXP (XEXP (x, 0), 0);
if (GET_CODE (regx2) != REG)
regx2 = force_reg (Pmode, force_operand (regx2, 0));
regx2 = force_reg (Pmode, gen_rtx_fmt_ee (GET_CODE (y), Pmode,
regx2, regx1));
return
force_reg (Pmode,
gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, regx2,
XEXP (XEXP (x, 0), 1)),
force_reg (Pmode, XEXP (y, 0))));
}
else if (GET_CODE (XEXP (y, 1)) == CONST_INT
&& INTVAL (XEXP (y, 1)) >= -4096
&& INTVAL (XEXP (y, 1)) <= 4095)
{
return orig;
}
else
{
regx1 = force_reg (Pmode, force_operand (XEXP (x, 0), 0));
regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0));
regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0));
regx1 = force_reg (Pmode,
gen_rtx_fmt_ee (GET_CODE (y), Pmode,
regx1, regy2));
return force_reg (Pmode, gen_rtx_PLUS (Pmode, regx1, regy1));
}
}
}
return orig;
}
static int
hppa_address_cost (rtx X)
{
switch (GET_CODE (X))
{
case REG:
case PLUS:
case LO_SUM:
return 1;
case HIGH:
return 2;
default:
return 4;
}
}
static bool
hppa_rtx_costs (rtx x, int code, int outer_code, int *total)
{
switch (code)
{
case CONST_INT:
if (INTVAL (x) == 0)
*total = 0;
else if (INT_14_BITS (x))
*total = 1;
else
*total = 2;
return true;
case HIGH:
*total = 2;
return true;
case CONST:
case LABEL_REF:
case SYMBOL_REF:
*total = 4;
return true;
case CONST_DOUBLE:
if ((x == CONST0_RTX (DFmode) || x == CONST0_RTX (SFmode))
&& outer_code != SET)
*total = 0;
else
*total = 8;
return true;
case MULT:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
*total = COSTS_N_INSNS (3);
else if (TARGET_PA_11 && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT)
*total = COSTS_N_INSNS (8);
else
*total = COSTS_N_INSNS (20);
return true;
case DIV:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
*total = COSTS_N_INSNS (14);
return true;
}
case UDIV:
case MOD:
case UMOD:
*total = COSTS_N_INSNS (60);
return true;
case PLUS:
case MINUS:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
*total = COSTS_N_INSNS (3);
else
*total = COSTS_N_INSNS (1);
return true;
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
*total = COSTS_N_INSNS (1);
return true;
default:
return false;
}
}
static inline rtx
force_mode (enum machine_mode mode, rtx orig)
{
if (mode == GET_MODE (orig))
return orig;
if (REGNO (orig) >= FIRST_PSEUDO_REGISTER)
abort ();
return gen_rtx_REG (mode, REGNO (orig));
}
int
emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
{
register rtx operand0 = operands[0];
register rtx operand1 = operands[1];
register rtx tem;
if (GET_CODE (operand0) == MEM && IS_INDEX_ADDR_P (XEXP (operand0, 0)))
{
if (no_new_pseudos)
abort ();
tem = copy_to_mode_reg (Pmode, XEXP (operand0, 0));
operand0 = replace_equiv_address (operand0, tem);
}
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (operand1) == MEM
&& GET_CODE (XEXP (operand1, 0)) == PLUS
&& REG_P (XEXP (XEXP (operand1, 0), 0))
&& REG_P (XEXP (XEXP (operand1, 0), 1)))
operand1
= replace_equiv_address (operand1,
copy_to_mode_reg (Pmode, XEXP (operand1, 0)));
if (scratch_reg
&& reload_in_progress && GET_CODE (operand0) == REG
&& REGNO (operand0) >= FIRST_PSEUDO_REGISTER)
operand0 = reg_equiv_mem[REGNO (operand0)];
else if (scratch_reg
&& reload_in_progress && GET_CODE (operand0) == SUBREG
&& GET_CODE (SUBREG_REG (operand0)) == REG
&& REGNO (SUBREG_REG (operand0)) >= FIRST_PSEUDO_REGISTER)
{
rtx temp = gen_rtx_SUBREG (GET_MODE (operand0),
reg_equiv_mem [REGNO (SUBREG_REG (operand0))],
SUBREG_BYTE (operand0));
operand0 = alter_subreg (&temp);
}
if (scratch_reg
&& reload_in_progress && GET_CODE (operand1) == REG
&& REGNO (operand1) >= FIRST_PSEUDO_REGISTER)
operand1 = reg_equiv_mem[REGNO (operand1)];
else if (scratch_reg
&& reload_in_progress && GET_CODE (operand1) == SUBREG
&& GET_CODE (SUBREG_REG (operand1)) == REG
&& REGNO (SUBREG_REG (operand1)) >= FIRST_PSEUDO_REGISTER)
{
rtx temp = gen_rtx_SUBREG (GET_MODE (operand1),
reg_equiv_mem [REGNO (SUBREG_REG (operand1))],
SUBREG_BYTE (operand1));
operand1 = alter_subreg (&temp);
}
if (scratch_reg && reload_in_progress && GET_CODE (operand0) == MEM
&& ((tem = find_replacement (&XEXP (operand0, 0)))
!= XEXP (operand0, 0)))
operand0 = gen_rtx_MEM (GET_MODE (operand0), tem);
if (scratch_reg && reload_in_progress && GET_CODE (operand1) == MEM
&& ((tem = find_replacement (&XEXP (operand1, 0)))
!= XEXP (operand1, 0)))
operand1 = gen_rtx_MEM (GET_MODE (operand1), tem);
if (scratch_reg
&& fp_reg_operand (operand0, mode)
&& ((GET_CODE (operand1) == MEM
&& !memory_address_p ((GET_MODE_SIZE (mode) == 4 ? SFmode : DFmode),
XEXP (operand1, 0)))
|| ((GET_CODE (operand1) == SUBREG
&& GET_CODE (XEXP (operand1, 0)) == MEM
&& !memory_address_p ((GET_MODE_SIZE (mode) == 4
? SFmode : DFmode),
XEXP (XEXP (operand1, 0), 0))))))
{
if (GET_CODE (operand1) == SUBREG)
operand1 = XEXP (operand1, 0);
scratch_reg = force_mode (word_mode, scratch_reg);
if (!memory_address_p (Pmode, XEXP (operand1, 0)))
{
emit_move_insn (scratch_reg, XEXP (XEXP (operand1, 0), 1));
emit_move_insn (scratch_reg,
gen_rtx_fmt_ee (GET_CODE (XEXP (operand1, 0)),
Pmode,
XEXP (XEXP (operand1, 0), 0),
scratch_reg));
}
else
emit_move_insn (scratch_reg, XEXP (operand1, 0));
emit_insn (gen_rtx_SET (VOIDmode, operand0,
gen_rtx_MEM (mode, scratch_reg)));
return 1;
}
else if (scratch_reg
&& fp_reg_operand (operand1, mode)
&& ((GET_CODE (operand0) == MEM
&& !memory_address_p ((GET_MODE_SIZE (mode) == 4
? SFmode : DFmode),
XEXP (operand0, 0)))
|| ((GET_CODE (operand0) == SUBREG)
&& GET_CODE (XEXP (operand0, 0)) == MEM
&& !memory_address_p ((GET_MODE_SIZE (mode) == 4
? SFmode : DFmode),
XEXP (XEXP (operand0, 0), 0)))))
{
if (GET_CODE (operand0) == SUBREG)
operand0 = XEXP (operand0, 0);
scratch_reg = force_mode (word_mode, scratch_reg);
if (!memory_address_p (Pmode, XEXP (operand0, 0)))
{
emit_move_insn (scratch_reg, XEXP (XEXP (operand0, 0), 1));
emit_move_insn (scratch_reg, gen_rtx_fmt_ee (GET_CODE (XEXP (operand0,
0)),
Pmode,
XEXP (XEXP (operand0, 0),
0),
scratch_reg));
}
else
emit_move_insn (scratch_reg, XEXP (operand0, 0));
emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (mode, scratch_reg),
operand1));
return 1;
}
else if (scratch_reg
&& CONSTANT_P (operand1)
&& fp_reg_operand (operand0, mode))
{
rtx xoperands[2];
scratch_reg = force_mode (word_mode, scratch_reg);
xoperands[0] = scratch_reg;
xoperands[1] = XEXP (force_const_mem (mode, operand1), 0);
emit_move_sequence (xoperands, Pmode, 0);
emit_insn (gen_rtx_SET (mode, operand0,
gen_rtx_MEM (mode, scratch_reg)));
return 1;
}
else if (scratch_reg
&& GET_CODE (operand0) == REG
&& REGNO (operand0) < FIRST_PSEUDO_REGISTER
&& REGNO_REG_CLASS (REGNO (operand0)) == SHIFT_REGS
&& (GET_CODE (operand1) == MEM
|| GET_CODE (operand1) == CONST_INT
|| (GET_CODE (operand1) == REG
&& FP_REG_CLASS_P (REGNO_REG_CLASS (REGNO (operand1))))))
{
if (GET_CODE (operand1) == MEM
&& !memory_address_p (Pmode, XEXP (operand1, 0)))
{
scratch_reg = force_mode (word_mode, scratch_reg);
emit_move_insn (scratch_reg, XEXP (XEXP (operand1, 0), 1));
emit_move_insn (scratch_reg, gen_rtx_fmt_ee (GET_CODE (XEXP (operand1,
0)),
Pmode,
XEXP (XEXP (operand1, 0),
0),
scratch_reg));
scratch_reg = force_mode (GET_MODE (operand0), scratch_reg);
emit_move_insn (scratch_reg, gen_rtx_MEM (GET_MODE (operand0),
scratch_reg));
}
else
{
scratch_reg = force_mode (GET_MODE (operand0), scratch_reg);
emit_move_insn (scratch_reg, operand1);
}
emit_move_insn (operand0, scratch_reg);
return 1;
}
else if (register_operand (operand0, mode))
{
if (register_operand (operand1, mode)
|| (GET_CODE (operand1) == CONST_INT
&& cint_ok_for_move (INTVAL (operand1)))
|| (operand1 == CONST0_RTX (mode))
|| (GET_CODE (operand1) == HIGH
&& !symbolic_operand (XEXP (operand1, 0), VOIDmode))
|| GET_CODE (operand1) == MEM)
{
if (REG_P (operand0) && REG_P (operand1))
{
if (REG_POINTER (operand1)
&& !REG_POINTER (operand0)
&& !HARD_REGISTER_P (operand0))
copy_reg_pointer (operand0, operand1);
else if (REG_POINTER (operand0)
&& !REG_POINTER (operand1)
&& !HARD_REGISTER_P (operand1))
copy_reg_pointer (operand1, operand0);
}
if (REG_P (operand0)
&& GET_CODE (operand1) == MEM
&& !REG_POINTER (operand0))
{
tree decl = MEM_EXPR (operand1);
if (decl
&& !(flag_argument_noalias > 1
&& TREE_CODE (decl) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL))
{
tree type;
if (TREE_CODE (decl) == COMPONENT_REF)
decl = TREE_OPERAND (decl, 1);
type = TREE_TYPE (decl);
if (TREE_CODE (type) == ARRAY_TYPE)
type = get_inner_array_type (type);
if (POINTER_TYPE_P (type))
{
int align;
type = TREE_TYPE (type);
align = (TYPE_ALIGN_OK (type) ? TYPE_ALIGN (type)
: BITS_PER_UNIT);
mark_reg_pointer (operand0, align);
}
}
}
emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
return 1;
}
}
else if (GET_CODE (operand0) == MEM)
{
if (mode == DFmode && operand1 == CONST0_RTX (mode)
&& !(reload_in_progress || reload_completed))
{
rtx temp = gen_reg_rtx (DFmode);
emit_insn (gen_rtx_SET (VOIDmode, temp, operand1));
emit_insn (gen_rtx_SET (VOIDmode, operand0, temp));
return 1;
}
if (register_operand (operand1, mode) || operand1 == CONST0_RTX (mode))
{
emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
return 1;
}
if (! (reload_in_progress || reload_completed))
{
operands[0] = validize_mem (operand0);
operands[1] = operand1 = force_reg (mode, operand1);
}
}
if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
|| function_label_operand (operand1, mode)
|| (GET_CODE (operand1) == HIGH
&& symbolic_operand (XEXP (operand1, 0), mode)))
{
int ishighonly = 0;
if (GET_CODE (operand1) == HIGH)
{
ishighonly = 1;
operand1 = XEXP (operand1, 0);
}
if (symbolic_operand (operand1, mode))
{
if ((GET_CODE (operand1) == CONST
&& GET_CODE (XEXP (operand1, 0)) == PLUS
&& function_label_operand (XEXP (XEXP (operand1, 0), 0), Pmode))
|| function_label_operand (operand1, mode))
{
rtx temp, const_part;
if (reload_in_progress || reload_completed)
{
scratch_reg = scratch_reg ? scratch_reg : operand0;
scratch_reg = force_mode (word_mode, scratch_reg);
}
else if (flag_pic)
scratch_reg = gen_reg_rtx (Pmode);
if (GET_CODE (operand1) == CONST)
{
const_part = XEXP (XEXP (operand1, 0), 1);
if (GET_CODE (const_part) != CONST_INT)
abort ();
temp = force_const_mem (mode, XEXP (XEXP (operand1, 0), 0));
}
else
{
const_part = NULL_RTX;
temp = force_const_mem (mode, operand1);
}
temp = XEXP (temp, 0);
if (flag_pic)
temp = legitimize_pic_address (temp, mode, scratch_reg);
operands[1] = temp;
emit_move_sequence (operands, mode, scratch_reg);
operands[1] = gen_rtx_MEM (Pmode, operands[0]);
emit_move_sequence (operands, mode, scratch_reg);
if (const_part != NULL_RTX)
expand_inc (operand0, const_part);
return 1;
}
if (flag_pic)
{
rtx temp;
if (reload_in_progress || reload_completed)
{
temp = scratch_reg ? scratch_reg : operand0;
temp = force_mode (word_mode, temp);
}
else
temp = gen_reg_rtx (Pmode);
if (GET_CODE (operand1) == CONST
&& GET_CODE (XEXP (operand1, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (operand1, 0), 1)) == CONST_INT
&& !INT_14_BITS (XEXP (XEXP (operand1, 0), 1))
&& (reload_completed || reload_in_progress)
&& flag_pic)
{
operands[1] = force_const_mem (mode, operand1);
operands[1] = legitimize_pic_address (XEXP (operands[1], 0),
mode, temp);
operands[1] = gen_rtx_MEM (mode, operands[1]);
emit_move_sequence (operands, mode, temp);
}
else
{
operands[1] = legitimize_pic_address (operand1, mode, temp);
if (REG_P (operand0) && REG_P (operands[1]))
copy_reg_pointer (operand0, operands[1]);
emit_insn (gen_rtx_SET (VOIDmode, operand0, operands[1]));
}
}
else
{
rtx temp, set;
if (reload_in_progress || reload_completed)
{
temp = scratch_reg ? scratch_reg : operand0;
temp = force_mode (word_mode, temp);
}
else
temp = gen_reg_rtx (mode);
if (GET_CODE (operand0) == REG
&& REGNO (operand0) >= FIRST_PSEUDO_REGISTER)
mark_reg_pointer (operand0, BITS_PER_UNIT);
if (REGNO (temp) >= FIRST_PSEUDO_REGISTER)
mark_reg_pointer (temp, BITS_PER_UNIT);
if (ishighonly)
set = gen_rtx_SET (mode, operand0, temp);
else
set = gen_rtx_SET (VOIDmode,
operand0,
gen_rtx_LO_SUM (mode, temp, operand1));
emit_insn (gen_rtx_SET (VOIDmode,
temp,
gen_rtx_HIGH (mode, operand1)));
emit_insn (set);
}
return 1;
}
else if (GET_CODE (operand1) != CONST_INT
|| !cint_ok_for_move (INTVAL (operand1)))
{
rtx insn, temp;
rtx op1 = operand1;
HOST_WIDE_INT value = 0;
HOST_WIDE_INT insv = 0;
int insert = 0;
if (GET_CODE (operand1) == CONST_INT)
value = INTVAL (operand1);
if (TARGET_64BIT
&& GET_CODE (operand1) == CONST_INT
&& HOST_BITS_PER_WIDE_INT > 32
&& GET_MODE_BITSIZE (GET_MODE (operand0)) > 32)
{
HOST_WIDE_INT nval;
nval = ((value & (((HOST_WIDE_INT) 2 << 31) - 1))
^ ((HOST_WIDE_INT) 1 << 31)) - ((HOST_WIDE_INT) 1 << 31);
if (value != nval)
{
#if HOST_BITS_PER_WIDE_INT > 32
insv = value >= 0 ? value >> 32 : ~(~value >> 32);
#endif
insert = 1;
value = nval;
operand1 = GEN_INT (nval);
}
}
if (reload_in_progress || reload_completed)
temp = scratch_reg ? scratch_reg : operand0;
else
temp = gen_reg_rtx (mode);
if (GET_CODE (operand1) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& !insert)
{
HOST_WIDE_INT low = value & 0x3fff;
HOST_WIDE_INT high = value & ~ 0x3fff;
if (low >= 0x2000)
{
if (high == 0x7fffc000 || (mode == HImode && high == 0x4000))
high += 0x2000;
else
high += 0x4000;
}
low = value - high;
emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (high)));
operands[1] = gen_rtx_PLUS (mode, temp, GEN_INT (low));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, temp,
gen_rtx_HIGH (mode, operand1)));
operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
}
insn = emit_move_insn (operands[0], operands[1]);
if (insert)
{
if (temp != operand0 && (insv >= 16384 || insv < -16384))
{
operand1 = GEN_INT (insv);
emit_insn (gen_rtx_SET (VOIDmode, temp,
gen_rtx_HIGH (mode, operand1)));
emit_move_insn (temp, gen_rtx_LO_SUM (mode, temp, operand1));
emit_insn (gen_insv (operand0, GEN_INT (32),
const0_rtx, temp));
}
else
{
int len = 5, pos = 27;
while (pos >= 0)
{
HOST_WIDE_INT v5 = ((insv & 31) ^ 16) - 16;
HOST_WIDE_INT sign = v5 < 0;
insv = (insv >= 0 ? insv >> len : ~(~insv >> len));
while (pos > 0 && (insv & 1) == sign)
{
insv = (insv >= 0 ? insv >> 1 : ~(~insv >> 1));
len += 1;
pos -= 1;
}
emit_insn (gen_insv (operand0, GEN_INT (len),
GEN_INT (pos), GEN_INT (v5)));
len = pos > 0 && pos < 5 ? pos : 5;
pos -= len;
}
}
}
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_EQUAL, op1, REG_NOTES (insn));
return 1;
}
}
return 0;
}
int
reloc_needed (tree exp)
{
int reloc = 0;
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
return 1;
case PLUS_EXPR:
case MINUS_EXPR:
reloc = reloc_needed (TREE_OPERAND (exp, 0));
reloc |= reloc_needed (TREE_OPERAND (exp, 1));
break;
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
reloc = reloc_needed (TREE_OPERAND (exp, 0));
break;
case CONSTRUCTOR:
{
register tree link;
for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
if (TREE_VALUE (link) != 0)
reloc |= reloc_needed (TREE_VALUE (link));
}
break;
case ERROR_MARK:
break;
default:
break;
}
return reloc;
}
int
read_only_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (operand) == CONST)
operand = XEXP (XEXP (operand, 0), 0);
if (flag_pic)
{
if (GET_CODE (operand) == SYMBOL_REF)
return SYMBOL_REF_FLAG (operand) && !CONSTANT_POOL_ADDRESS_P (operand);
}
else
{
if (GET_CODE (operand) == SYMBOL_REF)
return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
}
return 1;
}
const char *
singlemove_string (rtx *operands)
{
HOST_WIDE_INT intval;
if (GET_CODE (operands[0]) == MEM)
return "stw %r1,%0";
if (GET_CODE (operands[1]) == MEM)
return "ldw %1,%0";
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
long i;
REAL_VALUE_TYPE d;
if (GET_MODE (operands[1]) != SFmode)
abort ();
REAL_VALUE_FROM_CONST_DOUBLE (d, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (d, i);
operands[1] = GEN_INT (i);
}
if (GET_CODE (operands[1]) == CONST_INT)
{
intval = INTVAL (operands[1]);
if (VAL_14_BITS_P (intval))
return "ldi %1,%0";
else if ((intval & 0x7ff) == 0)
return "ldil L'%1,%0";
else if (zdepi_cint_p (intval))
return "{zdepi %Z1,%0|depwi,z %Z1,%0}";
else
return "ldil L'%1,%0\n\tldo R'%1(%0),%0";
}
return "copy %1,%0";
}
static void
compute_zdepwi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
{
int lsb, len;
for (lsb = 0; lsb < 32; lsb++)
{
if ((imm & 1) != 0)
break;
imm >>= 1;
}
if ((imm & 0x10) == 0)
len = (lsb <= 28) ? 4 : 32 - lsb;
else
{
for (len = 5; len < 32; len++)
{
if ((imm & (1 << len)) == 0)
break;
}
imm = (imm & 0xf) - 0x10;
}
op[0] = imm;
op[1] = 31 - lsb;
op[2] = len;
}
void
compute_zdepdi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
{
HOST_WIDE_INT lsb, len;
for (lsb = 0; lsb < HOST_BITS_PER_WIDE_INT; lsb++)
{
if ((imm & 1) != 0)
break;
imm >>= 1;
}
if ((imm & 0x10) == 0)
len = ((lsb <= HOST_BITS_PER_WIDE_INT - 4)
? 4 : HOST_BITS_PER_WIDE_INT - lsb);
else
{
for (len = 5; len < HOST_BITS_PER_WIDE_INT; len++)
{
if ((imm & ((unsigned HOST_WIDE_INT) 1 << len)) == 0)
break;
}
imm = (imm & 0xf) - 0x10;
}
op[0] = imm;
op[1] = 63 - lsb;
op[2] = len;
}
const char *
output_move_double (rtx *operands)
{
enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx addreg0 = 0, addreg1 = 0;
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1]))
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
if (optype0 != REGOP && optype1 != REGOP)
abort ();
if (optype0 == MEMOP)
{
rtx addr = XEXP (operands[0], 0);
if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
{
rtx high_reg = gen_rtx_SUBREG (SImode, operands[1], 0);
operands[0] = XEXP (addr, 0);
if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
abort ();
if (!reg_overlap_mentioned_p (high_reg, addr))
{
if (GET_CODE (addr) == POST_INC)
return "{stws|stw},ma %1,8(%0)\n\tstw %R1,-4(%0)";
return "{stws|stw},ma %1,-8(%0)\n\tstw %R1,12(%0)";
}
else
abort ();
}
else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
{
rtx high_reg = gen_rtx_SUBREG (SImode, operands[1], 0);
operands[0] = XEXP (addr, 0);
if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
abort ();
if (!reg_overlap_mentioned_p (high_reg, addr))
{
if (GET_CODE (addr) == PRE_INC)
return "{stws|stw},mb %1,8(%0)\n\tstw %R1,4(%0)";
return "{stws|stw},mb %1,-8(%0)\n\tstw %R1,4(%0)";
}
else
abort ();
}
}
if (optype1 == MEMOP)
{
rtx addr = XEXP (operands[1], 0);
if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC)
{
rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
operands[1] = XEXP (addr, 0);
if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
abort ();
if (!reg_overlap_mentioned_p (high_reg, addr))
{
if (GET_CODE (addr) == POST_INC)
return "{ldws|ldw},ma 8(%1),%0\n\tldw -4(%1),%R0";
return "{ldws|ldw},ma -8(%1),%0\n\tldw 12(%1),%R0";
}
else
{
if (GET_CODE (addr) == POST_INC)
return "ldw 4(%1),%R0\n\t{ldws|ldw},ma 8(%1),%0";
return "ldw 4(%1),%R0\n\t{ldws|ldw},ma -8(%1),%0";
}
}
else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
{
rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
operands[1] = XEXP (addr, 0);
if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
abort ();
if (!reg_overlap_mentioned_p (high_reg, addr))
{
if (GET_CODE (addr) == PRE_INC)
return "{ldws|ldw},mb 8(%1),%0\n\tldw 4(%1),%R0";
return "{ldws|ldw},mb -8(%1),%0\n\tldw 4(%1),%R0";
}
else
{
if (GET_CODE (addr) == PRE_INC)
return "ldw 12(%1),%R0\n\t{ldws|ldw},mb 8(%1),%0";
return "ldw -4(%1),%R0\n\t{ldws|ldw},mb -8(%1),%0";
}
}
else if (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 0)) == MULT)
{
rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
if (!reg_overlap_mentioned_p (high_reg, addr))
{
rtx xoperands[3];
xoperands[0] = high_reg;
xoperands[1] = XEXP (addr, 1);
xoperands[2] = XEXP (XEXP (addr, 0), 0);
xoperands[3] = XEXP (XEXP (addr, 0), 1);
output_asm_insn ("{sh%O3addl %2,%1,%0|shladd,l %2,%O3,%1,%0}",
xoperands);
return "ldw 4(%0),%R0\n\tldw 0(%0),%0";
}
else
{
rtx xoperands[3];
xoperands[0] = high_reg;
xoperands[1] = XEXP (addr, 1);
xoperands[2] = XEXP (XEXP (addr, 0), 0);
xoperands[3] = XEXP (XEXP (addr, 0), 1);
output_asm_insn ("{sh%O3addl %2,%1,%R0|shladd,l %2,%O3,%1,%R0}",
xoperands);
return "ldw 0(%R0),%0\n\tldw 4(%R0),%R0";
}
}
}
if (optype0 == MEMOP)
addreg0 = find_addr_reg (XEXP (operands[0], 0));
if (optype1 == MEMOP)
addreg1 = find_addr_reg (XEXP (operands[1], 0));
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adjust_address (operands[0], SImode, 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adjust_address (operands[1], SImode, 4);
else if (optype1 == CNSTOP)
split_double (operands[1], &operands[1], &latehalf[1]);
else
latehalf[1] = operands[1];
if (optype0 == REGOP
&& (optype1 == MEMOP || optype1 == OFFSOP)
&& refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
operands[1], 0))
{
if (addreg1)
output_asm_insn ("ldo 4(%0),%0", &addreg1);
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg1)
output_asm_insn ("ldo -4(%0),%0", &addreg1);
return singlemove_string (operands);
}
if (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (operands[1]) + 1)
{
output_asm_insn (singlemove_string (latehalf), latehalf);
return singlemove_string (operands);
}
output_asm_insn (singlemove_string (operands), operands);
if (addreg0)
output_asm_insn ("ldo 4(%0),%0", &addreg0);
if (addreg1)
output_asm_insn ("ldo 4(%0),%0", &addreg1);
output_asm_insn (singlemove_string (latehalf), latehalf);
if (addreg0)
output_asm_insn ("ldo -4(%0),%0", &addreg0);
if (addreg1)
output_asm_insn ("ldo -4(%0),%0", &addreg1);
return "";
}
const char *
output_fp_move_double (rtx *operands)
{
if (FP_REG_P (operands[0]))
{
if (FP_REG_P (operands[1])
|| operands[1] == CONST0_RTX (GET_MODE (operands[0])))
output_asm_insn ("fcpy,dbl %f1,%0", operands);
else
output_asm_insn ("fldd%F1 %1,%0", operands);
}
else if (FP_REG_P (operands[1]))
{
output_asm_insn ("fstd%F0 %1,%0", operands);
}
else if (operands[1] == CONST0_RTX (GET_MODE (operands[0])))
{
if (GET_CODE (operands[0]) == REG)
{
rtx xoperands[2];
xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
xoperands[0] = operands[0];
output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands);
}
else
abort ();
}
else abort ();
return "";
}
static rtx
find_addr_reg (rtx addr)
{
while (GET_CODE (addr) == PLUS)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
addr = XEXP (addr, 0);
else if (GET_CODE (XEXP (addr, 1)) == REG)
addr = XEXP (addr, 1);
else if (CONSTANT_P (XEXP (addr, 0)))
addr = XEXP (addr, 1);
else if (CONSTANT_P (XEXP (addr, 1)))
addr = XEXP (addr, 0);
else
abort ();
}
if (GET_CODE (addr) == REG)
return addr;
abort ();
}
const char *
output_block_move (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
{
int align = INTVAL (operands[5]);
unsigned long n_bytes = INTVAL (operands[4]);
if (align > (TARGET_64BIT ? 8 : 4))
align = (TARGET_64BIT ? 8 : 4);
switch (align)
{
case 8:
operands[4] = GEN_INT (n_bytes - 16);
output_asm_insn ("ldi %4,%2", operands);
output_asm_insn ("ldd,ma 8(%1),%3", operands);
output_asm_insn ("ldd,ma 8(%1),%6", operands);
output_asm_insn ("std,ma %3,8(%0)", operands);
output_asm_insn ("addib,>= -16,%2,.-12", operands);
output_asm_insn ("std,ma %6,8(%0)", operands);
if (n_bytes % 16 != 0)
{
operands[4] = GEN_INT (n_bytes % 8);
if (n_bytes % 16 >= 8)
output_asm_insn ("ldd,ma 8(%1),%3", operands);
if (n_bytes % 8 != 0)
output_asm_insn ("ldd 0(%1),%6", operands);
if (n_bytes % 16 >= 8)
output_asm_insn ("std,ma %3,8(%0)", operands);
if (n_bytes % 8 != 0)
output_asm_insn ("stdby,e %6,%4(%0)", operands);
}
return "";
case 4:
operands[4] = GEN_INT (n_bytes - 8);
output_asm_insn ("ldi %4,%2", operands);
output_asm_insn ("{ldws|ldw},ma 4(%1),%3", operands);
output_asm_insn ("{ldws|ldw},ma 4(%1),%6", operands);
output_asm_insn ("{stws|stw},ma %3,4(%0)", operands);
output_asm_insn ("addib,>= -8,%2,.-12", operands);
output_asm_insn ("{stws|stw},ma %6,4(%0)", operands);
if (n_bytes % 8 != 0)
{
operands[4] = GEN_INT (n_bytes % 4);
if (n_bytes % 8 >= 4)
output_asm_insn ("{ldws|ldw},ma 4(%1),%3", operands);
if (n_bytes % 4 != 0)
output_asm_insn ("ldw 0(%1),%6", operands);
if (n_bytes % 8 >= 4)
output_asm_insn ("{stws|stw},ma %3,4(%0)", operands);
if (n_bytes % 4 != 0)
output_asm_insn ("{stbys|stby},e %6,%4(%0)", operands);
}
return "";
case 2:
operands[4] = GEN_INT (n_bytes - 4);
output_asm_insn ("ldi %4,%2", operands);
output_asm_insn ("{ldhs|ldh},ma 2(%1),%3", operands);
output_asm_insn ("{ldhs|ldh},ma 2(%1),%6", operands);
output_asm_insn ("{sths|sth},ma %3,2(%0)", operands);
output_asm_insn ("addib,>= -4,%2,.-12", operands);
output_asm_insn ("{sths|sth},ma %6,2(%0)", operands);
if (n_bytes % 4 != 0)
{
if (n_bytes % 4 >= 2)
output_asm_insn ("{ldhs|ldh},ma 2(%1),%3", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("ldb 0(%1),%6", operands);
if (n_bytes % 4 >= 2)
output_asm_insn ("{sths|sth},ma %3,2(%0)", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("stb %6,0(%0)", operands);
}
return "";
case 1:
operands[4] = GEN_INT (n_bytes - 2);
output_asm_insn ("ldi %4,%2", operands);
output_asm_insn ("{ldbs|ldb},ma 1(%1),%3", operands);
output_asm_insn ("{ldbs|ldb},ma 1(%1),%6", operands);
output_asm_insn ("{stbs|stb},ma %3,1(%0)", operands);
output_asm_insn ("addib,>= -2,%2,.-12", operands);
output_asm_insn ("{stbs|stb},ma %6,1(%0)", operands);
if (n_bytes % 2 != 0)
{
output_asm_insn ("ldb 0(%1),%3", operands);
output_asm_insn ("stb %3,0(%0)", operands);
}
return "";
default:
abort ();
}
}
static int
compute_movmem_length (rtx insn)
{
rtx pat = PATTERN (insn);
unsigned int align = INTVAL (XEXP (XVECEXP (pat, 0, 7), 0));
unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));
unsigned int n_insns = 0;
if (align > (TARGET_64BIT ? 8 : 4))
align = (TARGET_64BIT ? 8 : 4);
n_insns = 6;
if (n_bytes % (2 * align) != 0)
{
if ((n_bytes % (2 * align)) >= align)
n_insns += 2;
if ((n_bytes % align) != 0)
n_insns += 2;
}
return n_insns * 4;
}
const char *
output_block_clear (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
{
int align = INTVAL (operands[3]);
unsigned long n_bytes = INTVAL (operands[2]);
if (align > (TARGET_64BIT ? 8 : 4))
align = (TARGET_64BIT ? 8 : 4);
switch (align)
{
case 8:
operands[2] = GEN_INT (n_bytes - 16);
output_asm_insn ("ldi %2,%1", operands);
output_asm_insn ("std,ma %%r0,8(%0)", operands);
output_asm_insn ("addib,>= -16,%1,.-4", operands);
output_asm_insn ("std,ma %%r0,8(%0)", operands);
if (n_bytes % 16 != 0)
{
operands[2] = GEN_INT (n_bytes % 8);
if (n_bytes % 16 >= 8)
output_asm_insn ("std,ma %%r0,8(%0)", operands);
if (n_bytes % 8 != 0)
output_asm_insn ("stdby,e %%r0,%2(%0)", operands);
}
return "";
case 4:
operands[2] = GEN_INT (n_bytes - 8);
output_asm_insn ("ldi %2,%1", operands);
output_asm_insn ("{stws|stw},ma %%r0,4(%0)", operands);
output_asm_insn ("addib,>= -8,%1,.-4", operands);
output_asm_insn ("{stws|stw},ma %%r0,4(%0)", operands);
if (n_bytes % 8 != 0)
{
operands[2] = GEN_INT (n_bytes % 4);
if (n_bytes % 8 >= 4)
output_asm_insn ("{stws|stw},ma %%r0,4(%0)", operands);
if (n_bytes % 4 != 0)
output_asm_insn ("{stbys|stby},e %%r0,%2(%0)", operands);
}
return "";
case 2:
operands[2] = GEN_INT (n_bytes - 4);
output_asm_insn ("ldi %2,%1", operands);
output_asm_insn ("{sths|sth},ma %%r0,2(%0)", operands);
output_asm_insn ("addib,>= -4,%1,.-4", operands);
output_asm_insn ("{sths|sth},ma %%r0,2(%0)", operands);
if (n_bytes % 4 != 0)
{
if (n_bytes % 4 >= 2)
output_asm_insn ("{sths|sth},ma %%r0,2(%0)", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("stb %%r0,0(%0)", operands);
}
return "";
case 1:
operands[2] = GEN_INT (n_bytes - 2);
output_asm_insn ("ldi %2,%1", operands);
output_asm_insn ("{stbs|stb},ma %%r0,1(%0)", operands);
output_asm_insn ("addib,>= -2,%1,.-4", operands);
output_asm_insn ("{stbs|stb},ma %%r0,1(%0)", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("stb %%r0,0(%0)", operands);
return "";
default:
abort ();
}
}
static int
compute_clrmem_length (rtx insn)
{
rtx pat = PATTERN (insn);
unsigned int align = INTVAL (XEXP (XVECEXP (pat, 0, 4), 0));
unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 3), 0));
unsigned int n_insns = 0;
if (align > (TARGET_64BIT ? 8 : 4))
align = (TARGET_64BIT ? 8 : 4);
n_insns = 4;
if (n_bytes % (2 * align) != 0)
{
if ((n_bytes % (2 * align)) >= align)
n_insns++;
if ((n_bytes % align) != 0)
n_insns++;
}
return n_insns * 4;
}
const char *
output_and (rtx *operands)
{
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
{
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
int ls0, ls1, ms0, p, len;
for (ls0 = 0; ls0 < 32; ls0++)
if ((mask & (1 << ls0)) == 0)
break;
for (ls1 = ls0; ls1 < 32; ls1++)
if ((mask & (1 << ls1)) != 0)
break;
for (ms0 = ls1; ms0 < 32; ms0++)
if ((mask & (1 << ms0)) == 0)
break;
if (ms0 != 32)
abort ();
if (ls1 == 32)
{
len = ls0;
if (len == 0)
abort ();
operands[2] = GEN_INT (len);
return "{extru|extrw,u} %1,31,%2,%0";
}
else
{
p = 31 - ls0;
len = ls1 - ls0;
operands[2] = GEN_INT (p);
operands[3] = GEN_INT (len);
return "{depi|depwi} 0,%2,%3,%0";
}
}
else
return "and %1,%2,%0";
}
const char *
output_64bit_and (rtx *operands)
{
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
{
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
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
{
p = 63 - ls0;
len = ls1 - ls0;
operands[2] = GEN_INT (p);
operands[3] = GEN_INT (len);
return "depdi 0,%2,%3,%0";
}
}
else
return "and %1,%2,%0";
}
const char *
output_ior (rtx *operands)
{
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
int bs0, bs1, p, len;
if (INTVAL (operands[2]) == 0)
return "copy %1,%0";
for (bs0 = 0; bs0 < 32; bs0++)
if ((mask & (1 << bs0)) != 0)
break;
for (bs1 = bs0; bs1 < 32; bs1++)
if ((mask & (1 << bs1)) == 0)
break;
if (bs1 != 32 && ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask)
abort ();
p = 31 - bs0;
len = bs1 - bs0;
operands[2] = GEN_INT (p);
operands[3] = GEN_INT (len);
return "{depi|depwi} -1,%2,%3,%0";
}
const char *
output_64bit_ior (rtx *operands)
{
unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
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";
}
static bool
pa_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
if (size == UNITS_PER_WORD
&& aligned_p
&& function_label_operand (x, VOIDmode))
{
fputs (size == 8? "\t.dword\tP%" : "\t.word\tP%", asm_out_file);
output_addr_const (asm_out_file, x);
fputc ('\n', asm_out_file);
return true;
}
return default_assemble_integer (x, size, aligned_p);
}
void
output_ascii (FILE *file, const char *p, int size)
{
int i;
int chars_output;
unsigned char partial_output[16];
fputs ("\t.STRING \"", file);
chars_output = 0;
for (i = 0; i < size; i += 4)
{
int co = 0;
int io = 0;
for (io = 0, co = 0; io < MIN (4, size - i); io++)
{
register unsigned int c = (unsigned char) p[i + io];
if (c == '\"' || c == '\\')
partial_output[co++] = '\\';
if (c >= ' ' && c < 0177)
partial_output[co++] = c;
else
{
unsigned int hexd;
partial_output[co++] = '\\';
partial_output[co++] = 'x';
hexd = c / 16 - 0 + '0';
if (hexd > '9')
hexd -= '9' - 'a' + 1;
partial_output[co++] = hexd;
hexd = c % 16 - 0 + '0';
if (hexd > '9')
hexd -= '9' - 'a' + 1;
partial_output[co++] = hexd;
}
}
if (chars_output + co > 243)
{
fputs ("\"\n\t.STRING \"", file);
chars_output = 0;
}
fwrite (partial_output, 1, (size_t) co, file);
chars_output += co;
co = 0;
}
fputs ("\"\n", file);
}
static void
remove_useless_addtr_insns (int check_notes)
{
rtx insn;
static int pass = 0;
if (optimize > 0)
{
int fcmp_count = 0;
int fbranch_count = 0;
for (insn = get_insns (); insn; insn = next_insn (insn))
{
rtx tmp;
if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
continue;
tmp = PATTERN (insn);
if (GET_CODE (tmp) != SET)
continue;
tmp = SET_DEST (tmp);
if (GET_CODE (tmp) == REG && REGNO (tmp) == 0)
{
fcmp_count++;
continue;
}
tmp = PATTERN (insn);
if (GET_CODE (tmp) == SET
&& SET_DEST (tmp) == pc_rtx
&& GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (tmp), 0)) == NE
&& GET_CODE (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == REG
&& REGNO (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == 0)
{
fbranch_count++;
continue;
}
}
for (insn = get_insns (); insn; insn = next_insn (insn))
{
rtx tmp, next;
if (GET_CODE (insn) != INSN)
continue;
tmp = PATTERN (insn);
if (GET_CODE (tmp) != SET)
continue;
tmp = SET_DEST (tmp);
if (GET_CODE (tmp) != REG || REGNO (tmp) != 0)
continue;
next = next_insn (insn);
while (next)
{
if (GET_CODE (next) == JUMP_INSN
|| GET_CODE (next) == CALL_INSN
|| GET_CODE (next) == CODE_LABEL)
break;
if (GET_CODE (next) == INSN
&& GET_CODE (PATTERN (next)) == SET
&& GET_CODE (SET_DEST (PATTERN (next))) == REG
&& REGNO (SET_DEST (PATTERN (next))) == 0)
break;
next = next_insn (next);
}
if (next
&& GET_CODE (next) == JUMP_INSN)
{
rtx pattern = PATTERN (next);
if (GET_CODE (pattern) == SET
&& SET_DEST (pattern) == pc_rtx
&& GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE
&& GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG
&& REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0
&& GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC
&& (fcmp_count == fbranch_count
|| (check_notes
&& find_regno_note (next, REG_DEAD, 0))))
{
tmp = XEXP (SET_SRC (pattern), 1);
XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2);
XEXP (SET_SRC (pattern), 2) = tmp;
INSN_CODE (next) = -1;
tmp = PATTERN (insn);
PUT_CODE (XEXP (tmp, 1),
(reverse_condition_maybe_unordered
(GET_CODE (XEXP (tmp, 1)))));
}
}
}
}
pass = !pass;
}
static HOST_WIDE_INT actual_fsize, local_fsize;
static int save_fregs;
static void
store_reg (int reg, HOST_WIDE_INT disp, int base)
{
rtx insn, dest, src, basereg;
src = gen_rtx_REG (word_mode, reg);
basereg = gen_rtx_REG (Pmode, base);
if (VAL_14_BITS_P (disp))
{
dest = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
insn = emit_move_insn (dest, src);
}
else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
{
rtx delta = GEN_INT (disp);
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg, delta);
emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
dest = gen_rtx_MEM (word_mode, tmpreg);
insn = emit_move_insn (dest, src);
if (DO_FRAME_NOTES)
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode,
gen_rtx_PLUS (word_mode, basereg,
delta)),
src),
REG_NOTES (insn));
}
}
else
{
rtx delta = GEN_INT (disp);
rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg, high);
dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
insn = emit_move_insn (dest, src);
if (DO_FRAME_NOTES)
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode,
gen_rtx_PLUS (word_mode, basereg,
delta)),
src),
REG_NOTES (insn));
}
}
if (DO_FRAME_NOTES)
RTX_FRAME_RELATED_P (insn) = 1;
}
static void
store_reg_modify (int base, int reg, HOST_WIDE_INT mod)
{
rtx insn, basereg, srcreg, delta;
if (!VAL_14_BITS_P (mod))
abort ();
basereg = gen_rtx_REG (Pmode, base);
srcreg = gen_rtx_REG (word_mode, reg);
delta = GEN_INT (mod);
insn = emit_insn (gen_post_store (basereg, srcreg, delta));
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
if (reg != 1)
{
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
}
else
{
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, basereg,
gen_rtx_PLUS (word_mode, basereg, delta)),
REG_NOTES (insn));
}
}
}
static void
set_reg_plus_d (int reg, int base, HOST_WIDE_INT disp, int note)
{
rtx insn;
if (VAL_14_BITS_P (disp))
{
insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
plus_constant (gen_rtx_REG (Pmode, base), disp));
}
else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
{
rtx basereg = gen_rtx_REG (Pmode, base);
rtx delta = GEN_INT (disp);
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg, delta);
insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
gen_rtx_PLUS (Pmode, tmpreg, basereg));
}
else
{
rtx basereg = gen_rtx_REG (Pmode, base);
rtx delta = GEN_INT (disp);
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg,
gen_rtx_PLUS (Pmode, basereg,
gen_rtx_HIGH (Pmode, delta)));
insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
gen_rtx_LO_SUM (Pmode, tmpreg, delta));
}
if (DO_FRAME_NOTES && note)
RTX_FRAME_RELATED_P (insn) = 1;
}
HOST_WIDE_INT
compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
{
int freg_saved = 0;
int i, j;
size = (size + UNITS_PER_WORD - 1) & ~(UNITS_PER_WORD - 1);
if (size || frame_pointer_needed)
size += STARTING_FRAME_OFFSET;
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i;
for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
continue;
size += i * UNITS_PER_WORD;
}
for (i = 18, j = frame_pointer_needed ? 4 : 3; i >= j; i--)
if (regs_ever_live[i])
size += UNITS_PER_WORD;
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
if (regs_ever_live[i]
|| (!TARGET_64BIT && regs_ever_live[i + 1]))
{
freg_saved = 1;
size += 8;
}
if (freg_saved)
{
size = (size + 7) & ~7;
if (fregs_live)
*fregs_live = 1;
}
size += current_function_outgoing_args_size;
if (!current_function_is_leaf || size)
size += TARGET_64BIT ? 48 : 32;
return ((size + PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1)
& ~(PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1));
}
static void
pa_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
ASM_OUTPUT_LABEL (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
fputs ("\t.PROC\n", file);
fprintf (file, "\t.CALLINFO FRAME=" HOST_WIDE_INT_PRINT_DEC, actual_fsize);
if (regs_ever_live[2])
fputs (",CALLS,SAVE_RP", file);
else
fputs (",NO_CALLS", file);
if (frame_pointer_needed)
fputs (",SAVE_SP", file);
if (gr_saved)
fprintf (file, ",ENTRY_GR=%d", gr_saved + 2);
if (fr_saved)
fprintf (file, ",ENTRY_FR=%d", fr_saved + 11);
fputs ("\n\t.ENTRY\n", file);
remove_useless_addtr_insns (0);
}
void
hppa_expand_prologue (void)
{
int merge_sp_adjust_with_store = 0;
HOST_WIDE_INT size = get_frame_size ();
HOST_WIDE_INT offset;
int i;
rtx insn, tmpreg;
gr_saved = 0;
fr_saved = 0;
save_fregs = 0;
local_fsize = (size + UNITS_PER_WORD - 1) & ~(UNITS_PER_WORD - 1);
if (local_fsize || frame_pointer_needed)
local_fsize += STARTING_FRAME_OFFSET;
actual_fsize = compute_frame_size (size, &save_fregs);
tmpreg = gen_rtx_REG (word_mode, 1);
if (regs_ever_live[2] || current_function_calls_eh_return)
store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
if (actual_fsize != 0)
{
if (frame_pointer_needed)
{
insn = emit_move_insn (tmpreg, frame_pointer_rtx);
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode,
gen_rtx_MEM (word_mode, stack_pointer_rtx),
frame_pointer_rtx),
REG_NOTES (insn));
}
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
if (DO_FRAME_NOTES)
RTX_FRAME_RELATED_P (insn) = 1;
if (VAL_14_BITS_P (actual_fsize))
store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
else
{
HOST_WIDE_INT adjust1 = 8192 - 64;
HOST_WIDE_INT adjust2 = actual_fsize - adjust1;
store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
adjust2, 1);
}
if (TARGET_HPUX_UNWIND_LIBRARY)
{
rtx addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx,
GEN_INT (TARGET_64BIT ? -8 : -4));
emit_move_insn (gen_rtx_MEM (word_mode, addr),
frame_pointer_rtx);
}
else
emit_insn (gen_blockage ());
}
else
{
if (VAL_14_BITS_P (actual_fsize) && local_fsize == 0)
merge_sp_adjust_with_store = 1;
else
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
actual_fsize, 1);
}
}
if (frame_pointer_needed)
{
offset = local_fsize;
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
store_reg (regno, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
store_reg (i, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
gr_saved++;
}
gr_saved++;
}
else
{
offset = local_fsize - actual_fsize;
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
if (merge_sp_adjust_with_store)
{
store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
merge_sp_adjust_with_store = 0;
}
else
store_reg (regno, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
if (merge_sp_adjust_with_store)
{
store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
merge_sp_adjust_with_store = 0;
}
else
store_reg (i, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
gr_saved++;
}
if (merge_sp_adjust_with_store)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
actual_fsize, 1);
}
if (flag_pic && actual_fsize != 0 && !TARGET_64BIT)
{
rtx addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx, GEN_INT (-32));
emit_move_insn (gen_rtx_MEM (word_mode, addr), pic_offset_table_rtx);
}
offset = (offset + 7) & ~7;
if (save_fregs)
{
rtx base;
if (frame_pointer_needed)
{
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
base = frame_pointer_rtx;
}
else
{
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
base = stack_pointer_rtx;
}
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
{
if (regs_ever_live[i]
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
{
rtx addr, insn, reg;
addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
reg = gen_rtx_REG (DFmode, i);
insn = emit_move_insn (addr, reg);
if (DO_FRAME_NOTES)
{
RTX_FRAME_RELATED_P (insn) = 1;
if (TARGET_64BIT)
{
rtx mem = gen_rtx_MEM (DFmode,
plus_constant (base, offset));
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, mem, reg),
REG_NOTES (insn));
}
else
{
rtx meml = gen_rtx_MEM (SFmode,
plus_constant (base, offset));
rtx memr = gen_rtx_MEM (SFmode,
plus_constant (base, offset + 4));
rtx regl = gen_rtx_REG (SFmode, i);
rtx regr = gen_rtx_REG (SFmode, i + 1);
rtx setl = gen_rtx_SET (VOIDmode, meml, regl);
rtx setr = gen_rtx_SET (VOIDmode, memr, regr);
rtvec vec;
RTX_FRAME_RELATED_P (setl) = 1;
RTX_FRAME_RELATED_P (setr) = 1;
vec = gen_rtvec (2, setl, setr);
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SEQUENCE (VOIDmode, vec),
REG_NOTES (insn));
}
}
offset += GET_MODE_SIZE (DFmode);
fr_saved++;
}
}
}
}
static void
load_reg (int reg, HOST_WIDE_INT disp, int base)
{
rtx dest = gen_rtx_REG (word_mode, reg);
rtx basereg = gen_rtx_REG (Pmode, base);
rtx src;
if (VAL_14_BITS_P (disp))
src = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
{
rtx delta = GEN_INT (disp);
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg, delta);
if (TARGET_DISABLE_INDEXING)
{
emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
src = gen_rtx_MEM (word_mode, tmpreg);
}
else
src = gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, tmpreg, basereg));
}
else
{
rtx delta = GEN_INT (disp);
rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
rtx tmpreg = gen_rtx_REG (Pmode, 1);
emit_move_insn (tmpreg, high);
src = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
}
emit_move_insn (dest, src);
}
static void
update_total_code_bytes (int nbytes)
{
if ((TARGET_PORTABLE_RUNTIME || !TARGET_GAS || !TARGET_SOM)
&& !IN_NAMED_SECTION_P (cfun->decl))
{
if (INSN_ADDRESSES_SET_P ())
{
unsigned long old_total = total_code_bytes;
total_code_bytes += nbytes;
if (old_total > total_code_bytes)
total_code_bytes = -1;
}
else
total_code_bytes = -1;
}
}
static void
pa_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
rtx insn = get_last_insn ();
last_address = 0;
if (GET_CODE (insn) == NOTE)
insn = prev_real_insn (insn);
if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
if (insn && GET_CODE (insn) == CALL_INSN)
{
fputs ("\tnop\n", file);
last_address += 4;
}
fputs ("\t.EXIT\n\t.PROCEND\n", file);
if (TARGET_SOM && TARGET_GAS)
{
forget_section ();
}
if (INSN_ADDRESSES_SET_P ())
{
insn = get_last_nonnote_insn ();
last_address += INSN_ADDRESSES (INSN_UID (insn));
if (INSN_P (insn))
last_address += insn_default_length (insn);
last_address = ((last_address + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
& ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
}
update_total_code_bytes (last_address);
}
void
hppa_expand_epilogue (void)
{
rtx tmpreg;
HOST_WIDE_INT offset;
HOST_WIDE_INT ret_off = 0;
int i;
int merge_sp_adjust_with_load = 0;
tmpreg = gen_rtx_REG (word_mode, 1);
if (regs_ever_live [2] || current_function_calls_eh_return)
{
ret_off = TARGET_64BIT ? -16 : -20;
if (frame_pointer_needed)
{
load_reg (2, ret_off, FRAME_POINTER_REGNUM);
ret_off = 0;
}
else
{
if (VAL_14_BITS_P (ret_off - actual_fsize))
{
load_reg (2, ret_off - actual_fsize, STACK_POINTER_REGNUM);
ret_off = 0;
}
}
}
if (frame_pointer_needed)
{
offset = local_fsize;
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
load_reg (regno, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 4; i--)
if (regs_ever_live[i] && ! call_used_regs[i])
{
load_reg (i, offset, FRAME_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
else
{
offset = local_fsize - actual_fsize;
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
unsigned int i, regno;
for (i = 0; ; ++i)
{
regno = EH_RETURN_DATA_REGNO (i);
if (regno == INVALID_REGNUM)
break;
if (merge_sp_adjust_with_load == 0
&& local_fsize == 0
&& VAL_14_BITS_P (-actual_fsize))
merge_sp_adjust_with_load = regno;
else
load_reg (regno, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
for (i = 18; i >= 3; i--)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
if (merge_sp_adjust_with_load == 0
&& local_fsize == 0
&& VAL_14_BITS_P (-actual_fsize))
merge_sp_adjust_with_load = i;
else
load_reg (i, offset, STACK_POINTER_REGNUM);
offset += UNITS_PER_WORD;
}
}
}
offset = (offset + 7) & ~7;
if (save_fregs)
{
if (frame_pointer_needed)
set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
else
set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
if (regs_ever_live[i]
|| (! TARGET_64BIT && regs_ever_live[i + 1]))
{
rtx src = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
rtx dest = gen_rtx_REG (DFmode, i);
emit_move_insn (dest, src);
}
}
emit_insn (gen_blockage ());
if (frame_pointer_needed)
{
rtx delta = GEN_INT (-64);
set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64, 0);
emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx, delta));
}
else if (merge_sp_adjust_with_load)
{
rtx delta = GEN_INT (-actual_fsize);
rtx dest = gen_rtx_REG (word_mode, merge_sp_adjust_with_load);
emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
}
else if (actual_fsize != 0)
set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
- actual_fsize, 0);
if (ret_off != 0)
load_reg (2, ret_off, STACK_POINTER_REGNUM);
if (DO_FRAME_NOTES && current_function_calls_eh_return)
{
rtx sa = EH_RETURN_STACKADJ_RTX;
emit_insn (gen_blockage ());
emit_insn (TARGET_64BIT
? gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
: gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
}
}
rtx
hppa_pic_save_rtx (void)
{
return get_hard_reg_initial_val (word_mode, PIC_OFFSET_TABLE_REGNUM);
}
void
hppa_profile_hook (int label_no)
{
rtx reg = gen_reg_rtx (SImode);
rtx label_rtx = gen_label_rtx ();
rtx begin_label_rtx, call_insn;
char begin_label_name[16];
ASM_GENERATE_INTERNAL_LABEL (begin_label_name, FUNC_BEGIN_PROLOG_LABEL,
label_no);
begin_label_rtx = gen_rtx_SYMBOL_REF (SImode, ggc_strdup (begin_label_name));
if (TARGET_64BIT)
emit_move_insn (arg_pointer_rtx,
gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
GEN_INT (64)));
emit_move_insn (gen_rtx_REG (word_mode, 26), gen_rtx_REG (word_mode, 2));
if (TARGET_PA_20)
emit_insn (gen_lcla2 (reg, label_rtx));
else
emit_insn (gen_lcla1 (reg, label_rtx));
emit_insn (gen_load_offset_label_address (gen_rtx_REG (SImode, 25),
reg, begin_label_rtx, label_rtx));
#ifndef NO_PROFILE_COUNTERS
{
rtx count_label_rtx, addr, r24;
char count_label_name[16];
ASM_GENERATE_INTERNAL_LABEL (count_label_name, "LP", label_no);
count_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (count_label_name));
addr = force_reg (Pmode, count_label_rtx);
r24 = gen_rtx_REG (Pmode, 24);
emit_move_insn (r24, addr);
call_insn =
emit_call_insn (gen_call (gen_rtx_MEM (Pmode,
gen_rtx_SYMBOL_REF (Pmode,
"_mcount")),
GEN_INT (TARGET_64BIT ? 24 : 12)));
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), r24);
}
#else
call_insn =
emit_call_insn (gen_call (gen_rtx_MEM (Pmode,
gen_rtx_SYMBOL_REF (Pmode,
"_mcount")),
GEN_INT (TARGET_64BIT ? 16 : 8)));
#endif
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 25));
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), gen_rtx_REG (SImode, 26));
REG_NOTES (call_insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, REG_NOTES (call_insn));
}
rtx
return_addr_rtx (int count, rtx frameaddr)
{
rtx label;
rtx rp;
rtx saved_rp;
rtx ins;
if (count != 0)
return NULL_RTX;
rp = get_hard_reg_initial_val (Pmode, 2);
if (TARGET_64BIT || TARGET_NO_SPACE_REGS)
return rp;
saved_rp = gen_reg_rtx (Pmode);
emit_move_insn (saved_rp, rp);
ins = copy_to_reg (gen_rtx_AND (Pmode, rp, MASK_RETURN_ADDR));
label = gen_label_rtx ();
emit_cmp_insn (gen_rtx_MEM (SImode, ins), GEN_INT (0x4bc23fd1), NE,
NULL_RTX, SImode, 1);
emit_jump_insn (gen_bne (label));
emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 4)),
GEN_INT (0x004010a1), NE, NULL_RTX, SImode, 1);
emit_jump_insn (gen_bne (label));
emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 8)),
GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1);
emit_jump_insn (gen_bne (label));
emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)),
GEN_INT (0xe0400002), NE, NULL_RTX, SImode, 1);
emit_jump_insn (gen_bne (label));
emit_move_insn (saved_rp,
gen_rtx_MEM (Pmode,
memory_address (Pmode,
plus_constant (frameaddr,
-24))));
emit_label (label);
return saved_rp;
}
int
hppa_can_use_return_insn_p (void)
{
return (reload_completed
&& (compute_frame_size (get_frame_size (), 0) ? 0 : 1)
&& ! regs_ever_live[2]
&& ! frame_pointer_needed);
}
void
emit_bcond_fp (enum rtx_code code, rtx operand0)
{
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_fmt_ee (code,
VOIDmode,
gen_rtx_REG (CCFPmode, 0),
const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, operand0),
pc_rtx)));
}
rtx
gen_cmp_fp (enum rtx_code code, rtx operand0, rtx operand1)
{
return gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0),
gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1));
}
static int
pa_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
{
enum attr_type attr_type;
if (pa_cpu >= PROCESSOR_8000 || REG_NOTE_KIND (link) == 0)
return cost;
if (! recog_memoized (insn))
return 0;
attr_type = get_attr_type (insn);
if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
{
if (attr_type == TYPE_FPLOAD)
{
rtx pat = PATTERN (insn);
rtx dep_pat = PATTERN (dep_insn);
if (GET_CODE (pat) == PARALLEL)
{
pat = XVECEXP (pat, 0, 0);
}
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return 0;
if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
{
if (! recog_memoized (dep_insn))
return 0;
switch (get_attr_type (dep_insn))
{
case TYPE_FPALU:
case TYPE_FPMULSGL:
case TYPE_FPMULDBL:
case TYPE_FPDIVSGL:
case TYPE_FPDIVDBL:
case TYPE_FPSQRTSGL:
case TYPE_FPSQRTDBL:
return insn_default_latency (dep_insn) - 1;
default:
return 0;
}
}
}
else if (attr_type == TYPE_FPALU)
{
rtx pat = PATTERN (insn);
rtx dep_pat = PATTERN (dep_insn);
if (GET_CODE (pat) == PARALLEL)
{
pat = XVECEXP (pat, 0, 0);
}
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return 0;
if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
{
if (! recog_memoized (dep_insn))
return 0;
switch (get_attr_type (dep_insn))
{
case TYPE_FPDIVSGL:
case TYPE_FPDIVDBL:
case TYPE_FPSQRTSGL:
case TYPE_FPSQRTDBL:
return insn_default_latency (dep_insn) - 2;
default:
return 0;
}
}
}
return 0;
}
else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
{
if (attr_type == TYPE_FPLOAD)
{
rtx pat = PATTERN (insn);
rtx dep_pat = PATTERN (dep_insn);
if (GET_CODE (pat) == PARALLEL)
{
pat = XVECEXP (pat, 0, 0);
}
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return 0;
if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
{
if (! recog_memoized (dep_insn))
return 0;
switch (get_attr_type (dep_insn))
{
case TYPE_FPALU:
case TYPE_FPMULSGL:
case TYPE_FPMULDBL:
case TYPE_FPDIVSGL:
case TYPE_FPDIVDBL:
case TYPE_FPSQRTSGL:
case TYPE_FPSQRTDBL:
return insn_default_latency (dep_insn) - 1;
default:
return 0;
}
}
}
else if (attr_type == TYPE_FPALU)
{
rtx pat = PATTERN (insn);
rtx dep_pat = PATTERN (dep_insn);
if (GET_CODE (pat) == PARALLEL)
{
pat = XVECEXP (pat, 0, 0);
}
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return 0;
if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
{
if (! recog_memoized (dep_insn))
return 0;
switch (get_attr_type (dep_insn))
{
case TYPE_FPDIVSGL:
case TYPE_FPDIVDBL:
case TYPE_FPSQRTSGL:
case TYPE_FPSQRTDBL:
return insn_default_latency (dep_insn) - 2;
default:
return 0;
}
}
}
return 0;
}
else
abort ();
}
static int
pa_adjust_priority (rtx insn, int priority)
{
rtx set = single_set (insn);
rtx src, dest;
if (set)
{
src = SET_SRC (set);
dest = SET_DEST (set);
if (GET_CODE (src) == LO_SUM
&& symbolic_operand (XEXP (src, 1), VOIDmode)
&& ! read_only_operand (XEXP (src, 1), VOIDmode))
priority >>= 3;
else if (GET_CODE (src) == MEM
&& GET_CODE (XEXP (src, 0)) == LO_SUM
&& symbolic_operand (XEXP (XEXP (src, 0), 1), VOIDmode)
&& ! read_only_operand (XEXP (XEXP (src, 0), 1), VOIDmode))
priority >>= 1;
else if (GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == LO_SUM
&& symbolic_operand (XEXP (XEXP (dest, 0), 1), VOIDmode)
&& ! read_only_operand (XEXP (XEXP (dest, 0), 1), VOIDmode))
priority >>= 3;
}
return priority;
}
static int
pa_issue_rate (void)
{
switch (pa_cpu)
{
case PROCESSOR_700: return 1;
case PROCESSOR_7100: return 2;
case PROCESSOR_7100LC: return 2;
case PROCESSOR_7200: return 2;
case PROCESSOR_7300: return 2;
case PROCESSOR_8000: return 4;
default:
abort ();
}
}
int
pa_adjust_insn_length (rtx insn, int length)
{
rtx pat = PATTERN (insn);
if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (pat) == PARALLEL
&& get_attr_type (insn) == TYPE_BTABLE_BRANCH)
return 4;
else if (GET_CODE (insn) == INSN
&& GET_CODE (pat) != SEQUENCE
&& GET_CODE (pat) != USE
&& GET_CODE (pat) != CLOBBER
&& get_attr_type (insn) == TYPE_MILLI)
return 4;
else if (GET_CODE (insn) == INSN
&& GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 0)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
&& GET_CODE (XEXP (XVECEXP (pat, 0, 0), 1)) == MEM
&& GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode
&& GET_MODE (XEXP (XVECEXP (pat, 0, 0), 1)) == BLKmode)
return compute_movmem_length (insn) - 4;
else if (GET_CODE (insn) == INSN
&& GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 0)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
&& XEXP (XVECEXP (pat, 0, 0), 1) == const0_rtx
&& GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode)
return compute_clrmem_length (insn) - 4;
else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn))
{
if (GET_CODE (pat) == SET
&& length == 4
&& ! forward_branch_p (insn))
return 4;
else if (GET_CODE (pat) == PARALLEL
&& get_attr_type (insn) == TYPE_PARALLEL_BRANCH
&& length == 4)
return 4;
else if (GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 1)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == REG
&& ! FP_REG_P (XEXP (XVECEXP (pat, 0, 1), 0))
&& length == 4
&& ! forward_branch_p (insn))
return 4;
else
return 0;
}
return 0;
}
void
print_operand (FILE *file, rtx x, int code)
{
switch (code)
{
case '#':
if (dbr_sequence_length () == 0)
fputs ("\n\tnop", file);
return;
case '*':
if (dbr_sequence_length () == 0 ||
(final_sequence &&
INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))))
fputs (",n", file);
return;
case 'R':
fputs (reg_names[REGNO (x) + 1], file);
return;
case 'r':
if (x == const0_rtx
|| (x == CONST0_RTX (DFmode))
|| (x == CONST0_RTX (SFmode)))
{
fputs ("%r0", file);
return;
}
else
break;
case 'f':
if (x == const0_rtx
|| (x == CONST0_RTX (DFmode))
|| (x == CONST0_RTX (SFmode)))
{
fputs ("%fr0", file);
return;
}
else
break;
case 'A':
{
rtx xoperands[2];
xoperands[0] = XEXP (XEXP (x, 0), 0);
xoperands[1] = XVECEXP (XEXP (XEXP (x, 0), 1), 0, 0);
output_global_address (file, xoperands[1], 0);
fprintf (file, "(%s)", reg_names [REGNO (xoperands[0])]);
return;
}
case 'C':
case 'X':
switch (GET_CODE (x))
{
case EQ:
fputs ("=", file); break;
case NE:
fputs ("<>", file); break;
case GT:
fputs (">", file); break;
case GE:
fputs (">=", file); break;
case GEU:
fputs (">>=", file); break;
case GTU:
fputs (">>", file); break;
case LT:
fputs ("<", file); break;
case LE:
fputs ("<=", file); break;
case LEU:
fputs ("<<=", file); break;
case LTU:
fputs ("<<", file); break;
default:
abort ();
}
return;
case 'N':
switch (GET_CODE (x))
{
case EQ:
fputs ("<>", file); break;
case NE:
fputs ("=", file); break;
case GT:
fputs ("<=", file); break;
case GE:
fputs ("<", file); break;
case GEU:
fputs ("<<", file); break;
case GTU:
fputs ("<<=", file); break;
case LT:
fputs (">=", file); break;
case LE:
fputs (">", file); break;
case LEU:
fputs (">>", file); break;
case LTU:
fputs (">>=", file); break;
default:
abort ();
}
return;
case 'Y':
switch (GET_CODE (x))
{
case EQ:
fputs ("!=", file); break;
case NE:
fputs ("=", file); break;
case GT:
fputs ("!>", file); break;
case GE:
fputs ("!>=", file); break;
case LT:
fputs ("!<", file); break;
case LE:
fputs ("!<=", file); break;
case LTGT:
fputs ("!<>", file); break;
case UNLE:
fputs ("!?<=", file); break;
case UNLT:
fputs ("!?<", file); break;
case UNGE:
fputs ("!?>=", file); break;
case UNGT:
fputs ("!?>", file); break;
case UNEQ:
fputs ("!?=", file); break;
case UNORDERED:
fputs ("!?", file); break;
case ORDERED:
fputs ("?", file); break;
default:
abort ();
}
return;
case 'S':
switch (GET_CODE (x))
{
case EQ:
fputs ("=", file); break;
case NE:
fputs ("<>", file); break;
case GT:
fputs ("<", file); break;
case GE:
fputs ("<=", file); break;
case GEU:
fputs ("<<=", file); break;
case GTU:
fputs ("<<", file); break;
case LT:
fputs (">", file); break;
case LE:
fputs (">=", file); break;
case LEU:
fputs (">>=", file); break;
case LTU:
fputs (">>", file); break;
default:
abort ();
}
return;
case 'B':
switch (GET_CODE (x))
{
case EQ:
fputs ("<>", file); break;
case NE:
fputs ("=", file); break;
case GT:
fputs (">=", file); break;
case GE:
fputs (">", file); break;
case GEU:
fputs (">>", file); break;
case GTU:
fputs (">>=", file); break;
case LT:
fputs ("<=", file); break;
case LE:
fputs ("<", file); break;
case LEU:
fputs ("<<", file); break;
case LTU:
fputs ("<<=", file); break;
default:
abort ();
}
return;
case 'k':
if (GET_CODE (x) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~INTVAL (x));
return;
}
abort ();
case 'Q':
if (GET_CODE (x) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - (INTVAL (x) & 63));
return;
}
abort ();
case 'L':
if (GET_CODE (x) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - (INTVAL (x) & 31));
return;
}
abort ();
case 'O':
if (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0)
{
fprintf (file, "%d", exact_log2 (INTVAL (x)));
return;
}
abort ();
case 'p':
if (GET_CODE (x) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, 63 - (INTVAL (x) & 63));
return;
}
abort ();
case 'P':
if (GET_CODE (x) == CONST_INT)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, 31 - (INTVAL (x) & 31));
return;
}
abort ();
case 'I':
if (GET_CODE (x) == CONST_INT)
fputs ("i", file);
return;
case 'M':
case 'F':
switch (GET_CODE (XEXP (x, 0)))
{
case PRE_DEC:
case PRE_INC:
if (ASSEMBLER_DIALECT == 0)
fputs ("s,mb", file);
else
fputs (",mb", file);
break;
case POST_DEC:
case POST_INC:
if (ASSEMBLER_DIALECT == 0)
fputs ("s,ma", file);
else
fputs (",ma", file);
break;
case PLUS:
if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == REG)
{
if (ASSEMBLER_DIALECT == 0)
fputs ("x", file);
}
else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
|| GET_CODE (XEXP (XEXP (x, 0), 1)) == MULT)
{
if (ASSEMBLER_DIALECT == 0)
fputs ("x,s", file);
else
fputs (",s", file);
}
else if (code == 'F' && ASSEMBLER_DIALECT == 0)
fputs ("s", file);
break;
default:
if (code == 'F' && ASSEMBLER_DIALECT == 0)
fputs ("s", file);
break;
}
return;
case 'G':
output_global_address (file, x, 0);
return;
case 'H':
output_global_address (file, x, 1);
return;
case 0:
break;
case 'Z':
{
unsigned op[3];
compute_zdepwi_operands (INTVAL (x), op);
fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
return;
}
case 'z':
{
unsigned op[3];
compute_zdepdi_operands (INTVAL (x), op);
fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
return;
}
case 'c':
break;
default:
abort ();
}
if (GET_CODE (x) == REG)
{
fputs (reg_names [REGNO (x)], file);
if (TARGET_64BIT && FP_REG_P (x) && GET_MODE_SIZE (GET_MODE (x)) <= 4)
{
fputs ("R", file);
return;
}
if (FP_REG_P (x)
&& GET_MODE_SIZE (GET_MODE (x)) <= 4
&& (REGNO (x) & 1) == 0)
fputs ("L", file);
}
else if (GET_CODE (x) == MEM)
{
int size = GET_MODE_SIZE (GET_MODE (x));
rtx base = NULL_RTX;
switch (GET_CODE (XEXP (x, 0)))
{
case PRE_DEC:
case POST_DEC:
base = XEXP (XEXP (x, 0), 0);
fprintf (file, "-%d(%s)", size, reg_names [REGNO (base)]);
break;
case PRE_INC:
case POST_INC:
base = XEXP (XEXP (x, 0), 0);
fprintf (file, "%d(%s)", size, reg_names [REGNO (base)]);
break;
case PLUS:
if (GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT)
fprintf (file, "%s(%s)",
reg_names [REGNO (XEXP (XEXP (XEXP (x, 0), 0), 0))],
reg_names [REGNO (XEXP (XEXP (x, 0), 1))]);
else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == MULT)
fprintf (file, "%s(%s)",
reg_names [REGNO (XEXP (XEXP (XEXP (x, 0), 1), 0))],
reg_names [REGNO (XEXP (XEXP (x, 0), 0))]);
else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == REG)
{
rtx base = XEXP (XEXP (x, 0), 1);
rtx index = XEXP (XEXP (x, 0), 0);
fprintf (file, "%s(%s)",
reg_names [REGNO (index)], reg_names [REGNO (base)]);
}
else
output_address (XEXP (x, 0));
break;
default:
output_address (XEXP (x, 0));
break;
}
}
else
output_addr_const (file, x);
}
void
output_global_address (FILE *file, rtx x, int round_constant)
{
if (GET_CODE (x) == HIGH)
x = XEXP (x, 0);
if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x, VOIDmode))
output_addr_const (file, x);
else if (GET_CODE (x) == SYMBOL_REF && !flag_pic)
{
output_addr_const (file, x);
fputs ("-$global$", file);
}
else if (GET_CODE (x) == CONST)
{
const char *sep = "";
int offset = 0;
rtx base = NULL_RTX;
if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
{
base = XEXP (XEXP (x, 0), 0);
output_addr_const (file, base);
}
else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == CONST_INT)
offset = INTVAL (XEXP (XEXP (x, 0), 0));
else abort ();
if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF)
{
base = XEXP (XEXP (x, 0), 1);
output_addr_const (file, base);
}
else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
offset = INTVAL (XEXP (XEXP (x, 0), 1));
else abort ();
if (round_constant)
offset = ((offset + 0x1000) & ~0x1fff);
if (GET_CODE (XEXP (x, 0)) == PLUS)
{
if (offset < 0)
{
offset = -offset;
sep = "-";
}
else
sep = "+";
}
else if (GET_CODE (XEXP (x, 0)) == MINUS
&& (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
sep = "-";
else abort ();
if (!read_only_operand (base, VOIDmode) && !flag_pic)
fputs ("-$global$", file);
if (offset)
fprintf (file, "%s%d", sep, offset);
}
else
output_addr_const (file, x);
}
#define aputs(x) fputs(x, asm_out_file)
static inline void
pa_file_start_level (void)
{
if (TARGET_64BIT)
aputs ("\t.LEVEL 2.0w\n");
else if (TARGET_PA_20)
aputs ("\t.LEVEL 2.0\n");
else if (TARGET_PA_11)
aputs ("\t.LEVEL 1.1\n");
else
aputs ("\t.LEVEL 1.0\n");
}
static inline void
pa_file_start_space (int sortspace)
{
aputs ("\t.SPACE $PRIVATE$");
if (sortspace)
aputs (",SORT=16");
aputs ("\n\t.SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31"
"\n\t.SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82"
"\n\t.SPACE $TEXT$");
if (sortspace)
aputs (",SORT=8");
aputs ("\n\t.SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44"
"\n\t.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY\n");
}
static inline void
pa_file_start_file (int want_version)
{
if (write_symbols != NO_DEBUG)
{
output_file_directive (asm_out_file, main_input_filename);
if (want_version)
aputs ("\t.version\t\"01.01\"\n");
}
}
static inline void
pa_file_start_mcount (const char *aswhat)
{
if (profile_flag)
fprintf (asm_out_file, "\t.IMPORT _mcount,%s\n", aswhat);
}
static void
pa_elf_file_start (void)
{
pa_file_start_level ();
pa_file_start_mcount ("ENTRY");
pa_file_start_file (0);
}
static void
pa_som_file_start (void)
{
pa_file_start_level ();
pa_file_start_space (0);
aputs ("\t.IMPORT $global$,DATA\n"
"\t.IMPORT $$dyncall,MILLICODE\n");
pa_file_start_mcount ("CODE");
pa_file_start_file (0);
}
static void
pa_linux_file_start (void)
{
pa_file_start_file (1);
pa_file_start_level ();
pa_file_start_mcount ("CODE");
}
static void
pa_hpux64_gas_file_start (void)
{
pa_file_start_level ();
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
if (profile_flag)
ASM_OUTPUT_TYPE_DIRECTIVE (asm_out_file, "_mcount", "function");
#endif
pa_file_start_file (1);
}
static void
pa_hpux64_hpas_file_start (void)
{
pa_file_start_level ();
pa_file_start_space (1);
pa_file_start_mcount ("CODE");
pa_file_start_file (0);
}
#undef aputs
static struct deferred_plabel *
get_plabel (rtx symbol)
{
const char *fname = XSTR (symbol, 0);
size_t i;
for (i = 0; i < n_deferred_plabels; i++)
if (strcmp (fname, XSTR (deferred_plabels[i].symbol, 0)) == 0)
break;
if (deferred_plabels == NULL || i == n_deferred_plabels)
{
tree id;
if (deferred_plabels == 0)
deferred_plabels = (struct deferred_plabel *)
ggc_alloc (sizeof (struct deferred_plabel));
else
deferred_plabels = (struct deferred_plabel *)
ggc_realloc (deferred_plabels,
((n_deferred_plabels + 1)
* sizeof (struct deferred_plabel)));
i = n_deferred_plabels++;
deferred_plabels[i].internal_label = gen_label_rtx ();
deferred_plabels[i].symbol = symbol;
id = maybe_get_identifier (targetm.strip_name_encoding (fname));
if (id)
mark_referenced (id);
}
return &deferred_plabels[i];
}
static void
output_deferred_plabels (void)
{
size_t i;
if (n_deferred_plabels)
{
data_section ();
ASM_OUTPUT_ALIGN (asm_out_file, TARGET_64BIT ? 3 : 2);
}
for (i = 0; i < n_deferred_plabels; i++)
{
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (deferred_plabels[i].internal_label));
assemble_integer (deferred_plabels[i].symbol,
TARGET_64BIT ? 8 : 4, TARGET_64BIT ? 64 : 32, 1);
}
}
#ifdef HPUX_LONG_DOUBLE_LIBRARY
static void
pa_hpux_init_libfuncs (void)
{
set_optab_libfunc (add_optab, TFmode, "_U_Qfadd");
set_optab_libfunc (sub_optab, TFmode, "_U_Qfsub");
set_optab_libfunc (smul_optab, TFmode, "_U_Qfmpy");
set_optab_libfunc (sdiv_optab, TFmode, "_U_Qfdiv");
set_optab_libfunc (smin_optab, TFmode, "_U_Qmin");
set_optab_libfunc (smax_optab, TFmode, "_U_Qfmax");
set_optab_libfunc (sqrt_optab, TFmode, "_U_Qfsqrt");
set_optab_libfunc (abs_optab, TFmode, "_U_Qfabs");
set_optab_libfunc (neg_optab, TFmode, "_U_Qfneg");
set_optab_libfunc (eq_optab, TFmode, "_U_Qfeq");
set_optab_libfunc (ne_optab, TFmode, "_U_Qfne");
set_optab_libfunc (gt_optab, TFmode, "_U_Qfgt");
set_optab_libfunc (ge_optab, TFmode, "_U_Qfge");
set_optab_libfunc (lt_optab, TFmode, "_U_Qflt");
set_optab_libfunc (le_optab, TFmode, "_U_Qfle");
set_optab_libfunc (unord_optab, TFmode, "_U_Qfunord");
set_conv_libfunc (sext_optab, TFmode, SFmode, "_U_Qfcnvff_sgl_to_quad");
set_conv_libfunc (sext_optab, TFmode, DFmode, "_U_Qfcnvff_dbl_to_quad");
set_conv_libfunc (trunc_optab, SFmode, TFmode, "_U_Qfcnvff_quad_to_sgl");
set_conv_libfunc (trunc_optab, DFmode, TFmode, "_U_Qfcnvff_quad_to_dbl");
set_conv_libfunc (sfix_optab, SImode, TFmode, TARGET_64BIT
? "__U_Qfcnvfxt_quad_to_sgl"
: "_U_Qfcnvfxt_quad_to_sgl");
set_conv_libfunc (sfix_optab, DImode, TFmode, "_U_Qfcnvfxt_quad_to_dbl");
set_conv_libfunc (ufix_optab, SImode, TFmode, "_U_Qfcnvfxt_quad_to_usgl");
set_conv_libfunc (ufix_optab, DImode, TFmode, "_U_Qfcnvfxt_quad_to_udbl");
set_conv_libfunc (sfloat_optab, TFmode, SImode, "_U_Qfcnvxf_sgl_to_quad");
set_conv_libfunc (sfloat_optab, TFmode, DImode, "_U_Qfcnvxf_dbl_to_quad");
}
#endif
enum millicodes { remI, remU, divI, divU, mulI, end1000 };
static void import_milli (enum millicodes);
static char imported[(int) end1000];
static const char * const milli_names[] = {"remI", "remU", "divI", "divU", "mulI"};
static const char import_string[] = ".IMPORT $$....,MILLICODE";
#define MILLI_START 10
static void
import_milli (enum millicodes code)
{
char str[sizeof (import_string)];
if (!imported[(int) code])
{
imported[(int) code] = 1;
strcpy (str, import_string);
strncpy (str + MILLI_START, milli_names[(int) code], 4);
output_asm_insn (str, 0);
}
}
const char *
output_mul_insn (int unsignedp ATTRIBUTE_UNUSED, rtx insn)
{
import_milli (mulI);
return output_millicode_call (insn, gen_rtx_SYMBOL_REF (Pmode, "$$mulI"));
}
static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
1, 1};
static int div_milli[16][2];
int
div_operand (rtx op, enum machine_mode mode)
{
return (mode == SImode
&& ((GET_CODE (op) == REG && REGNO (op) == 25)
|| (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
&& INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
}
int
emit_hpdiv_const (rtx *operands, int unsignedp)
{
if (GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) < 16
&& magic_milli[INTVAL (operands[2])])
{
rtx ret = gen_rtx_REG (SImode, TARGET_64BIT ? 2 : 31);
emit_move_insn (gen_rtx_REG (SImode, 26), operands[1]);
emit
(gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (6, gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, 29),
gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
SImode,
gen_rtx_REG (SImode, 26),
operands[2])),
gen_rtx_CLOBBER (VOIDmode, operands[4]),
gen_rtx_CLOBBER (VOIDmode, operands[3]),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 26)),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 25)),
gen_rtx_CLOBBER (VOIDmode, ret))));
emit_move_insn (operands[0], gen_rtx_REG (SImode, 29));
return 1;
}
return 0;
}
const char *
output_div_insn (rtx *operands, int unsignedp, rtx insn)
{
int divisor;
if (GET_CODE (operands[0]) == CONST_INT)
{
static char buf[100];
divisor = INTVAL (operands[0]);
if (!div_milli[divisor][unsignedp])
{
div_milli[divisor][unsignedp] = 1;
if (unsignedp)
output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands);
else
output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands);
}
if (unsignedp)
{
sprintf (buf, "$$divU_" HOST_WIDE_INT_PRINT_DEC,
INTVAL (operands[0]));
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, buf));
}
else
{
sprintf (buf, "$$divI_" HOST_WIDE_INT_PRINT_DEC,
INTVAL (operands[0]));
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, buf));
}
}
else
{
if (unsignedp)
{
import_milli (divU);
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, "$$divU"));
}
else
{
import_milli (divI);
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, "$$divI"));
}
}
}
const char *
output_mod_insn (int unsignedp, rtx insn)
{
if (unsignedp)
{
import_milli (remU);
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, "$$remU"));
}
else
{
import_milli (remI);
return output_millicode_call (insn,
gen_rtx_SYMBOL_REF (SImode, "$$remI"));
}
}
void
output_arg_descriptor (rtx call_insn)
{
const char *arg_regs[4];
enum machine_mode arg_mode;
rtx link;
int i, output_flag = 0;
int regno;
if (TARGET_64BIT || TARGET_ELF32)
return;
for (i = 0; i < 4; i++)
arg_regs[i] = 0;
if (TARGET_PORTABLE_RUNTIME)
{
fputs ("\t.CALL ARGW0=NO,ARGW1=NO,ARGW2=NO,ARGW3=NO,RETVAL=NO\n",
asm_out_file);
return;
}
if (GET_CODE (call_insn) != CALL_INSN)
abort ();
for (link = CALL_INSN_FUNCTION_USAGE (call_insn); link; link = XEXP (link, 1))
{
rtx use = XEXP (link, 0);
if (! (GET_CODE (use) == USE
&& GET_CODE (XEXP (use, 0)) == REG
&& FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
continue;
arg_mode = GET_MODE (XEXP (use, 0));
regno = REGNO (XEXP (use, 0));
if (regno >= 23 && regno <= 26)
{
arg_regs[26 - regno] = "GR";
if (arg_mode == DImode)
arg_regs[25 - regno] = "GR";
}
else if (regno >= 32 && regno <= 39)
{
if (arg_mode == SFmode)
arg_regs[(regno - 32) / 2] = "FR";
else
{
#ifndef HP_FP_ARG_DESCRIPTOR_REVERSED
arg_regs[(regno - 34) / 2] = "FR";
arg_regs[(regno - 34) / 2 + 1] = "FU";
#else
arg_regs[(regno - 34) / 2] = "FU";
arg_regs[(regno - 34) / 2 + 1] = "FR";
#endif
}
}
}
fputs ("\t.CALL ", asm_out_file);
for (i = 0; i < 4; i++)
{
if (arg_regs[i])
{
if (output_flag++)
fputc (',', asm_out_file);
fprintf (asm_out_file, "ARGW%d=%s", i, arg_regs[i]);
}
}
fputc ('\n', asm_out_file);
}
enum reg_class
secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
{
int regno, is_symbolic;
if (flag_pic
&& GET_MODE_CLASS (mode) == MODE_INT
&& FP_REG_CLASS_P (class)
&& (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
return R1_REGS;
if (GET_CODE (in) == REG)
{
regno = REGNO (in);
if (regno >= FIRST_PSEUDO_REGISTER)
regno = true_regnum (in);
}
else if (GET_CODE (in) == SUBREG)
regno = true_regnum (in);
else
regno = -1;
if (GET_CODE (in) == MEM
&& GET_CODE (XEXP (in, 0)) == MEM)
return NO_REGS;
if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
&& GET_MODE_CLASS (mode) == MODE_INT
&& FP_REG_CLASS_P (class))
|| (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
return GENERAL_REGS;
if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
&& ((REGNO_REG_CLASS (regno) == SHIFT_REGS && FP_REG_CLASS_P (class))
|| (class == SHIFT_REGS && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
return GENERAL_REGS;
if (GET_CODE (in) == HIGH)
in = XEXP (in, 0);
switch (GET_CODE (in))
{
rtx tmp;
case SYMBOL_REF:
case LABEL_REF:
is_symbolic = 1;
break;
case CONST:
tmp = XEXP (in, 0);
is_symbolic = ((GET_CODE (XEXP (tmp, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (tmp, 0)) == LABEL_REF)
&& GET_CODE (XEXP (tmp, 1)) == CONST_INT);
break;
default:
is_symbolic = 0;
break;
}
if (!flag_pic
&& is_symbolic
&& read_only_operand (in, VOIDmode))
return NO_REGS;
if (class != R1_REGS && is_symbolic)
return R1_REGS;
return NO_REGS;
}
static bool
pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
enum machine_mode mode, tree type,
bool named ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT size;
if (type)
size = int_size_in_bytes (type);
else
size = GET_MODE_SIZE (mode);
if (TARGET_64BIT)
return size <= 0;
else
return size <= 0 || size > 8;
}
enum direction
function_arg_padding (enum machine_mode mode, tree type)
{
if (mode == BLKmode
|| (TARGET_64BIT && type && AGGREGATE_TYPE_P (type)))
{
if (type
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& (int_size_in_bytes (type) * BITS_PER_UNIT) % PARM_BOUNDARY == 0)
return none;
if (TARGET_64BIT)
return upward;
else
return downward;
}
if (GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
return downward;
else
return none;
}
static rtx
hppa_builtin_saveregs (void)
{
rtx offset, dest;
tree fntype = TREE_TYPE (current_function_decl);
int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node)))
? UNITS_PER_WORD : 0);
if (argadj)
offset = plus_constant (current_function_arg_offset_rtx, argadj);
else
offset = current_function_arg_offset_rtx;
if (TARGET_64BIT)
{
int i, off;
if (argadj)
offset = plus_constant (current_function_arg_offset_rtx, -argadj);
else
offset = current_function_arg_offset_rtx;
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));
emit_move_insn (virtual_incoming_args_rtx,
plus_constant (arg_pointer_rtx, -64));
return copy_to_reg (expand_binop (Pmode, add_optab,
virtual_incoming_args_rtx,
offset, 0, 0, OPTAB_LIB_WIDEN));
}
dest = gen_rtx_MEM (BLKmode,
plus_constant (current_function_internal_arg_pointer,
-16));
set_mem_alias_set (dest, get_varargs_alias_set ());
set_mem_align (dest, BITS_PER_WORD);
move_block_from_reg (23, dest, 4);
emit_insn (gen_blockage ());
return copy_to_reg (expand_binop (Pmode, add_optab,
current_function_internal_arg_pointer,
offset, 0, 0, OPTAB_LIB_WIDEN));
}
void
hppa_va_start (tree valist, rtx nextarg)
{
nextarg = expand_builtin_saveregs ();
std_expand_builtin_va_start (valist, nextarg);
}
static tree
hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
{
if (TARGET_64BIT)
{
return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
}
else
{
tree ptr = build_pointer_type (type);
tree valist_type;
tree t, u;
unsigned int size, ofs;
bool indirect;
indirect = pass_by_reference (NULL, TYPE_MODE (type), type, 0);
if (indirect)
{
type = ptr;
ptr = build_pointer_type (type);
}
size = int_size_in_bytes (type);
valist_type = TREE_TYPE (valist);
u = fold_convert (valist_type, size_in_bytes (type));
t = build (MINUS_EXPR, valist_type, valist, u);
u = build_int_cst (valist_type, (size > 4 ? -8 : -4));
t = build (BIT_AND_EXPR, valist_type, t, u);
t = build (MODIFY_EXPR, valist_type, valist, t);
ofs = (8 - size) % 4;
if (ofs != 0)
{
u = fold_convert (valist_type, size_int (ofs));
t = build (PLUS_EXPR, valist_type, t, u);
}
t = fold_convert (ptr, t);
t = build_fold_indirect_ref (t);
if (indirect)
t = build_fold_indirect_ref (t);
return t;
}
}
static bool
pa_scalar_mode_supported_p (enum machine_mode mode)
{
int precision = GET_MODE_PRECISION (mode);
switch (GET_MODE_CLASS (mode))
{
case MODE_PARTIAL_INT:
case MODE_INT:
if (precision == CHAR_TYPE_SIZE)
return true;
if (precision == SHORT_TYPE_SIZE)
return true;
if (precision == INT_TYPE_SIZE)
return true;
if (precision == LONG_TYPE_SIZE)
return true;
if (precision == LONG_LONG_TYPE_SIZE)
return true;
return false;
case MODE_FLOAT:
if (precision == FLOAT_TYPE_SIZE)
return true;
if (precision == DOUBLE_TYPE_SIZE)
return true;
if (precision == LONG_DOUBLE_TYPE_SIZE)
return true;
return false;
default:
gcc_unreachable ();
}
}
const char *
output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
{
static char buf[100];
int useskip = 0;
rtx xoperands[5];
if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
return "nop";
if (GET_MODE (operands[1]) == DImode && operands[2] == const0_rtx)
operands[2] = gen_rtx_REG (DImode, 0);
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
if (length == 4
&& next_real_insn (insn) != 0
&& get_attr_length (next_real_insn (insn)) == 4
&& JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
&& nullify)
useskip = 1;
switch (length)
{
case 4:
if (useskip)
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
else
strcpy (buf, "{com%I2b,|cmp%I2b,}");
if (GET_MODE (operands[1]) == DImode)
strcat (buf, "*");
if (negated)
strcat (buf, "%B3");
else
strcat (buf, "%S3");
if (useskip)
strcat (buf, " %2,%r1,%%r0");
else if (nullify)
strcat (buf, ",n %2,%r1,%0");
else
strcat (buf, " %2,%r1,%0");
break;
case 8:
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
{
strcpy (buf, "{com%I2b,|cmp%I2b,}");
if (GET_MODE (operands[1]) == DImode)
strcat (buf, "*");
if (negated)
strcat (buf, "%S3");
else
strcat (buf, "%B3");
strcat (buf, ",n %2,%r1,.+12\n\tb %0");
}
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& INSN_ADDRESSES_SET_P ()
&& VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
- INSN_ADDRESSES (INSN_UID (insn)) - 8))
{
strcpy (buf, "{com%I2b,|cmp%I2b,}");
if (GET_MODE (operands[1]) == DImode)
strcat (buf, "*");
if (negated)
strcat (buf, "%B3 %2,%r1,%0%#");
else
strcat (buf, "%S3 %2,%r1,%0%#");
}
else
{
strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
if (GET_MODE (operands[1]) == DImode)
strcat (buf, "*");
if (negated)
strcat (buf, "%S3");
else
strcat (buf, "%B3");
if (nullify)
strcat (buf, " %2,%r1,%%r0\n\tb,n %0");
else
strcat (buf, " %2,%r1,%%r0\n\tb %0");
}
break;
case 20:
case 28:
xoperands[0] = operands[0];
xoperands[1] = operands[1];
xoperands[2] = operands[2];
xoperands[3] = operands[3];
nullify = dbr_sequence_length () == 0;
xoperands[4] = nullify ? GEN_INT (length) : GEN_INT (length + 4);
if (GET_MODE (operands[1]) != DImode)
{
if (nullify)
{
if (negated)
strcpy (buf,
"{com%I2b,%S3,n %2,%r1,.+%4|cmp%I2b,%S3,n %2,%r1,.+%4}");
else
strcpy (buf,
"{com%I2b,%B3,n %2,%r1,.+%4|cmp%I2b,%B3,n %2,%r1,.+%4}");
}
else
{
if (negated)
strcpy (buf,
"{com%I2b,%S3 %2,%r1,.+%4|cmp%I2b,%S3 %2,%r1,.+%4}");
else
strcpy (buf,
"{com%I2b,%B3 %2,%r1,.+%4|cmp%I2b,%B3 %2,%r1,.+%4}");
}
}
else
{
if (nullify)
{
if (negated)
strcpy (buf,
"{com%I2b,*%S3,n %2,%r1,.+%4|cmp%I2b,*%S3,n %2,%r1,.+%4}");
else
strcpy (buf,
"{com%I2b,*%B3,n %2,%r1,.+%4|cmp%I2b,*%B3,n %2,%r1,.+%4}");
}
else
{
if (negated)
strcpy (buf,
"{com%I2b,*%S3 %2,%r1,.+%4|cmp%I2b,*%S3 %2,%r1,.+%4}");
else
strcpy (buf,
"{com%I2b,*%B3 %2,%r1,.+%4|cmp%I2b,*%B3 %2,%r1,.+%4}");
}
}
output_asm_insn (buf, xoperands);
return output_lbranch (operands[0], insn);
default:
abort ();
}
return buf;
}
const char *
output_lbranch (rtx dest, rtx insn)
{
rtx xoperands[2];
xoperands[0] = dest;
if (dbr_sequence_length () != 0)
{
if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
abort ();
final_scan_insn (NEXT_INSN (insn), asm_out_file,
optimize, 0, 0, NULL);
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
}
if (TARGET_64BIT)
{
if (actual_fsize == 0 && !regs_ever_live[2])
output_asm_insn ("std %%r1,-16(%%r30)", xoperands);
else
output_asm_insn ("std %%r1,-40(%%r30)", xoperands);
}
else
{
if (actual_fsize == 0 && !regs_ever_live[2])
output_asm_insn ("stw %%r1,-20(%%r30)", xoperands);
else
output_asm_insn ("stw %%r1,-12(%%r30)", xoperands);
}
if (TARGET_PORTABLE_RUNTIME)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
output_asm_insn ("ldo R'%0(%%r1),%%r1", xoperands);
output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
else if (flag_pic)
{
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
if (TARGET_SOM || !TARGET_GAS)
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
else
output_asm_insn ("ldil L'%l0,%%r1\n\tbe R'%l0(%%sr4,%%r1)", xoperands);
if (TARGET_64BIT)
{
if (actual_fsize == 0 && !regs_ever_live[2])
return "ldd -16(%%r30),%%r1";
else
return "ldd -40(%%r30),%%r1";
}
else
{
if (actual_fsize == 0 && !regs_ever_live[2])
return "ldw -20(%%r30),%%r1";
else
return "ldw -12(%%r30),%%r1";
}
}
const char *
output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
int negated, rtx insn, int which)
{
static char buf[100];
int useskip = 0;
if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
return "nop";
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
if (length == 4
&& next_real_insn (insn) != 0
&& get_attr_length (next_real_insn (insn)) == 4
&& JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
&& nullify)
useskip = 1;
switch (length)
{
case 4:
if (useskip)
strcpy (buf, "{extrs,|extrw,s,}");
else
strcpy (buf, "bb,");
if (useskip && GET_MODE (operands[0]) == DImode)
strcpy (buf, "extrd,s,*");
else if (GET_MODE (operands[0]) == DImode)
strcpy (buf, "bb,*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (useskip)
strcat (buf, " %0,%1,1,%%r0");
else if (nullify && negated)
strcat (buf, ",n %0,%1,%3");
else if (nullify && ! negated)
strcat (buf, ",n %0,%1,%2");
else if (! nullify && negated)
strcat (buf, "%0,%1,%3");
else if (! nullify && ! negated)
strcat (buf, " %0,%1,%2");
break;
case 8:
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
{
strcpy (buf, "bb,");
if (GET_MODE (operands[0]) == DImode)
strcat (buf, "*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (negated)
strcat (buf, ",n %0,%1,.+12\n\tb %3");
else
strcat (buf, ",n %0,%1,.+12\n\tb %2");
}
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& INSN_ADDRESSES_SET_P ()
&& VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
- INSN_ADDRESSES (INSN_UID (insn)) - 8))
{
strcpy (buf, "bb,");
if (GET_MODE (operands[0]) == DImode)
strcat (buf, "*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (negated)
strcat (buf, " %0,%1,%3%#");
else
strcat (buf, " %0,%1,%2%#");
}
else
{
strcpy (buf, "{extrs,|extrw,s,}");
if (GET_MODE (operands[0]) == DImode)
strcpy (buf, "extrd,s,*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (nullify && negated)
strcat (buf, " %0,%1,1,%%r0\n\tb,n %3");
else if (nullify && ! negated)
strcat (buf, " %0,%1,1,%%r0\n\tb,n %2");
else if (negated)
strcat (buf, " %0,%1,1,%%r0\n\tb %3");
else
strcat (buf, " %0,%1,1,%%r0\n\tb %2");
}
break;
default:
abort ();
}
return buf;
}
const char *
output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
int negated, rtx insn, int which)
{
static char buf[100];
int useskip = 0;
if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
return "nop";
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
if (length == 4
&& next_real_insn (insn) != 0
&& get_attr_length (next_real_insn (insn)) == 4
&& JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
&& nullify)
useskip = 1;
switch (length)
{
case 4:
if (useskip)
strcpy (buf, "{vextrs,|extrw,s,}");
else
strcpy (buf, "{bvb,|bb,}");
if (useskip && GET_MODE (operands[0]) == DImode)
strcpy (buf, "extrd,s,*");
else if (GET_MODE (operands[0]) == DImode)
strcpy (buf, "bb,*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (useskip)
strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}");
else if (nullify && negated)
strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}");
else if (nullify && ! negated)
strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}");
else if (! nullify && negated)
strcat (buf, "{%0,%3|%0,%%sar,%3}");
else if (! nullify && ! negated)
strcat (buf, "{ %0,%2| %0,%%sar,%2}");
break;
case 8:
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
{
strcpy (buf, "{bvb,|bb,}");
if (GET_MODE (operands[0]) == DImode)
strcat (buf, "*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (negated)
strcat (buf, "{,n %0,.+12\n\tb %3|,n %0,%%sar,.+12\n\tb %3}");
else
strcat (buf, "{,n %0,.+12\n\tb %2|,n %0,%%sar,.+12\n\tb %2}");
}
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& INSN_ADDRESSES_SET_P ()
&& VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
- INSN_ADDRESSES (INSN_UID (insn)) - 8))
{
strcpy (buf, "{bvb,|bb,}");
if (GET_MODE (operands[0]) == DImode)
strcat (buf, "*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (negated)
strcat (buf, "{ %0,%3%#| %0,%%sar,%3%#}");
else
strcat (buf, "{ %0,%2%#| %0,%%sar,%2%#}");
}
else
{
strcpy (buf, "{vextrs,|extrw,s,}");
if (GET_MODE (operands[0]) == DImode)
strcpy (buf, "extrd,s,*");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (nullify && negated)
strcat (buf, "{ %0,1,%%r0\n\tb,n %3| %0,%%sar,1,%%r0\n\tb,n %3}");
else if (nullify && ! negated)
strcat (buf, "{ %0,1,%%r0\n\tb,n %2| %0,%%sar,1,%%r0\n\tb,n %2}");
else if (negated)
strcat (buf, "{ %0,1,%%r0\n\tb %3| %0,%%sar,1,%%r0\n\tb %3}");
else
strcat (buf, "{ %0,1,%%r0\n\tb %2| %0,%%sar,1,%%r0\n\tb %2}");
}
break;
default:
abort ();
}
return buf;
}
const char *
output_dbra (rtx *operands, rtx insn, int which_alternative)
{
if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
{
if (which_alternative == 0)
return "ldo %1(%0),%0";
else if (which_alternative == 1)
{
output_asm_insn ("{fstws|fstw} %0,-16(%%r30)", operands);
output_asm_insn ("ldw -16(%%r30),%4", operands);
output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(%%r30)", operands);
return "{fldws|fldw} -16(%%r30),%0";
}
else
{
output_asm_insn ("ldw %0,%4", operands);
return "ldo %1(%4),%4\n\tstw %4,%0";
}
}
if (which_alternative == 0)
{
int nullify = INSN_ANNULLED_BRANCH_P (insn);
int length = get_attr_length (insn);
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
if (length == 4 && nullify)
return "addib,%C2,n %1,%0,%3";
else if (length == 4 && ! nullify)
return "addib,%C2 %1,%0,%3";
else if (length == 8)
{
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
return "addib,%N2,n %1,%0,.+12\n\tb %3";
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& INSN_ADDRESSES_SET_P ()
&& VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
- INSN_ADDRESSES (INSN_UID (insn)) - 8))
return "addib,%C2 %1,%0,%3%#";
if (nullify)
return "addi,%N2 %1,%0,%0\n\tb,n %3";
else
return "addi,%N2 %1,%0,%0\n\tb %3";
}
else
abort ();
}
else if (which_alternative == 1)
{
output_asm_insn ("{fstws|fstw} %0,-16(%%r30)\n\tldw -16(%%r30),%4",
operands);
output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(%%r30)", operands);
if (get_attr_length (insn) == 24)
return "{comb|cmpb},%S2 %%r0,%4,%3\n\t{fldws|fldw} -16(%%r30),%0";
else
return "{comclr|cmpclr},%B2 %%r0,%4,%%r0\n\tb %3\n\t{fldws|fldw} -16(%%r30),%0";
}
else
{
output_asm_insn ("ldw %0,%4", operands);
if (get_attr_length (insn) == 12)
return "addib,%C2 %1,%4,%3\n\tstw %4,%0";
else
return "addi,%N2 %1,%4,%4\n\tb %3\n\tstw %4,%0";
}
}
const char *
output_movb (rtx *operands, rtx insn, int which_alternative,
int reverse_comparison)
{
if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
{
if (which_alternative == 0)
return "copy %1,%0";
else if (which_alternative == 1)
{
output_asm_insn ("stw %1,-16(%%r30)", operands);
return "{fldws|fldw} -16(%%r30),%0";
}
else if (which_alternative == 2)
return "stw %1,%0";
else
return "mtsar %r1";
}
if (reverse_comparison)
PUT_CODE (operands[2], reverse_condition (GET_CODE (operands[2])));
if (which_alternative == 0)
{
int nullify = INSN_ANNULLED_BRANCH_P (insn);
int length = get_attr_length (insn);
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
if (length == 4 && nullify)
return "movb,%C2,n %1,%0,%3";
else if (length == 4 && ! nullify)
return "movb,%C2 %1,%0,%3";
else if (length == 8)
{
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
return "movb,%N2,n %1,%0,.+12\n\tb %3";
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& INSN_ADDRESSES_SET_P ()
&& VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
- INSN_ADDRESSES (INSN_UID (insn)) - 8))
return "movb,%C2 %1,%0,%3%#";
if (nullify)
return "or,%N2 %1,%%r0,%0\n\tb,n %3";
else
return "or,%N2 %1,%%r0,%0\n\tb %3";
}
else
abort ();
}
else if (which_alternative == 1)
{
output_asm_insn ("stw %1,-16(%%r30)", operands);
if (get_attr_length (insn) == 12)
return "{comb|cmpb},%S2 %%r0,%1,%3\n\t{fldws|fldw} -16(%%r30),%0";
else
return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\t{fldws|fldw} -16(%%r30),%0";
}
else if (which_alternative == 2)
{
if (get_attr_length (insn) == 8)
return "{comb|cmpb},%S2 %%r0,%1,%3\n\tstw %1,%0";
else
return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tstw %1,%0";
}
else
{
if (get_attr_length (insn) == 8)
return "{comb|cmpb},%S2 %%r0,%1,%3\n\tmtsar %r1";
else
return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tmtsar %r1";
}
}
static void
copy_fp_args (rtx insn)
{
rtx link;
rtx xoperands[2];
for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
{
int arg_mode, regno;
rtx use = XEXP (link, 0);
if (! (GET_CODE (use) == USE
&& GET_CODE (XEXP (use, 0)) == REG
&& FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
continue;
arg_mode = GET_MODE (XEXP (use, 0));
regno = REGNO (XEXP (use, 0));
if (regno >= 32 && regno <= 39)
{
if (arg_mode == SFmode)
{
xoperands[0] = XEXP (use, 0);
xoperands[1] = gen_rtx_REG (SImode, 26 - (regno - 32) / 2);
output_asm_insn ("{fstws|fstw} %0,-16(%%sr0,%%r30)", xoperands);
output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
}
else
{
xoperands[0] = XEXP (use, 0);
xoperands[1] = gen_rtx_REG (DImode, 25 - (regno - 34) / 2);
output_asm_insn ("{fstds|fstd} %0,-16(%%sr0,%%r30)", xoperands);
output_asm_insn ("ldw -12(%%sr0,%%r30),%R1", xoperands);
output_asm_insn ("ldw -16(%%sr0,%%r30),%1", xoperands);
}
}
}
}
static int
length_fp_args (rtx insn)
{
int length = 0;
rtx link;
for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
{
int arg_mode, regno;
rtx use = XEXP (link, 0);
if (! (GET_CODE (use) == USE
&& GET_CODE (XEXP (use, 0)) == REG
&& FUNCTION_ARG_REGNO_P (REGNO (XEXP (use, 0)))))
continue;
arg_mode = GET_MODE (XEXP (use, 0));
regno = REGNO (XEXP (use, 0));
if (regno >= 32 && regno <= 39)
{
if (arg_mode == SFmode)
length += 8;
else
length += 12;
}
}
return length;
}
int
attr_length_millicode_call (rtx insn)
{
unsigned long distance = -1;
unsigned long total = IN_NAMED_SECTION_P (cfun->decl) ? 0 : total_code_bytes;
if (INSN_ADDRESSES_SET_P ())
{
distance = (total + insn_current_reference_address (insn));
if (distance < total)
distance = -1;
}
if (TARGET_64BIT)
{
if (!TARGET_LONG_CALLS && distance < 7600000)
return 8;
return 20;
}
else if (TARGET_PORTABLE_RUNTIME)
return 24;
else
{
if (!TARGET_LONG_CALLS && distance < 240000)
return 8;
if (TARGET_LONG_ABS_CALL && !flag_pic)
return 12;
return 24;
}
}
const char *
output_millicode_call (rtx insn, rtx call_dest)
{
int attr_length = get_attr_length (insn);
int seq_length = dbr_sequence_length ();
int distance;
rtx seq_insn;
rtx xoperands[3];
xoperands[0] = call_dest;
xoperands[2] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
if (!TARGET_LONG_CALLS
&& ((seq_length == 0
&& (attr_length == 12
|| (attr_length == 28 && get_attr_type (insn) == TYPE_MULTI)))
|| (seq_length != 0 && attr_length == 8)))
{
output_asm_insn ("{bl|b,l} %0,%2", xoperands);
}
else
{
if (TARGET_64BIT)
{
output_asm_insn ("b,l .+8,%%r1", xoperands);
if (TARGET_GAS)
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
else
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
}
output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
}
else if (TARGET_PORTABLE_RUNTIME)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
output_asm_insn ("ldo R'%0(%%r1),%%r1", xoperands);
output_asm_insn ("{bl|b,l} .+8,%%r31", xoperands);
output_asm_insn ("addi 8,%%r31,%%r31", xoperands);
output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
else if (!flag_pic)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
if (TARGET_PA_20)
output_asm_insn ("be,l R'%0(%%sr4,%%r1),%%sr0,%%r31", xoperands);
else
output_asm_insn ("ble R'%0(%%sr4,%%r1)", xoperands);
}
else
{
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
output_asm_insn ("addi 16,%%r1,%%r31", xoperands);
if (TARGET_SOM || !TARGET_GAS)
{
xoperands[1] = gen_label_rtx ();
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+8,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+12(%%r1),%%r1",
xoperands);
}
output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
}
if (seq_length == 0)
output_asm_insn ("nop", xoperands);
if (seq_length == 0 || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
return "";
xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
if (INSN_ADDRESSES_SET_P ())
{
seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
- INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
if (VAL_14_BITS_P (distance))
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
}
else
output_asm_insn ("nop\n\tb,n %0", xoperands);
}
else
output_asm_insn ("nop\n\tb,n %0", xoperands);
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
return "";
}
int
attr_length_call (rtx insn, int sibcall)
{
int local_call;
rtx call_dest;
tree call_decl;
int length = 0;
rtx pat = PATTERN (insn);
unsigned long distance = -1;
if (INSN_ADDRESSES_SET_P ())
{
unsigned long total;
total = IN_NAMED_SECTION_P (cfun->decl) ? 0 : total_code_bytes;
distance = (total + insn_current_reference_address (insn));
if (distance < total)
distance = -1;
}
if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL)
call_dest = XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0);
else
call_dest = XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0);
call_decl = SYMBOL_REF_DECL (call_dest);
local_call = call_decl && (*targetm.binds_local_p) (call_decl);
if (!TARGET_LONG_CALLS
&& ((TARGET_PA_20 && !sibcall && distance < 7600000)
|| distance < 240000))
length += 8;
else if (TARGET_64BIT && !local_call)
length += sibcall ? 28 : 24;
else if ((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
length += 12;
else if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
|| (TARGET_64BIT && !TARGET_GAS)
|| (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call)))
{
length += 20;
if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS)
length += 8;
}
else
{
length += 32;
if (TARGET_SOM)
length += length_fp_args (insn);
if (flag_pic)
length += 4;
if (!TARGET_PA_20)
{
if (!sibcall)
length += 8;
if (!TARGET_NO_SPACE_REGS)
length += 8;
}
}
return length;
}
const char *
output_call (rtx insn, rtx call_dest, int sibcall)
{
int delay_insn_deleted = 0;
int delay_slot_filled = 0;
int seq_length = dbr_sequence_length ();
tree call_decl = SYMBOL_REF_DECL (call_dest);
int local_call = call_decl && (*targetm.binds_local_p) (call_decl);
rtx xoperands[2];
xoperands[0] = call_dest;
if (!TARGET_LONG_CALLS && attr_length_call (insn, sibcall) == 8)
{
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
output_asm_insn ("{bl|b,l} %0,%1", xoperands);
}
else
{
if (TARGET_64BIT && !local_call)
{
struct deferred_plabel *p = get_plabel (call_dest);
xoperands[0] = p->internal_label;
xoperands[1] = gen_label_rtx ();
if (seq_length != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
&& !sibcall)
{
final_scan_insn (NEXT_INSN (insn), asm_out_file,
optimize, 0, 0, NULL);
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
delay_insn_deleted = 1;
}
output_asm_insn ("addil LT'%0,%%r27", xoperands);
output_asm_insn ("ldd RT'%0(%%r1),%%r1", xoperands);
output_asm_insn ("ldd 0(%%r1),%%r1", xoperands);
if (sibcall)
{
output_asm_insn ("ldd 24(%%r1),%%r27", xoperands);
output_asm_insn ("ldd 16(%%r1),%%r1", xoperands);
output_asm_insn ("bve (%%r1)", xoperands);
}
else
{
output_asm_insn ("ldd 16(%%r1),%%r2", xoperands);
output_asm_insn ("bve,l (%%r2),%%r2", xoperands);
output_asm_insn ("ldd 24(%%r1),%%r27", xoperands);
delay_slot_filled = 1;
}
}
else
{
int indirect_call = 0;
if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
&& !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
&& !(TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
&& !TARGET_64BIT)
indirect_call = 1;
if (seq_length != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
&& !sibcall
&& (!TARGET_PA_20 || indirect_call))
{
final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0,
NULL);
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
delay_insn_deleted = 1;
}
if ((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
if (sibcall)
output_asm_insn ("be R'%0(%%sr4,%%r1)", xoperands);
else
{
if (TARGET_PA_20)
output_asm_insn ("be,l R'%0(%%sr4,%%r1),%%sr0,%%r31",
xoperands);
else
output_asm_insn ("ble R'%0(%%sr4,%%r1)", xoperands);
output_asm_insn ("copy %%r31,%%r2", xoperands);
delay_slot_filled = 1;
}
}
else
{
if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
|| (TARGET_64BIT && !TARGET_GAS))
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
}
else if (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
{
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1",
xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1",
xoperands);
}
else
{
struct deferred_plabel *p = get_plabel (call_dest);
xoperands[0] = p->internal_label;
xoperands[1] = gen_label_rtx ();
if (TARGET_SOM)
copy_fp_args (insn);
if (flag_pic)
{
output_asm_insn ("addil LT'%0,%%r19", xoperands);
output_asm_insn ("ldw RT'%0(%%r1),%%r1", xoperands);
output_asm_insn ("ldw 0(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil LR'%0-$global$,%%r27",
xoperands);
output_asm_insn ("ldw RR'%0-$global$(%%r1),%%r1",
xoperands);
}
output_asm_insn ("bb,>=,n %%r1,30,.+16", xoperands);
output_asm_insn ("depi 0,31,2,%%r1", xoperands);
output_asm_insn ("ldw 4(%%sr0,%%r1),%%r19", xoperands);
output_asm_insn ("ldw 0(%%sr0,%%r1),%%r1", xoperands);
if (!sibcall && !TARGET_PA_20)
{
output_asm_insn ("{bl|b,l} .+8,%%r2", xoperands);
if (TARGET_NO_SPACE_REGS)
output_asm_insn ("addi 8,%%r2,%%r2", xoperands);
else
output_asm_insn ("addi 16,%%r2,%%r2", xoperands);
}
}
if (TARGET_PA_20)
{
if (sibcall)
output_asm_insn ("bve (%%r1)", xoperands);
else
{
if (indirect_call)
{
output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
output_asm_insn ("stw %%r2,-24(%%sp)", xoperands);
delay_slot_filled = 1;
}
else
output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
}
}
else
{
if (!TARGET_NO_SPACE_REGS)
output_asm_insn ("ldsid (%%r1),%%r31\n\tmtsp %%r31,%%sr0",
xoperands);
if (sibcall)
{
if (TARGET_NO_SPACE_REGS)
output_asm_insn ("be 0(%%sr4,%%r1)", xoperands);
else
output_asm_insn ("be 0(%%sr0,%%r1)", xoperands);
}
else
{
if (TARGET_NO_SPACE_REGS)
output_asm_insn ("ble 0(%%sr4,%%r1)", xoperands);
else
output_asm_insn ("ble 0(%%sr0,%%r1)", xoperands);
if (indirect_call)
output_asm_insn ("stw %%r31,-24(%%sp)", xoperands);
else
output_asm_insn ("copy %%r31,%%r2", xoperands);
delay_slot_filled = 1;
}
}
}
}
}
if (!delay_slot_filled && (seq_length == 0 || delay_insn_deleted))
output_asm_insn ("nop", xoperands);
if (seq_length == 0
|| delay_insn_deleted
|| GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
return "";
if (sibcall)
abort ();
xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
if (!delay_slot_filled && INSN_ADDRESSES_SET_P ())
{
rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
- INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
if (VAL_14_BITS_P (distance))
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
}
else
output_asm_insn ("nop\n\tb,n %0", xoperands);
}
else
output_asm_insn ("b,n %0", xoperands);
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
return "";
}
int
attr_length_indirect_call (rtx insn)
{
unsigned long distance = -1;
unsigned long total = IN_NAMED_SECTION_P (cfun->decl) ? 0 : total_code_bytes;
if (INSN_ADDRESSES_SET_P ())
{
distance = (total + insn_current_reference_address (insn));
if (distance < total)
distance = -1;
}
if (TARGET_64BIT)
return 12;
if (TARGET_FAST_INDIRECT_CALLS
|| (!TARGET_PORTABLE_RUNTIME
&& ((TARGET_PA_20 && distance < 7600000) || distance < 240000)))
return 8;
if (flag_pic)
return 24;
if (TARGET_PORTABLE_RUNTIME)
return 20;
return 12;
}
const char *
output_indirect_call (rtx insn, rtx call_dest)
{
rtx xoperands[1];
if (TARGET_64BIT)
{
xoperands[0] = call_dest;
output_asm_insn ("ldd 16(%0),%%r2", xoperands);
output_asm_insn ("bve,l (%%r2),%%r2\n\tldd 24(%0),%%r27", xoperands);
return "";
}
if (TARGET_FAST_INDIRECT_CALLS)
return "ble 0(%%sr4,%%r22)\n\tcopy %%r31,%%r2";
if (attr_length_indirect_call (insn) == 8)
{
if (TARGET_PA_20)
return ".CALL\tARGW0=GR\n\tb,l $$dyncall,%%r2\n\tcopy %%r2,%%r31";
else
return ".CALL\tARGW0=GR\n\tbl $$dyncall,%%r31\n\tcopy %%r31,%%r2";
}
if (attr_length_indirect_call (insn) == 12)
return ".CALL\tARGW0=GR\n\tldil L'$$dyncall,%%r2\n\tble R'$$dyncall(%%sr4,%%r2)\n\tcopy %%r31,%%r2";
if (attr_length_indirect_call (insn) == 20)
return "ldil L'$$dyncall,%%r31\n\tldo R'$$dyncall(%%r31),%%r31\n\tblr %%r0,%%r2\n\tbv,n %%r0(%%r31)\n\tnop";
xoperands[0] = NULL_RTX;
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
if (TARGET_SOM || !TARGET_GAS)
{
xoperands[0] = gen_label_rtx ();
output_asm_insn ("addil L'$$dyncall-%0,%%r1", xoperands);
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[0]));
output_asm_insn ("ldo R'$$dyncall-%0(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'$$dyncall-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'$$dyncall-$PIC_pcrel$0+8(%%r1),%%r1",
xoperands);
}
output_asm_insn ("blr %%r0,%%r2", xoperands);
output_asm_insn ("bv,n %%r0(%%r1)\n\tnop", xoperands);
return "";
}
int
attr_length_save_restore_dltp (rtx insn)
{
if (find_reg_note (insn, REG_NORETURN, NULL_RTX))
return 0;
return 8;
}
void
hppa_encode_label (rtx sym)
{
const char *str = XSTR (sym, 0);
int len = strlen (str) + 1;
char *newstr, *p;
p = newstr = alloca (len + 1);
*p++ = '@';
strcpy (p, str);
XSTR (sym, 0) = ggc_alloc_string (newstr, len);
}
static void
pa_encode_section_info (tree decl, rtx rtl, int first)
{
if (first && TEXT_SPACE_P (decl))
{
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
if (TREE_CODE (decl) == FUNCTION_DECL)
hppa_encode_label (XEXP (rtl, 0));
}
}
static const char *
pa_strip_name_encoding (const char *str)
{
str += (*str == '@');
str += (*str == '*');
return str;
}
int
function_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == SYMBOL_REF && FUNCTION_NAME_P (XSTR (op, 0));
}
int
is_function_label_plus_const (rtx op)
{
if (GET_CODE (op) == CONST)
op = XEXP (op, 0);
return (GET_CODE (op) == PLUS
&& function_label_operand (XEXP (op, 0), Pmode)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
}
static void
pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
tree function)
{
static unsigned int current_thunk_number;
int val_14 = VAL_14_BITS_P (delta);
int nbytes = 0;
char label[16];
rtx xoperands[4];
xoperands[0] = XEXP (DECL_RTL (function), 0);
xoperands[1] = XEXP (DECL_RTL (thunk_fndecl), 0);
xoperands[2] = GEN_INT (delta);
ASM_OUTPUT_LABEL (file, XSTR (xoperands[1], 0));
fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=0,NO_CALLS\n\t.ENTRY\n");
if ((!TARGET_LONG_CALLS && TARGET_SOM && !TARGET_PORTABLE_RUNTIME
&& !(flag_pic && TREE_PUBLIC (function))
&& (TARGET_GAS || last_address < 262132))
|| (!TARGET_LONG_CALLS && !TARGET_SOM && !TARGET_PORTABLE_RUNTIME
&& ((targetm.have_named_sections
&& DECL_SECTION_NAME (thunk_fndecl) != NULL
&& ((!TARGET_64BIT
&& (DECL_SECTION_NAME (thunk_fndecl)
!= DECL_SECTION_NAME (function)))
|| ((DECL_SECTION_NAME (thunk_fndecl)
== DECL_SECTION_NAME (function))
&& last_address < 262132)))
|| (!targetm.have_named_sections && last_address < 262132))))
{
if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands);
output_asm_insn ("b %0", xoperands);
if (val_14)
{
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
nbytes += 8;
}
else
{
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
nbytes += 12;
}
}
else if (TARGET_64BIT)
{
if (!val_14)
{
output_asm_insn ("addil L'%2,%%r26", xoperands);
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
}
output_asm_insn ("b,l .+8,%%r1", xoperands);
if (TARGET_GAS)
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
else
{
xoperands[3] = GEN_INT (val_14 ? 8 : 16);
output_asm_insn ("addil L'%0-%1-%3,%%r1", xoperands);
}
if (val_14)
{
output_asm_insn ("bv %%r0(%%r1)", xoperands);
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
nbytes += 20;
}
else
{
output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
nbytes += 24;
}
}
else if (TARGET_PORTABLE_RUNTIME)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands);
if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands);
output_asm_insn ("bv %%r0(%%r22)", xoperands);
if (val_14)
{
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
nbytes += 16;
}
else
{
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
nbytes += 20;
}
}
else if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
{
ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number);
xoperands[3] = gen_rtx_SYMBOL_REF (Pmode, label);
output_asm_insn ("addil LT'%3,%%r19", xoperands);
output_asm_insn ("ldw RT'%3(%%r1),%%r22", xoperands);
output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands);
output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands);
output_asm_insn ("depi 0,31,2,%%r22", xoperands);
output_asm_insn ("ldw 4(%%sr0,%%r22),%%r19", xoperands);
output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands);
if (!val_14)
{
output_asm_insn ("addil L'%2,%%r26", xoperands);
nbytes += 4;
}
if (TARGET_PA_20)
{
output_asm_insn ("bve (%%r22)", xoperands);
nbytes += 36;
}
else if (TARGET_NO_SPACE_REGS)
{
output_asm_insn ("be 0(%%sr4,%%r22)", xoperands);
nbytes += 36;
}
else
{
output_asm_insn ("ldsid (%%sr0,%%r22),%%r21", xoperands);
output_asm_insn ("mtsp %%r21,%%sr0", xoperands);
output_asm_insn ("be 0(%%sr0,%%r22)", xoperands);
nbytes += 44;
}
if (val_14)
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
else
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
}
else if (flag_pic)
{
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
if (TARGET_SOM || !TARGET_GAS)
{
output_asm_insn ("addil L'%0-%1-8,%%r1", xoperands);
output_asm_insn ("ldo R'%0-%1-8(%%r1),%%r22", xoperands);
}
else
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r22", xoperands);
}
if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands);
output_asm_insn ("bv %%r0(%%r22)", xoperands);
if (val_14)
{
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
nbytes += 20;
}
else
{
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
nbytes += 24;
}
}
else
{
if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands);
output_asm_insn ("ldil L'%0,%%r22", xoperands);
output_asm_insn ("be R'%0(%%sr4,%%r22)", xoperands);
if (val_14)
{
output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
nbytes += 12;
}
else
{
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
nbytes += 16;
}
}
fprintf (file, "\t.EXIT\n\t.PROCEND\n");
if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
{
data_section ();
output_asm_insn (".align 4", xoperands);
ASM_OUTPUT_LABEL (file, label);
output_asm_insn (".word P'%0", xoperands);
}
else if (TARGET_SOM && TARGET_GAS)
forget_section ();
current_thunk_number++;
nbytes = ((nbytes + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
& ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
last_address += nbytes;
update_total_code_bytes (nbytes);
}
static bool
pa_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
{
if (TARGET_PORTABLE_RUNTIME)
return false;
if (TARGET_ELF32)
return (decl != NULL_TREE);
if (TARGET_64BIT)
return false;
return (decl && !TREE_PUBLIC (decl));
}
int
fmpyaddoperands (rtx *operands)
{
enum machine_mode mode = GET_MODE (operands[0]);
if (mode != SFmode && mode != DFmode)
return 0;
if (! (mode == GET_MODE (operands[1])
&& mode == GET_MODE (operands[2])
&& mode == GET_MODE (operands[3])
&& mode == GET_MODE (operands[4])
&& mode == GET_MODE (operands[5])))
return 0;
if (! (GET_CODE (operands[1]) == REG
&& GET_CODE (operands[2]) == REG
&& GET_CODE (operands[3]) == REG
&& GET_CODE (operands[4]) == REG
&& GET_CODE (operands[5]) == REG))
return 0;
if (! rtx_equal_p (operands[3], operands[4])
&& ! rtx_equal_p (operands[3], operands[5]))
return 0;
if (rtx_equal_p (operands[3], operands[0])
|| rtx_equal_p (operands[3], operands[1])
|| rtx_equal_p (operands[3], operands[2]))
return 0;
if (rtx_equal_p (operands[4], operands[0])
|| rtx_equal_p (operands[5], operands[0]))
return 0;
if (mode == SFmode
&& (REGNO_REG_CLASS (REGNO (operands[0])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[1])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[2])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[3])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[4])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[5])) != FPUPPER_REGS))
return 0;
return 1;
}
#if !defined(USE_COLLECT2)
static void
pa_asm_out_constructor (rtx symbol, int priority)
{
if (!function_label_operand (symbol, VOIDmode))
hppa_encode_label (symbol);
#ifdef CTORS_SECTION_ASM_OP
default_ctor_section_asm_out_constructor (symbol, priority);
#else
# ifdef TARGET_ASM_NAMED_SECTION
default_named_section_asm_out_constructor (symbol, priority);
# else
default_stabs_asm_out_constructor (symbol, priority);
# endif
#endif
}
static void
pa_asm_out_destructor (rtx symbol, int priority)
{
if (!function_label_operand (symbol, VOIDmode))
hppa_encode_label (symbol);
#ifdef DTORS_SECTION_ASM_OP
default_dtor_section_asm_out_destructor (symbol, priority);
#else
# ifdef TARGET_ASM_NAMED_SECTION
default_named_section_asm_out_destructor (symbol, priority);
# else
default_stabs_asm_out_destructor (symbol, priority);
# endif
#endif
}
#endif
void
pa_asm_output_aligned_bss (FILE *stream,
const char *name,
unsigned HOST_WIDE_INT size,
unsigned int align)
{
bss_section ();
fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
#endif
#ifdef ASM_OUTPUT_SIZE_DIRECTIVE
ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
#endif
fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
ASM_OUTPUT_LABEL (stream, name);
fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
}
void
pa_asm_output_aligned_common (FILE *stream,
const char *name,
unsigned HOST_WIDE_INT size,
unsigned int align)
{
unsigned int max_common_align;
max_common_align = TARGET_64BIT ? 128 : (size >= 4096 ? 256 : 64);
if (align > max_common_align)
{
warning ("alignment (%u) for %s exceeds maximum alignment "
"for global common data. Using %u",
align / BITS_PER_UNIT, name, max_common_align / BITS_PER_UNIT);
align = max_common_align;
}
bss_section ();
assemble_name (stream, name);
fprintf (stream, "\t.comm "HOST_WIDE_INT_PRINT_UNSIGNED"\n",
MAX (size, align / BITS_PER_UNIT));
}
void
pa_asm_output_aligned_local (FILE *stream,
const char *name,
unsigned HOST_WIDE_INT size,
unsigned int align)
{
bss_section ();
fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
#ifdef LOCAL_ASM_OP
fprintf (stream, "%s", LOCAL_ASM_OP);
assemble_name (stream, name);
fprintf (stream, "\n");
#endif
ASM_OUTPUT_LABEL (stream, name);
fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
}
int
fmpysuboperands (rtx *operands)
{
enum machine_mode mode = GET_MODE (operands[0]);
if (mode != SFmode && mode != DFmode)
return 0;
if (! (mode == GET_MODE (operands[1])
&& mode == GET_MODE (operands[2])
&& mode == GET_MODE (operands[3])
&& mode == GET_MODE (operands[4])
&& mode == GET_MODE (operands[5])))
return 0;
if (! (GET_CODE (operands[1]) == REG
&& GET_CODE (operands[2]) == REG
&& GET_CODE (operands[3]) == REG
&& GET_CODE (operands[4]) == REG
&& GET_CODE (operands[5]) == REG))
return 0;
if (! rtx_equal_p (operands[3], operands[4]))
return 0;
if (rtx_equal_p (operands[5], operands[0]))
return 0;
if (rtx_equal_p (operands[3], operands[0])
|| rtx_equal_p (operands[3], operands[1])
|| rtx_equal_p (operands[3], operands[2]))
return 0;
if (mode == SFmode
&& (REGNO_REG_CLASS (REGNO (operands[0])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[1])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[2])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[3])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[4])) != FPUPPER_REGS
|| REGNO_REG_CLASS (REGNO (operands[5])) != FPUPPER_REGS))
return 0;
return 1;
}
int
plus_xor_ior_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR
|| GET_CODE (op) == IOR);
}
static int
shadd_constant_p (int val)
{
if (val == 2 || val == 4 || val == 8)
return 1;
else
return 0;
}
int
shadd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
}
int
borx_reg_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != REG)
return 0;
if (op == virtual_incoming_args_rtx
|| op == virtual_stack_vars_rtx
|| op == virtual_stack_dynamic_rtx
|| op == virtual_outgoing_args_rtx
|| op == virtual_cfa_rtx)
return 0;
if (!reload_completed
&& flag_omit_frame_pointer
&& !current_function_calls_alloca
&& op == frame_pointer_rtx)
return 0;
return register_operand (op, mode);
}
int
non_hard_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ! (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER);
}
static int
forward_branch_p (rtx insn)
{
rtx label = JUMP_LABEL (insn);
while (insn)
{
if (insn == label)
break;
else
insn = NEXT_INSN (insn);
}
return (insn == label);
}
int
eq_neq_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
}
int
movb_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE
|| GET_CODE (op) == LT || GET_CODE (op) == GE);
}
int
jump_in_call_delay (rtx insn)
{
if (GET_CODE (insn) != JUMP_INSN)
return 0;
if (PREV_INSN (insn)
&& PREV_INSN (PREV_INSN (insn))
&& GET_CODE (next_real_insn (PREV_INSN (PREV_INSN (insn)))) == INSN)
{
rtx test_insn = next_real_insn (PREV_INSN (PREV_INSN (insn)));
return (GET_CODE (PATTERN (test_insn)) == SEQUENCE
&& XVECEXP (PATTERN (test_insn), 0, 1) == insn);
}
else
return 0;
}
const char *
output_parallel_movb (rtx *operands, int length)
{
if (length == 4)
return "mov%I1b,tr %1,%0,%2";
if (dbr_sequence_length () == 0)
{
if (GET_CODE (operands[1]) == CONST_INT)
return "b %2\n\tldi %1,%0";
else
return "b %2\n\tcopy %1,%0";
}
else
{
if (GET_CODE (operands[1]) == CONST_INT)
return "ldi %1,%0\n\tb %2";
else
return "copy %1,%0\n\tb %2";
}
}
const char *
output_parallel_addb (rtx *operands, int length)
{
if (operands[0] == operands[1])
operands[1] = operands[2];
if (length == 4)
return "add%I1b,tr %1,%0,%3";
if (dbr_sequence_length () == 0)
{
return "b %3\n\tadd%I1 %1,%0,%0";
}
else
{
return "add%I1 %1,%0,%0\n\tb %3";
}
}
int
following_call (rtx insn)
{
if (! TARGET_JUMP_IN_DELAY)
return 0;
insn = PREV_INSN (insn);
while (insn && GET_CODE (insn) == NOTE)
insn = PREV_INSN (insn);
if (insn
&& ((GET_CODE (insn) == CALL_INSN
&& get_attr_type (insn) != TYPE_DYNCALL)
|| (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) != SEQUENCE
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& get_attr_type (insn) == TYPE_MILLI)))
return 1;
return 0;
}
static void
pa_reorg (void)
{
rtx insn;
remove_useless_addtr_insns (1);
if (pa_cpu < PROCESSOR_8000)
pa_combine_instructions ();
if (optimize > 0 && !TARGET_BIG_SWITCH)
{
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx pattern, tmp, location, label;
unsigned int length, i;
if (GET_CODE (insn) != JUMP_INSN
|| (GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC))
continue;
emit_insn_before (gen_begin_brtab (), insn);
pattern = PATTERN (insn);
location = PREV_INSN (insn);
length = XVECLEN (pattern, GET_CODE (pattern) == ADDR_DIFF_VEC);
for (i = 0; i < length; i++)
{
tmp = gen_label_rtx ();
LABEL_NUSES (tmp) = 1;
emit_label_after (tmp, location);
location = NEXT_INSN (location);
if (GET_CODE (pattern) == ADDR_VEC)
label = XEXP (XVECEXP (pattern, 0, i), 0);
else
label = XEXP (XVECEXP (pattern, 1, i), 0);
tmp = gen_short_jump (label);
tmp = emit_jump_insn_after (tmp, location);
JUMP_LABEL (tmp) = label;
LABEL_NUSES (label)++;
location = NEXT_INSN (location);
emit_barrier_after (location);
location = NEXT_INSN (location);
}
emit_insn_before (gen_end_brtab (), location);
location = NEXT_INSN (location);
emit_barrier_after (location);
delete_insn (insn);
}
}
else
{
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) != JUMP_INSN
|| (GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC))
continue;
emit_insn_before (gen_begin_brtab (), insn);
emit_insn_after (gen_end_brtab (), insn);
}
}
}
static void
pa_combine_instructions (void)
{
rtx anchor, new;
if (optimize < 2)
return;
new = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, NULL_RTX, NULL_RTX));
new = make_insn_raw (new);
for (anchor = get_insns (); anchor; anchor = NEXT_INSN (anchor))
{
enum attr_pa_combine_type anchor_attr;
enum attr_pa_combine_type floater_attr;
if ((GET_CODE (anchor) != INSN
&& GET_CODE (anchor) != JUMP_INSN
&& GET_CODE (anchor) != CALL_INSN)
|| GET_CODE (PATTERN (anchor)) == USE
|| GET_CODE (PATTERN (anchor)) == CLOBBER
|| GET_CODE (PATTERN (anchor)) == ADDR_VEC
|| GET_CODE (PATTERN (anchor)) == ADDR_DIFF_VEC)
continue;
anchor_attr = get_attr_pa_combine_type (anchor);
if (anchor_attr == PA_COMBINE_TYPE_FMPY
|| anchor_attr == PA_COMBINE_TYPE_FADDSUB
|| (anchor_attr == PA_COMBINE_TYPE_UNCOND_BRANCH
&& ! forward_branch_p (anchor)))
{
rtx floater;
for (floater = PREV_INSN (anchor);
floater;
floater = PREV_INSN (floater))
{
if (GET_CODE (floater) == NOTE
|| (GET_CODE (floater) == INSN
&& (GET_CODE (PATTERN (floater)) == USE
|| GET_CODE (PATTERN (floater)) == CLOBBER)))
continue;
if (GET_CODE (floater) != INSN
|| GET_CODE (PATTERN (floater)) == ADDR_VEC
|| GET_CODE (PATTERN (floater)) == ADDR_DIFF_VEC)
{
floater = NULL_RTX;
break;
}
floater_attr = get_attr_pa_combine_type (floater);
if ((anchor_attr == PA_COMBINE_TYPE_FMPY
&& floater_attr == PA_COMBINE_TYPE_FADDSUB)
|| (anchor_attr == PA_COMBINE_TYPE_FADDSUB
&& floater_attr == PA_COMBINE_TYPE_FMPY))
{
if (pa_can_combine_p (new, anchor, floater, 0,
SET_DEST (PATTERN (floater)),
XEXP (SET_SRC (PATTERN (floater)), 0),
XEXP (SET_SRC (PATTERN (floater)), 1)))
break;
}
else if (anchor_attr == PA_COMBINE_TYPE_UNCOND_BRANCH
&& floater_attr == PA_COMBINE_TYPE_ADDMOVE)
{
if (GET_CODE (SET_SRC (PATTERN (floater))) == PLUS)
{
if (pa_can_combine_p (new, anchor, floater, 0,
SET_DEST (PATTERN (floater)),
XEXP (SET_SRC (PATTERN (floater)), 0),
XEXP (SET_SRC (PATTERN (floater)), 1)))
break;
}
else
{
if (pa_can_combine_p (new, anchor, floater, 0,
SET_DEST (PATTERN (floater)),
SET_SRC (PATTERN (floater)),
SET_SRC (PATTERN (floater))))
break;
}
}
}
if (!floater
&& (anchor_attr == PA_COMBINE_TYPE_FMPY
|| anchor_attr == PA_COMBINE_TYPE_FADDSUB))
{
for (floater = anchor; floater; floater = NEXT_INSN (floater))
{
if (GET_CODE (floater) == NOTE
|| (GET_CODE (floater) == INSN
&& (GET_CODE (PATTERN (floater)) == USE
|| GET_CODE (PATTERN (floater)) == CLOBBER)))
continue;
if (GET_CODE (floater) != INSN
|| GET_CODE (PATTERN (floater)) == ADDR_VEC
|| GET_CODE (PATTERN (floater)) == ADDR_DIFF_VEC)
{
floater = NULL_RTX;
break;
}
floater_attr = get_attr_pa_combine_type (floater);
if ((anchor_attr == PA_COMBINE_TYPE_FMPY
&& floater_attr == PA_COMBINE_TYPE_FADDSUB)
|| (anchor_attr == PA_COMBINE_TYPE_FADDSUB
&& floater_attr == PA_COMBINE_TYPE_FMPY))
{
if (pa_can_combine_p (new, anchor, floater, 1,
SET_DEST (PATTERN (floater)),
XEXP (SET_SRC (PATTERN (floater)),
0),
XEXP (SET_SRC (PATTERN (floater)),
1)))
break;
}
}
}
if (floater
&& (anchor_attr == PA_COMBINE_TYPE_FADDSUB
|| anchor_attr == PA_COMBINE_TYPE_FMPY))
{
emit_insn_before (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2, PATTERN (anchor),
PATTERN (floater))),
anchor);
PUT_CODE (anchor, NOTE);
NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (anchor) = 0;
emit_insn_before (gen_rtx_USE (VOIDmode, floater), floater);
delete_insn (floater);
continue;
}
else if (floater
&& anchor_attr == PA_COMBINE_TYPE_UNCOND_BRANCH)
{
rtx temp;
temp
= emit_jump_insn_before (gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2, PATTERN (anchor),
PATTERN (floater))),
anchor);
JUMP_LABEL (temp) = JUMP_LABEL (anchor);
PUT_CODE (anchor, NOTE);
NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (anchor) = 0;
emit_insn_before (gen_rtx_USE (VOIDmode, floater), floater);
delete_insn (floater);
continue;
}
}
}
}
static int
pa_can_combine_p (rtx new, rtx anchor, rtx floater, int reversed, rtx dest,
rtx src1, rtx src2)
{
int insn_code_number;
rtx start, end;
XVECEXP (PATTERN (new), 0, 0) = PATTERN (anchor);
XVECEXP (PATTERN (new), 0, 1) = PATTERN (floater);
INSN_CODE (new) = -1;
insn_code_number = recog_memoized (new);
if (insn_code_number < 0
|| (extract_insn (new), ! constrain_operands (1)))
return 0;
if (reversed)
{
start = anchor;
end = floater;
}
else
{
start = floater;
end = anchor;
}
if (reg_used_between_p (dest, start, end))
return 0;
if (reg_set_between_p (src1, start, end))
return 0;
if (reg_set_between_p (src2, start, end))
return 0;
return 1;
}
int
insn_refs_are_delayed (rtx insn)
{
return ((GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) != SEQUENCE
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& get_attr_type (insn) == TYPE_MILLI));
}
rtx
function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
{
enum machine_mode valmode;
if (TARGET_64BIT && AGGREGATE_TYPE_P (valtype))
{
rtx loc[2];
int i, offset = 0;
int ub = int_size_in_bytes (valtype) <= UNITS_PER_WORD ? 1 : 2;
for (i = 0; i < ub; i++)
{
loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (DImode, 28 + i),
GEN_INT (offset));
offset += 8;
}
return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (ub, loc));
}
if ((INTEGRAL_TYPE_P (valtype)
&& TYPE_PRECISION (valtype) < BITS_PER_WORD)
|| POINTER_TYPE_P (valtype))
valmode = word_mode;
else
valmode = TYPE_MODE (valtype);
if (TREE_CODE (valtype) == REAL_TYPE
&& TYPE_MODE (valtype) != TFmode
&& !TARGET_SOFT_FLOAT)
return gen_rtx_REG (valmode, 32);
return gen_rtx_REG (valmode, 28);
}
rtx
function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
int named ATTRIBUTE_UNUSED)
{
int max_arg_words = (TARGET_64BIT ? 8 : 4);
int alignment = 0;
int arg_size;
int fpr_reg_base;
int gpr_reg_base;
rtx retval;
if (mode == VOIDmode)
return NULL_RTX;
arg_size = FUNCTION_ARG_SIZE (mode, type);
if (! TARGET_64BIT)
{
if (cum->words + arg_size > max_arg_words)
return NULL_RTX;
}
else
{
if (arg_size > 1)
alignment = cum->words & 1;
if (cum->words + alignment >= max_arg_words)
return NULL_RTX;
}
if (TARGET_64BIT)
{
gpr_reg_base = 26 - cum->words;
fpr_reg_base = 32 + cum->words;
if (arg_size > 1
|| mode == BLKmode
|| (type && AGGREGATE_TYPE_P (type)))
{
rtx loc[8];
int i, offset = 0, ub = arg_size;
gpr_reg_base -= alignment;
ub = MIN (ub, max_arg_words - cum->words - alignment);
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;
}
return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
}
}
else
{
if (arg_size > 1)
{
if (cum->words)
{
gpr_reg_base = 23;
fpr_reg_base = 38;
}
else
{
gpr_reg_base = 25;
fpr_reg_base = 34;
}
if (mode == BLKmode)
{
rtx loc = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (DImode, gpr_reg_base),
const0_rtx);
return gen_rtx_PARALLEL (mode, gen_rtvec (1, loc));
}
}
else
{
gpr_reg_base = 26 - cum->words;
fpr_reg_base = 32 + 2 * cum->words;
}
}
if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
&& !TARGET_SOFT_FLOAT
&& FLOAT_MODE_P (mode)
&& cum->nargs_prototype <= 0
&& type != NULL_TREE
&& !cum->incoming)
|| (!TARGET_64BIT
&& !TARGET_GAS
&& !cum->incoming
&& cum->indirect
&& FLOAT_MODE_P (mode)))
{
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
{
if (TARGET_SOFT_FLOAT
|| (!TARGET_PORTABLE_RUNTIME
&& !TARGET_64BIT
&& !TARGET_ELF32
&& cum->indirect)
|| !FLOAT_MODE_P (mode))
retval = gen_rtx_REG (mode, gpr_reg_base);
else
retval = gen_rtx_REG (mode, fpr_reg_base);
}
return retval;
}
static int
pa_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, bool named ATTRIBUTE_UNUSED)
{
unsigned int max_arg_words = 8;
unsigned int offset = 0;
if (!TARGET_64BIT)
return 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)
return 0;
else if (cum->words + offset >= max_arg_words)
return 0;
else
return (max_arg_words - cum->words - offset) * UNITS_PER_WORD;
}
int
cmpib_comparison_operator (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) == GTU
|| GET_CODE (op) == GE
|| GET_CODE (op) == LT
|| GET_CODE (op) == LE
|| GET_CODE (op) == LEU));
}
const char *
som_text_section_asm_op (void)
{
if (!TARGET_SOM)
return "";
if (TARGET_GAS)
{
if (cfun && !cfun->machine->in_nsubspa)
{
cfun->machine->in_nsubspa = 1;
if (cfun->decl
&& DECL_ONE_ONLY (cfun->decl)
&& !DECL_WEAK (cfun->decl))
return
"\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,SORT=24,COMDAT";
return "\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$";
}
else
{
forget_section ();
}
}
return "\t.SPACE $TEXT$\n\t.SUBSPA $CODE$";
}
static void
pa_select_section (tree exp, int reloc,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
if (TREE_CODE (exp) == VAR_DECL
&& TREE_READONLY (exp)
&& !TREE_THIS_VOLATILE (exp)
&& DECL_INITIAL (exp)
&& (DECL_INITIAL (exp) == error_mark_node
|| TREE_CONSTANT (DECL_INITIAL (exp)))
&& !reloc)
{
if (TARGET_SOM
&& DECL_ONE_ONLY (exp)
&& !DECL_WEAK (exp))
som_one_only_readonly_data_section ();
else
readonly_data_section ();
}
else if (CONSTANT_CLASS_P (exp) && !reloc)
readonly_data_section ();
else if (TARGET_SOM
&& TREE_CODE (exp) == VAR_DECL
&& DECL_ONE_ONLY (exp)
&& !DECL_WEAK (exp))
som_one_only_data_section ();
else
data_section ();
}
static void
pa_globalize_label (FILE *stream, const char *name)
{
if (! FUNCTION_NAME_P (name))
{
fputs ("\t.EXPORT ", stream);
assemble_name (stream, name);
fputs (",DATA\n", stream);
}
}
static rtx
pa_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
int incoming ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (Pmode, PA_STRUCT_VALUE_REGNUM);
}
bool
pa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
return (int_size_in_bytes (type) > (TARGET_64BIT ? 16 : 8)
|| int_size_in_bytes (type) <= 0);
}
struct extern_symbol GTY(())
{
tree decl;
const char *name;
};
typedef struct extern_symbol *extern_symbol;
DEF_VEC_GC_P(extern_symbol);
static GTY(()) VEC(extern_symbol) *extern_symbols;
#ifdef ASM_OUTPUT_EXTERNAL_REAL
void
pa_hpux_asm_output_external (FILE *file, tree decl, const char *name)
{
extern_symbol p = ggc_alloc (sizeof (struct extern_symbol));
gcc_assert (file == asm_out_file);
p->decl = decl;
p->name = name;
VEC_safe_push (extern_symbol, extern_symbols, p);
}
static void
pa_hpux_file_end (void)
{
unsigned int i;
extern_symbol p;
output_deferred_plabels ();
for (i = 0; VEC_iterate (extern_symbol, extern_symbols, i, p); i++)
{
tree decl = p->decl;
if (!TREE_ASM_WRITTEN (decl)
&& SYMBOL_REF_REFERENCED_P (XEXP (DECL_RTL (decl), 0)))
ASM_OUTPUT_EXTERNAL_REAL (asm_out_file, decl, p->name);
}
extern_symbols = NULL;
}
#endif
#include "gt-pa.h"