#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "reload.h"
#include "expr.h"
#include "obstack.h"
#include "except.h"
#include "function.h"
#include "optabs.h"
#include "toplev.h"
#include "basic-block.h"
#include "tm_p.h"
#include "ggc.h"
#include <ctype.h>
#include "target.h"
#include "target-def.h"
#include "targhooks.h"
#include "integrate.h"
#include "langhooks.h"
#ifndef FRV_INLINE
#define FRV_INLINE inline
#endif
#define NUM_NOP_PATTERNS 3
enum frv_insn_group { GROUP_I, GROUP_FM, GROUP_B, GROUP_C, NUM_GROUPS };
static const char *const frv_unit_names[] =
{
"c",
"i0", "f0",
"i1", "f1",
"i2", "f2",
"i3", "f3",
"b0", "b1"
};
static const enum frv_insn_group frv_unit_groups[ARRAY_SIZE (frv_unit_names)] =
{
GROUP_C,
GROUP_I, GROUP_FM,
GROUP_I, GROUP_FM,
GROUP_I, GROUP_FM,
GROUP_I, GROUP_FM,
GROUP_B, GROUP_B
};
#define NTH_UNIT(GROUP, N) frv_unit_codes[(GROUP) + (N) * 2 + 1]
#define UNIT_NUMBER(UNIT) (((UNIT) - 1) / 2)
static int frv_unit_codes[ARRAY_SIZE (frv_unit_names)];
static unsigned int frv_type_to_unit[TYPE_UNKNOWN + 1];
static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
static unsigned int frv_num_nops;
#define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
#define SET_PACKING_FLAG(INSN) PUT_MODE (INSN, TImode)
#define CLEAR_PACKING_FLAG(INSN) PUT_MODE (INSN, VOIDmode)
#define FOR_EACH_REGNO(REG, X) \
for (REG = REGNO (X); \
REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \
REG++)
struct frv_unspec {
rtx symbol;
int reloc;
HOST_WIDE_INT offset;
};
typedef struct frv_tmp_reg_struct
{
HARD_REG_SET regs;
int next_reg[N_REG_CLASSES];
}
frv_tmp_reg_t;
#define REGSTATE_CC_MASK 0x07
#define REGSTATE_MODIFIED 0x08
#define REGSTATE_IF_TRUE 0x10
#define REGSTATE_IF_FALSE 0x20
#define REGSTATE_IF_EITHER (REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
typedef unsigned char regstate_t;
enum frv_stack_op
{
FRV_LOAD,
FRV_STORE
};
typedef struct
{
enum frv_stack_op op;
rtx base;
int base_offset;
} frv_frame_accessor_t;
rtx frv_compare_op0;
rtx frv_compare_op1;
typedef struct
{
rtx added_insns_list;
frv_tmp_reg_t tmp_reg;
HARD_REG_SET nested_cc_ok_rewrite;
rtx scratch_regs[FIRST_PSEUDO_REGISTER];
int cur_scratch_regs;
int num_nested_cond_exec;
bitmap scratch_insns_bitmap;
rtx cr_reg;
rtx nested_cc_reg;
rtx extra_int_cr;
rtx extra_fp_cr;
rtx last_nested_if_cr;
}
frv_ifcvt_t;
static frv_ifcvt_t frv_ifcvt;
enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
enum reg_class reg_class_from_letter[256];
static frv_stack_t *frv_stack_cache = (frv_stack_t *)0;
const char *frv_branch_cost_string;
int frv_branch_cost_int = DEFAULT_BRANCH_COST;
const char *frv_cpu_string;
frv_cpu_t frv_cpu_type = CPU_TYPE;
const char *frv_condexec_insns_str;
int frv_condexec_insns = DEFAULT_CONDEXEC_INSNS;
const char *frv_condexec_temps_str;
int frv_condexec_temps = DEFAULT_CONDEXEC_TEMPS;
const char *frv_sched_lookahead_str;
int frv_sched_lookahead = 4;
static int frv_default_flags_for_cpu (void);
static int frv_string_begins_with (tree, const char *);
static FRV_INLINE bool frv_small_data_reloc_p (rtx, int);
static FRV_INLINE bool frv_const_unspec_p (rtx, struct frv_unspec *);
static void frv_print_operand_memory_reference_reg
(FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int);
static int frv_print_operand_jump_hint (rtx);
static const char *comparison_string (enum rtx_code, rtx);
static FRV_INLINE int frv_regno_ok_for_base_p (int, int);
static rtx single_set_pattern (rtx);
static int frv_function_contains_far_jump (void);
static rtx frv_alloc_temp_reg (frv_tmp_reg_t *,
enum reg_class,
enum machine_mode,
int, int);
static rtx frv_frame_offset_rtx (int);
static rtx frv_frame_mem (enum machine_mode, rtx, int);
static rtx frv_dwarf_store (rtx, int);
static void frv_frame_insn (rtx, rtx);
static void frv_frame_access (frv_frame_accessor_t*,
rtx, int);
static void frv_frame_access_multi (frv_frame_accessor_t*,
frv_stack_t *, int);
static void frv_frame_access_standard_regs (enum frv_stack_op,
frv_stack_t *);
static struct machine_function *frv_init_machine_status (void);
static int frv_legitimate_memory_operand (rtx, enum machine_mode, int);
static rtx frv_int_to_acc (enum insn_code, int, rtx);
static enum machine_mode frv_matching_accg_mode (enum machine_mode);
static rtx frv_read_argument (tree *);
static rtx frv_read_iacc_argument (enum machine_mode, tree *);
static int frv_check_constant_argument (enum insn_code, int, rtx);
static rtx frv_legitimize_target (enum insn_code, rtx);
static rtx frv_legitimize_argument (enum insn_code, int, rtx);
static rtx frv_legitimize_tls_address (rtx, enum tls_model);
static rtx frv_expand_set_builtin (enum insn_code, tree, rtx);
static rtx frv_expand_unop_builtin (enum insn_code, tree, rtx);
static rtx frv_expand_binop_builtin (enum insn_code, tree, rtx);
static rtx frv_expand_cut_builtin (enum insn_code, tree, rtx);
static rtx frv_expand_binopimm_builtin (enum insn_code, tree, rtx);
static rtx frv_expand_voidbinop_builtin (enum insn_code, tree);
static rtx frv_expand_int_void2arg (enum insn_code, tree);
static rtx frv_expand_prefetches (enum insn_code, tree);
static rtx frv_expand_voidtriop_builtin (enum insn_code, tree);
static rtx frv_expand_voidaccop_builtin (enum insn_code, tree);
static rtx frv_expand_mclracc_builtin (tree);
static rtx frv_expand_mrdacc_builtin (enum insn_code, tree);
static rtx frv_expand_mwtacc_builtin (enum insn_code, tree);
static rtx frv_expand_noargs_builtin (enum insn_code);
static void frv_split_iacc_move (rtx, rtx);
static rtx frv_emit_comparison (enum rtx_code, rtx, rtx);
static int frv_clear_registers_used (rtx *, void *);
static void frv_ifcvt_add_insn (rtx, rtx, int);
static rtx frv_ifcvt_rewrite_mem (rtx, enum machine_mode, rtx);
static rtx frv_ifcvt_load_value (rtx, rtx);
static int frv_acc_group_1 (rtx *, void *);
static unsigned int frv_insn_unit (rtx);
static bool frv_issues_to_branch_unit_p (rtx);
static int frv_cond_flags (rtx);
static bool frv_regstate_conflict_p (regstate_t, regstate_t);
static int frv_registers_conflict_p_1 (rtx *, void *);
static bool frv_registers_conflict_p (rtx);
static void frv_registers_update_1 (rtx, rtx, void *);
static void frv_registers_update (rtx);
static void frv_start_packet (void);
static void frv_start_packet_block (void);
static void frv_finish_packet (void (*) (void));
static bool frv_pack_insn_p (rtx);
static void frv_add_insn_to_packet (rtx);
static void frv_insert_nop_in_packet (rtx);
static bool frv_for_each_packet (void (*) (void));
static bool frv_sort_insn_group_1 (enum frv_insn_group,
unsigned int, unsigned int,
unsigned int, unsigned int,
state_t);
static int frv_compare_insns (const void *, const void *);
static void frv_sort_insn_group (enum frv_insn_group);
static void frv_reorder_packet (void);
static void frv_fill_unused_units (enum frv_insn_group);
static void frv_align_label (void);
static void frv_reorg_packet (void);
static void frv_register_nop (rtx);
static void frv_reorg (void);
static void frv_pack_insns (void);
static void frv_function_prologue (FILE *, HOST_WIDE_INT);
static void frv_function_epilogue (FILE *, HOST_WIDE_INT);
static bool frv_assemble_integer (rtx, unsigned, int);
static void frv_init_builtins (void);
static rtx frv_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static void frv_init_libfuncs (void);
static bool frv_in_small_data_p (tree);
static void frv_asm_output_mi_thunk
(FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
static void frv_setup_incoming_varargs (CUMULATIVE_ARGS *,
enum machine_mode,
tree, int *, int);
static rtx frv_expand_builtin_saveregs (void);
static bool frv_rtx_costs (rtx, int, int, int*);
static void frv_asm_out_constructor (rtx, int);
static void frv_asm_out_destructor (rtx, int);
static bool frv_function_symbol_referenced_p (rtx);
static bool frv_cannot_force_const_mem (rtx);
static const char *unspec_got_name (int);
static void frv_output_const_unspec (FILE *,
const struct frv_unspec *);
static bool frv_function_ok_for_sibcall (tree, tree);
static rtx frv_struct_value_rtx (tree, int);
static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
static int frv_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE frv_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE frv_function_epilogue
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER frv_assemble_integer
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS frv_init_builtins
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN frv_expand_builtin
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS frv_init_libfuncs
#undef TARGET_IN_SMALL_DATA_P
#define TARGET_IN_SMALL_DATA_P frv_in_small_data_p
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS frv_rtx_costs
#undef TARGET_ASM_CONSTRUCTOR
#define TARGET_ASM_CONSTRUCTOR frv_asm_out_constructor
#undef TARGET_ASM_DESTRUCTOR
#define TARGET_ASM_DESTRUCTOR frv_asm_out_destructor
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK frv_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_SCHED_ISSUE_RATE
#define TARGET_SCHED_ISSUE_RATE frv_issue_rate
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL frv_function_ok_for_sibcall
#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS HAVE_AS_TLS
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX frv_struct_value_rtx
#undef TARGET_MUST_PASS_IN_STACK
#define TARGET_MUST_PASS_IN_STACK frv_must_pass_in_stack
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES frv_arg_partial_bytes
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
#define TARGET_EXPAND_BUILTIN_SAVEREGS frv_expand_builtin_saveregs
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS frv_setup_incoming_varargs
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG frv_reorg
struct gcc_target targetm = TARGET_INITIALIZER;
#define FRV_SYMBOL_REF_TLS_P(RTX) \
(GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
static bool
frv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
tree exp ATTRIBUTE_UNUSED)
{
return true;
}
static FRV_INLINE bool
frv_small_data_reloc_p (rtx symbol, int reloc)
{
return (GET_CODE (symbol) == SYMBOL_REF
&& SYMBOL_REF_SMALL_P (symbol)
&& (!TARGET_FDPIC || flag_pic == 1)
&& (reloc == R_FRV_GOTOFF12 || reloc == R_FRV_GPREL12));
}
static FRV_INLINE bool
frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
{
if (GET_CODE (x) == CONST)
{
unspec->offset = 0;
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
unspec->offset += INTVAL (XEXP (x, 1));
x = XEXP (x, 0);
}
if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_GOT)
{
unspec->symbol = XVECEXP (x, 0, 0);
unspec->reloc = INTVAL (XVECEXP (x, 0, 1));
if (unspec->offset == 0)
return true;
if (frv_small_data_reloc_p (unspec->symbol, unspec->reloc)
&& unspec->offset > 0
&& (unsigned HOST_WIDE_INT) unspec->offset < g_switch_value)
return true;
}
}
return false;
}
static bool
frv_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
{
return TARGET_FDPIC;
}
static int
frv_default_flags_for_cpu (void)
{
switch (frv_cpu_type)
{
case FRV_CPU_GENERIC:
return MASK_DEFAULT_FRV;
case FRV_CPU_FR550:
return MASK_DEFAULT_FR550;
case FRV_CPU_FR500:
case FRV_CPU_TOMCAT:
return MASK_DEFAULT_FR500;
case FRV_CPU_FR450:
return MASK_DEFAULT_FR450;
case FRV_CPU_FR405:
case FRV_CPU_FR400:
return MASK_DEFAULT_FR400;
case FRV_CPU_FR300:
case FRV_CPU_SIMPLE:
return MASK_DEFAULT_SIMPLE;
}
abort ();
}
void
frv_override_options (void)
{
int regno;
unsigned int i;
if (frv_cpu_string)
{
if (strcmp (frv_cpu_string, "simple") == 0)
frv_cpu_type = FRV_CPU_SIMPLE;
else if (strcmp (frv_cpu_string, "tomcat") == 0)
frv_cpu_type = FRV_CPU_TOMCAT;
else if (strncmp (frv_cpu_string, "fr", sizeof ("fr")-1) != 0)
error ("Unknown cpu: -mcpu=%s", frv_cpu_string);
else
{
const char *p = frv_cpu_string + sizeof ("fr") - 1;
if (strcmp (p, "550") == 0)
frv_cpu_type = FRV_CPU_FR550;
else if (strcmp (p, "500") == 0)
frv_cpu_type = FRV_CPU_FR500;
else if (strcmp (p, "450") == 0)
frv_cpu_type = FRV_CPU_FR450;
else if (strcmp (p, "405") == 0)
frv_cpu_type = FRV_CPU_FR405;
else if (strcmp (p, "400") == 0)
frv_cpu_type = FRV_CPU_FR400;
else if (strcmp (p, "300") == 0)
frv_cpu_type = FRV_CPU_FR300;
else if (strcmp (p, "v") == 0)
frv_cpu_type = FRV_CPU_GENERIC;
else
error ("Unknown cpu: -mcpu=%s", frv_cpu_string);
}
}
target_flags |= (frv_default_flags_for_cpu () & ~target_flags_explicit);
if (TARGET_LIBPIC)
{
if (!flag_pic)
flag_pic = 2;
if (! g_switch_set)
{
g_switch_set = 1;
g_switch_value = 0;
}
}
if (frv_branch_cost_string)
frv_branch_cost_int = atoi (frv_branch_cost_string);
if (frv_condexec_insns_str)
frv_condexec_insns = atoi (frv_condexec_insns_str);
if (frv_condexec_temps_str)
frv_condexec_temps = atoi (frv_condexec_temps_str);
if (frv_sched_lookahead_str)
frv_sched_lookahead = atoi (frv_sched_lookahead_str);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
{
enum reg_class class;
if (GPR_P (regno))
{
int gpr_reg = regno - GPR_FIRST;
if (gpr_reg == GR8_REG)
class = GR8_REGS;
else if (gpr_reg == GR9_REG)
class = GR9_REGS;
else if (gpr_reg == GR14_REG)
class = FDPIC_FPTR_REGS;
else if (gpr_reg == FDPIC_REGNO)
class = FDPIC_REGS;
else if ((gpr_reg & 3) == 0)
class = QUAD_REGS;
else if ((gpr_reg & 1) == 0)
class = EVEN_REGS;
else
class = GPR_REGS;
}
else if (FPR_P (regno))
{
int fpr_reg = regno - GPR_FIRST;
if ((fpr_reg & 3) == 0)
class = QUAD_FPR_REGS;
else if ((fpr_reg & 1) == 0)
class = FEVEN_REGS;
else
class = FPR_REGS;
}
else if (regno == LR_REGNO)
class = LR_REG;
else if (regno == LCR_REGNO)
class = LCR_REG;
else if (ICC_P (regno))
class = ICC_REGS;
else if (FCC_P (regno))
class = FCC_REGS;
else if (ICR_P (regno))
class = ICR_REGS;
else if (FCR_P (regno))
class = FCR_REGS;
else if (ACC_P (regno))
{
int r = regno - ACC_FIRST;
if ((r & 3) == 0)
class = QUAD_ACC_REGS;
else if ((r & 1) == 0)
class = EVEN_ACC_REGS;
else
class = ACC_REGS;
}
else if (ACCG_P (regno))
class = ACCG_REGS;
else
class = NO_REGS;
regno_reg_class[regno] = class;
}
if (!g_switch_set)
g_switch_value = SDATA_DEFAULT_SIZE;
for (i = 0; i < 256; i++)
reg_class_from_letter[i] = NO_REGS;
reg_class_from_letter['a'] = ACC_REGS;
reg_class_from_letter['b'] = EVEN_ACC_REGS;
reg_class_from_letter['c'] = CC_REGS;
reg_class_from_letter['d'] = GPR_REGS;
reg_class_from_letter['e'] = EVEN_REGS;
reg_class_from_letter['f'] = FPR_REGS;
reg_class_from_letter['h'] = FEVEN_REGS;
reg_class_from_letter['l'] = LR_REG;
reg_class_from_letter['q'] = QUAD_REGS;
reg_class_from_letter['t'] = ICC_REGS;
reg_class_from_letter['u'] = FCC_REGS;
reg_class_from_letter['v'] = ICR_REGS;
reg_class_from_letter['w'] = FCR_REGS;
reg_class_from_letter['x'] = QUAD_FPR_REGS;
reg_class_from_letter['y'] = LCR_REG;
reg_class_from_letter['z'] = SPR_REGS;
reg_class_from_letter['A'] = QUAD_ACC_REGS;
reg_class_from_letter['B'] = ACCG_REGS;
reg_class_from_letter['C'] = CR_REGS;
reg_class_from_letter['W'] = FDPIC_CALL_REGS;
reg_class_from_letter['Z'] = FDPIC_REGS;
if (flag_pic || TARGET_FDPIC)
targetm.asm_out.unaligned_op.si = 0;
if ((target_flags_explicit & MASK_LINKED_FP) == 0)
target_flags |= MASK_LINKED_FP;
for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++)
frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]);
for (i = 0; i < ARRAY_SIZE (frv_type_to_unit); i++)
frv_type_to_unit[i] = ARRAY_SIZE (frv_unit_codes);
init_machine_status = frv_init_machine_status;
}
void
frv_optimization_options (int level, int size ATTRIBUTE_UNUSED)
{
if (level >= 2)
{
#ifdef DISABLE_SCHED2
flag_schedule_insns_after_reload = 0;
#endif
#ifdef ENABLE_RCSP
flag_rcsp = 1;
#endif
}
}
static int
frv_string_begins_with (tree name, const char *prefix)
{
int prefix_len = strlen (prefix);
return (TREE_STRING_LENGTH (name) > prefix_len
&& strncmp (TREE_STRING_POINTER (name), prefix, prefix_len) == 0);
}
void
frv_conditional_register_usage (void)
{
int i;
for (i = GPR_FIRST + NUM_GPRS; i <= GPR_LAST; i++)
fixed_regs[i] = call_used_regs[i] = 1;
for (i = FPR_FIRST + NUM_FPRS; i <= FPR_LAST; i++)
fixed_regs[i] = call_used_regs[i] = 1;
fixed_regs[ICC_TEMP] = call_used_regs[ICC_TEMP] = 1;
fixed_regs[ICR_TEMP] = call_used_regs[ICR_TEMP] = 1;
if (TARGET_FIXED_CC)
{
fixed_regs[ICC_FIRST] = call_used_regs[ICC_FIRST] = 1;
fixed_regs[FCC_FIRST] = call_used_regs[FCC_FIRST] = 1;
fixed_regs[ICR_FIRST] = call_used_regs[ICR_FIRST] = 1;
fixed_regs[FCR_FIRST] = call_used_regs[FCR_FIRST] = 1;
}
if (TARGET_FDPIC)
fixed_regs[GPR_FIRST + 16] = fixed_regs[GPR_FIRST + 17] =
call_used_regs[GPR_FIRST + 16] = call_used_regs[GPR_FIRST + 17] = 0;
#if 0
if (g_switch_value == 0 && !flag_pic)
fixed_regs[SDA_BASE_REG] = call_used_regs[SDA_BASE_REG] = 0;
if (!flag_pic)
fixed_regs[PIC_REGNO] = call_used_regs[PIC_REGNO] = 0;
#endif
}
frv_stack_t *
frv_stack_info (void)
{
static frv_stack_t info, zero_info;
frv_stack_t *info_ptr = &info;
tree fndecl = current_function_decl;
int varargs_p = 0;
tree cur_arg;
tree next_arg;
int range;
int alignment;
int offset;
if (frv_stack_cache)
return frv_stack_cache;
info = zero_info;
info_ptr->regs[STACK_REGS_GPR].name = "gpr";
info_ptr->regs[STACK_REGS_GPR].first = LAST_ARG_REGNUM + 1;
info_ptr->regs[STACK_REGS_GPR].last = GPR_LAST;
info_ptr->regs[STACK_REGS_GPR].dword_p = TRUE;
info_ptr->regs[STACK_REGS_FPR].name = "fpr";
info_ptr->regs[STACK_REGS_FPR].first = FPR_FIRST;
info_ptr->regs[STACK_REGS_FPR].last = FPR_LAST;
info_ptr->regs[STACK_REGS_FPR].dword_p = TRUE;
info_ptr->regs[STACK_REGS_LR].name = "lr";
info_ptr->regs[STACK_REGS_LR].first = LR_REGNO;
info_ptr->regs[STACK_REGS_LR].last = LR_REGNO;
info_ptr->regs[STACK_REGS_LR].special_p = 1;
info_ptr->regs[STACK_REGS_CC].name = "cc";
info_ptr->regs[STACK_REGS_CC].first = CC_FIRST;
info_ptr->regs[STACK_REGS_CC].last = CC_LAST;
info_ptr->regs[STACK_REGS_CC].field_p = TRUE;
info_ptr->regs[STACK_REGS_LCR].name = "lcr";
info_ptr->regs[STACK_REGS_LCR].first = LCR_REGNO;
info_ptr->regs[STACK_REGS_LCR].last = LCR_REGNO;
info_ptr->regs[STACK_REGS_STDARG].name = "stdarg";
info_ptr->regs[STACK_REGS_STDARG].first = FIRST_ARG_REGNUM;
info_ptr->regs[STACK_REGS_STDARG].last = LAST_ARG_REGNUM;
info_ptr->regs[STACK_REGS_STDARG].dword_p = 1;
info_ptr->regs[STACK_REGS_STDARG].special_p = 1;
info_ptr->regs[STACK_REGS_STRUCT].name = "struct";
info_ptr->regs[STACK_REGS_STRUCT].first = FRV_STRUCT_VALUE_REGNUM;
info_ptr->regs[STACK_REGS_STRUCT].last = FRV_STRUCT_VALUE_REGNUM;
info_ptr->regs[STACK_REGS_STRUCT].special_p = 1;
info_ptr->regs[STACK_REGS_FP].name = "fp";
info_ptr->regs[STACK_REGS_FP].first = FRAME_POINTER_REGNUM;
info_ptr->regs[STACK_REGS_FP].last = FRAME_POINTER_REGNUM;
info_ptr->regs[STACK_REGS_FP].special_p = 1;
if (cfun->stdarg)
varargs_p = 1;
else
{
for (cur_arg = DECL_ARGUMENTS (fndecl); cur_arg != (tree)0; cur_arg = next_arg)
{
next_arg = TREE_CHAIN (cur_arg);
if (next_arg == (tree)0)
{
if (DECL_NAME (cur_arg)
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)), "__builtin_va_alist"))
varargs_p = 1;
break;
}
}
}
for (range = 0; range < STACK_REGS_MAX; range++)
{
frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
int first = reg_ptr->first;
int last = reg_ptr->last;
int size_1word = 0;
int size_2words = 0;
int regno;
switch (range)
{
default:
for (regno = first; regno <= last; regno++)
{
if ((regs_ever_live[regno] && !call_used_regs[regno])
|| (current_function_calls_eh_return
&& (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
|| (!TARGET_FDPIC && flag_pic
&& cfun->uses_pic_offset_table && regno == PIC_REGNO))
{
info_ptr->save_p[regno] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
}
}
break;
case STACK_REGS_FP:
break;
case STACK_REGS_LR:
if (regs_ever_live[LR_REGNO]
|| profile_flag
|| cfun->machine->frame_needed
|| (TARGET_LINKED_FP && frame_pointer_needed)
|| (!TARGET_FDPIC && flag_pic
&& cfun->uses_pic_offset_table))
{
info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
}
break;
case STACK_REGS_STDARG:
if (varargs_p)
{
last -= (ADDR_ALIGN (cfun->pretend_args_size, UNITS_PER_WORD)
/ UNITS_PER_WORD);
for (regno = first; regno <= last; regno++)
{
info_ptr->save_p[regno] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
}
info_ptr->stdarg_size = size_1word;
}
break;
case STACK_REGS_STRUCT:
if (cfun->returns_struct)
{
info_ptr->save_p[FRV_STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
}
break;
}
if (size_1word)
{
if (reg_ptr->field_p)
size_1word = UNITS_PER_WORD;
else if (reg_ptr->dword_p && TARGET_DWORD)
{
for (regno = first; regno < last; regno += 2)
{
if (info_ptr->save_p[regno] && info_ptr->save_p[regno+1])
{
size_2words += 2 * UNITS_PER_WORD;
size_1word -= 2 * UNITS_PER_WORD;
info_ptr->save_p[regno] = REG_SAVE_2WORDS;
info_ptr->save_p[regno+1] = REG_SAVE_NO_SAVE;
}
}
}
reg_ptr->size_1word = size_1word;
reg_ptr->size_2words = size_2words;
if (! reg_ptr->special_p)
{
info_ptr->regs_size_1word += size_1word;
info_ptr->regs_size_2words += size_2words;
}
}
}
alignment = (TARGET_DWORD? 2 * UNITS_PER_WORD : UNITS_PER_WORD);
info_ptr->parameter_size = ADDR_ALIGN (cfun->outgoing_args_size, alignment);
info_ptr->regs_size = ADDR_ALIGN (info_ptr->regs_size_2words
+ info_ptr->regs_size_1word,
alignment);
info_ptr->vars_size = ADDR_ALIGN (get_frame_size (), alignment);
info_ptr->pretend_size = cfun->pretend_args_size;
info_ptr->total_size
= (ADDR_ALIGN (info_ptr->parameter_size
+ info_ptr->regs_size
+ info_ptr->vars_size,
2 * UNITS_PER_WORD)
+ ADDR_ALIGN (info_ptr->pretend_size
+ info_ptr->stdarg_size,
2 * UNITS_PER_WORD));
if (info_ptr->total_size > 0
|| frame_pointer_needed
|| info_ptr->regs[STACK_REGS_LR].size_1word > 0
|| info_ptr->regs[STACK_REGS_STRUCT].size_1word > 0)
{
offset = info_ptr->parameter_size;
info_ptr->header_size = 4 * UNITS_PER_WORD;
info_ptr->total_size += 4 * UNITS_PER_WORD;
for (range = 0; range < STACK_REGS_MAX; range++)
{
frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
if (! reg_ptr->special_p)
{
int first = reg_ptr->first;
int last = reg_ptr->last;
int regno;
for (regno = first; regno <= last; regno++)
if (info_ptr->save_p[regno] == REG_SAVE_2WORDS
&& regno != FRAME_POINTER_REGNUM
&& (regno < FIRST_ARG_REGNUM
|| regno > LAST_ARG_REGNUM))
{
info_ptr->reg_offset[regno] = offset;
offset += 2 * UNITS_PER_WORD;
}
}
}
for (range = 0; range < STACK_REGS_MAX; range++)
{
frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
if (! reg_ptr->special_p)
{
int first = reg_ptr->first;
int last = reg_ptr->last;
int regno;
for (regno = first; regno <= last; regno++)
if (info_ptr->save_p[regno] == REG_SAVE_1WORD
&& regno != FRAME_POINTER_REGNUM
&& (regno < FIRST_ARG_REGNUM
|| regno > LAST_ARG_REGNUM))
{
info_ptr->reg_offset[regno] = offset;
offset += UNITS_PER_WORD;
}
}
}
offset = ADDR_ALIGN (offset, alignment);
if (info_ptr->vars_size)
{
info_ptr->vars_offset = offset;
offset += info_ptr->vars_size;
}
offset = ADDR_ALIGN (offset, 2 * UNITS_PER_WORD);
info_ptr->save_p[FRAME_POINTER_REGNUM] = REG_SAVE_1WORD;
info_ptr->reg_offset[FRAME_POINTER_REGNUM] = offset;
info_ptr->regs[STACK_REGS_FP].size_1word = UNITS_PER_WORD;
info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
info_ptr->reg_offset[LR_REGNO] = offset + 2*UNITS_PER_WORD;
info_ptr->regs[STACK_REGS_LR].size_1word = UNITS_PER_WORD;
if (cfun->returns_struct)
{
info_ptr->save_p[FRV_STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
info_ptr->reg_offset[FRV_STRUCT_VALUE_REGNUM] = offset + UNITS_PER_WORD;
info_ptr->regs[STACK_REGS_STRUCT].size_1word = UNITS_PER_WORD;
}
if (info_ptr->stdarg_size)
{
int first = info_ptr->regs[STACK_REGS_STDARG].first;
int last = info_ptr->regs[STACK_REGS_STDARG].last;
int regno;
offset += 4 * UNITS_PER_WORD;
for (regno = first; regno <= last; regno++)
{
if (info_ptr->save_p[regno] == REG_SAVE_2WORDS)
{
info_ptr->reg_offset[regno] = offset;
offset += 2 * UNITS_PER_WORD;
}
else if (info_ptr->save_p[regno] == REG_SAVE_1WORD)
{
info_ptr->reg_offset[regno] = offset;
offset += UNITS_PER_WORD;
}
}
}
}
if (reload_completed)
frv_stack_cache = info_ptr;
return info_ptr;
}
void
frv_debug_stack (frv_stack_t *info)
{
int range;
if (!info)
info = frv_stack_info ();
fprintf (stderr, "\nStack information for function %s:\n",
((current_function_decl && DECL_NAME (current_function_decl))
? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
: "<unknown>"));
fprintf (stderr, "\ttotal_size\t= %6d\n", info->total_size);
fprintf (stderr, "\tvars_size\t= %6d\n", info->vars_size);
fprintf (stderr, "\tparam_size\t= %6d\n", info->parameter_size);
fprintf (stderr, "\tregs_size\t= %6d, 1w = %3d, 2w = %3d\n",
info->regs_size, info->regs_size_1word, info->regs_size_2words);
fprintf (stderr, "\theader_size\t= %6d\n", info->header_size);
fprintf (stderr, "\tpretend_size\t= %6d\n", info->pretend_size);
fprintf (stderr, "\tvars_offset\t= %6d\n", info->vars_offset);
fprintf (stderr, "\tregs_offset\t= %6d\n", info->regs_offset);
for (range = 0; range < STACK_REGS_MAX; range++)
{
frv_stack_regs_t *regs = &(info->regs[range]);
if ((regs->size_1word + regs->size_2words) > 0)
{
int first = regs->first;
int last = regs->last;
int regno;
fprintf (stderr, "\t%s\tsize\t= %6d, 1w = %3d, 2w = %3d, save =",
regs->name, regs->size_1word + regs->size_2words,
regs->size_1word, regs->size_2words);
for (regno = first; regno <= last; regno++)
{
if (info->save_p[regno] == REG_SAVE_1WORD)
fprintf (stderr, " %s (%d)", reg_names[regno],
info->reg_offset[regno]);
else if (info->save_p[regno] == REG_SAVE_2WORDS)
fprintf (stderr, " %s-%s (%d)", reg_names[regno],
reg_names[regno+1], info->reg_offset[regno]);
}
fputc ('\n', stderr);
}
}
fflush (stderr);
}
static int frv_insn_packing_flag;
static int
frv_function_contains_far_jump (void)
{
rtx insn = get_insns ();
while (insn != NULL
&& !(GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
&& get_attr_far_jump (insn) == FAR_JUMP_YES))
insn = NEXT_INSN (insn);
return (insn != NULL);
}
static void
frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
if (frv_stack_info ()->total_size == 0 && frv_function_contains_far_jump ())
{
rtx insn;
if (regs_ever_live[GPR_FIRST + 3])
abort ();
fprintf (file, "\tmovsg lr,gr3\n");
for (insn = get_insns(); insn != NULL; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
rtx pattern = PATTERN (insn);
if (GET_CODE (pattern) == PARALLEL
&& XVECLEN (pattern, 0) >= 2
&& GET_CODE (XVECEXP (pattern, 0, 0)) == RETURN
&& GET_CODE (XVECEXP (pattern, 0, 1)) == USE)
{
rtx address = XEXP (XVECEXP (pattern, 0, 1), 0);
if (GET_CODE (address) == REG && REGNO (address) == LR_REGNO)
REGNO (address) = GPR_FIRST + 3;
}
}
}
frv_pack_insns ();
memset (frv_nops, 0, sizeof (frv_nops));
}
static rtx
frv_alloc_temp_reg (
frv_tmp_reg_t *info,
enum reg_class class,
enum machine_mode mode,
int mark_as_used,
int no_abort)
{
int regno = info->next_reg[ (int)class ];
int orig_regno = regno;
HARD_REG_SET *reg_in_class = ®_class_contents[ (int)class ];
int i, nr;
for (;;)
{
if (TEST_HARD_REG_BIT (*reg_in_class, regno)
&& TEST_HARD_REG_BIT (info->regs, regno))
break;
if (++regno >= FIRST_PSEUDO_REGISTER)
regno = 0;
if (regno == orig_regno)
{
if (no_abort)
return NULL_RTX;
else
abort ();
}
}
nr = HARD_REGNO_NREGS (regno, mode);
info->next_reg[ (int)class ] = regno + nr;
if (mark_as_used)
for (i = 0; i < nr; i++)
CLEAR_HARD_REG_BIT (info->regs, regno+i);
return gen_rtx_REG (mode, regno);
}
static rtx
frv_frame_offset_rtx (int offset)
{
rtx offset_rtx = GEN_INT (offset);
if (IN_RANGE_P (offset, -2048, 2047))
return offset_rtx;
else
{
rtx reg_rtx = gen_rtx_REG (SImode, OFFSET_REGNO);
if (IN_RANGE_P (offset, -32768, 32767))
emit_insn (gen_movsi (reg_rtx, offset_rtx));
else
{
emit_insn (gen_movsi_high (reg_rtx, offset_rtx));
emit_insn (gen_movsi_lo_sum (reg_rtx, offset_rtx));
}
return reg_rtx;
}
}
static rtx
frv_frame_mem (enum machine_mode mode, rtx base, int offset)
{
return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode,
base,
frv_frame_offset_rtx (offset)));
}
static rtx
frv_dwarf_store (rtx reg, int offset)
{
rtx set = gen_rtx_SET (VOIDmode,
gen_rtx_MEM (GET_MODE (reg),
plus_constant (stack_pointer_rtx,
offset)),
reg);
RTX_FRAME_RELATED_P (set) = 1;
return set;
}
static void
frv_frame_insn (rtx pattern, rtx dwarf_pattern)
{
rtx insn = emit_insn (pattern);
RTX_FRAME_RELATED_P (insn) = 1;
REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
dwarf_pattern,
REG_NOTES (insn));
}
static void
frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset)
{
enum machine_mode mode = GET_MODE (reg);
rtx mem = frv_frame_mem (mode,
accessor->base,
stack_offset - accessor->base_offset);
if (accessor->op == FRV_LOAD)
{
if (SPR_P (REGNO (reg)))
{
rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
emit_insn (gen_rtx_SET (VOIDmode, temp, mem));
emit_insn (gen_rtx_SET (VOIDmode, reg, temp));
}
else
emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
emit_insn (gen_rtx_USE (VOIDmode, reg));
}
else
{
if (SPR_P (REGNO (reg)))
{
rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
emit_insn (gen_rtx_SET (VOIDmode, temp, reg));
frv_frame_insn (gen_rtx_SET (Pmode, mem, temp),
frv_dwarf_store (reg, stack_offset));
}
else if (GET_MODE (reg) == DImode)
{
rtx reg1 = gen_rtx_REG (SImode, REGNO (reg));
rtx reg2 = gen_rtx_REG (SImode, REGNO (reg) + 1);
rtx set1 = frv_dwarf_store (reg1, stack_offset);
rtx set2 = frv_dwarf_store (reg2, stack_offset + 4);
frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, set1, set2)));
}
else
frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
frv_dwarf_store (reg, stack_offset));
}
}
static void
frv_frame_access_multi (frv_frame_accessor_t *accessor,
frv_stack_t *info,
int reg_set)
{
frv_stack_regs_t *regs_info;
int regno;
regs_info = &info->regs[reg_set];
for (regno = regs_info->first; regno <= regs_info->last; regno++)
if (info->save_p[regno])
frv_frame_access (accessor,
info->save_p[regno] == REG_SAVE_2WORDS
? gen_rtx_REG (DImode, regno)
: gen_rtx_REG (SImode, regno),
info->reg_offset[regno]);
}
static void
frv_frame_access_standard_regs (enum frv_stack_op op, frv_stack_t *info)
{
frv_frame_accessor_t accessor;
accessor.op = op;
accessor.base = stack_pointer_rtx;
accessor.base_offset = 0;
frv_frame_access_multi (&accessor, info, STACK_REGS_GPR);
frv_frame_access_multi (&accessor, info, STACK_REGS_FPR);
frv_frame_access_multi (&accessor, info, STACK_REGS_LCR);
}
void
frv_expand_prologue (void)
{
frv_stack_t *info = frv_stack_info ();
rtx sp = stack_pointer_rtx;
rtx fp = frame_pointer_rtx;
frv_frame_accessor_t accessor;
if (TARGET_DEBUG_STACK)
frv_debug_stack (info);
if (info->total_size == 0)
return;
accessor.op = FRV_STORE;
if (frame_pointer_needed && info->total_size > 2048)
{
rtx insn;
accessor.base = gen_rtx_REG (Pmode, OLD_SP_REGNO);
accessor.base_offset = info->total_size;
insn = emit_insn (gen_movsi (accessor.base, sp));
}
else
{
accessor.base = stack_pointer_rtx;
accessor.base_offset = 0;
}
{
rtx asm_offset = frv_frame_offset_rtx (-info->total_size);
rtx dwarf_offset = GEN_INT (-info->total_size);
frv_frame_insn (gen_stack_adjust (sp, sp, asm_offset),
gen_rtx_SET (Pmode,
sp,
gen_rtx_PLUS (Pmode, sp, dwarf_offset)));
}
if (frame_pointer_needed)
{
int fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
rtx asm_src = plus_constant (accessor.base,
fp_offset - accessor.base_offset);
rtx dwarf_src = plus_constant (sp, fp_offset);
frv_frame_access (&accessor, fp, fp_offset);
frv_frame_insn (gen_rtx_SET (VOIDmode, fp, asm_src),
gen_rtx_SET (VOIDmode, fp, dwarf_src));
accessor.base = fp;
accessor.base_offset = fp_offset;
}
frv_frame_access_multi (&accessor, info, STACK_REGS_STRUCT);
frv_frame_access_multi (&accessor, info, STACK_REGS_LR);
frv_frame_access_multi (&accessor, info, STACK_REGS_STDARG);
frv_frame_access_standard_regs (FRV_STORE, info);
if (info->stdarg_size > 0)
emit_insn (gen_blockage ());
if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO),
gen_rtx_REG (Pmode, LR_REGNO),
gen_rtx_REG (SImode, OFFSET_REGNO)));
}
static void
frv_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
frv_stack_cache = (frv_stack_t *)0;
memset (&frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg));
BITMAP_FREE (frv_ifcvt.scratch_insns_bitmap);
}
void
frv_expand_epilogue (bool emit_return)
{
frv_stack_t *info = frv_stack_info ();
rtx fp = frame_pointer_rtx;
rtx sp = stack_pointer_rtx;
rtx return_addr;
int fp_offset;
fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
if (! current_function_sp_is_unchanging)
emit_insn (gen_addsi3 (sp, fp, frv_frame_offset_rtx (-fp_offset)));
frv_frame_access_standard_regs (FRV_LOAD, info);
if (info->save_p[LR_REGNO])
{
int lr_offset;
rtx mem;
lr_offset = info->reg_offset[LR_REGNO];
if (frame_pointer_needed)
mem = frv_frame_mem (Pmode, fp, lr_offset - fp_offset);
else
mem = frv_frame_mem (Pmode, sp, lr_offset);
return_addr = gen_rtx_REG (Pmode, TEMP_REGNO);
emit_insn (gen_rtx_SET (VOIDmode, return_addr, mem));
}
else
return_addr = gen_rtx_REG (Pmode, LR_REGNO);
if (frame_pointer_needed)
{
emit_insn (gen_rtx_SET (VOIDmode, fp, gen_rtx_MEM (Pmode, fp)));
emit_insn (gen_rtx_USE (VOIDmode, fp));
}
if (info->total_size != 0)
{
rtx offset = frv_frame_offset_rtx (info->total_size);
emit_insn (gen_stack_adjust (sp, sp, offset));
}
if (current_function_calls_eh_return)
emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX));
if (emit_return)
emit_jump_insn (gen_epilogue_return (return_addr));
else
{
rtx lr = return_addr;
if (REGNO (return_addr) != LR_REGNO)
{
lr = gen_rtx_REG (Pmode, LR_REGNO);
emit_move_insn (lr, return_addr);
}
emit_insn (gen_rtx_USE (VOIDmode, lr));
}
}
static void
frv_asm_output_mi_thunk (FILE *file,
tree thunk_fndecl ATTRIBUTE_UNUSED,
HOST_WIDE_INT delta,
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
tree function)
{
const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0);
const char *name_arg0 = reg_names[FIRST_ARG_REGNUM];
const char *name_jmp = reg_names[JUMP_REGNO];
const char *parallel = (frv_issue_rate () > 1 ? ".p" : "");
if (IN_RANGE_P (delta, -2048, 2047))
fprintf (file, "\taddi %s,#%d,%s\n", name_arg0, (int) delta, name_arg0);
else
{
const char *const name_add = reg_names[TEMP_REGNO];
fprintf (file, "\tsethi%s #hi(" HOST_WIDE_INT_PRINT_DEC "),%s\n",
parallel, delta, name_add);
fprintf (file, "\tsetlo #lo(" HOST_WIDE_INT_PRINT_DEC "),%s\n",
delta, name_add);
fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0);
}
if (TARGET_FDPIC)
{
const char *name_pic = reg_names[FDPIC_REGNO];
name_jmp = reg_names[FDPIC_FPTR_REGNO];
if (flag_pic != 1)
{
fprintf (file, "\tsethi%s #gotofffuncdeschi(", parallel);
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_jmp);
fprintf (file, "\tsetlo #gotofffuncdesclo(");
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_jmp);
fprintf (file, "\tldd @(%s,%s), %s\n", name_jmp, name_pic, name_jmp);
}
else
{
fprintf (file, "\tlddo @(%s,#gotofffuncdesc12(", name_pic);
assemble_name (file, name_func);
fprintf (file, "\t)), %s\n", name_jmp);
}
}
else if (!flag_pic)
{
fprintf (file, "\tsethi%s #hi(", parallel);
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_jmp);
fprintf (file, "\tsetlo #lo(");
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_jmp);
}
else
{
const char *name_lr = reg_names[LR_REGNO];
const char *name_gppic = name_jmp;
const char *name_tmp = reg_names[TEMP_REGNO];
fprintf (file, "\tmovsg %s,%s\n", name_lr, name_tmp);
fprintf (file, "\tcall 1f\n");
fprintf (file, "1:\tmovsg %s,%s\n", name_lr, name_gppic);
fprintf (file, "\tmovgs %s,%s\n", name_tmp, name_lr);
fprintf (file, "\tsethi%s #gprelhi(1b),%s\n", parallel, name_tmp);
fprintf (file, "\tsetlo #gprello(1b),%s\n", name_tmp);
fprintf (file, "\tsub %s,%s,%s\n", name_gppic, name_tmp, name_gppic);
fprintf (file, "\tsethi%s #gprelhi(", parallel);
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_tmp);
fprintf (file, "\tsetlo #gprello(");
assemble_name (file, name_func);
fprintf (file, "),%s\n", name_tmp);
fprintf (file, "\tadd %s,%s,%s\n", name_gppic, name_tmp, name_jmp);
}
fprintf (file, "\tjmpl @(%s,%s)\n", name_jmp, reg_names[GPR_FIRST+0]);
}
int
frv_frame_pointer_required (void)
{
if (!TARGET_LINKED_FP)
return !current_function_sp_is_unchanging;
if (! current_function_is_leaf)
return TRUE;
if (get_frame_size () != 0)
return TRUE;
if (cfun->stdarg)
return TRUE;
if (!current_function_sp_is_unchanging)
return TRUE;
if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
return TRUE;
if (profile_flag)
return TRUE;
if (cfun->machine->frame_needed)
return TRUE;
return FALSE;
}
int
frv_initial_elimination_offset (int from, int to)
{
frv_stack_t *info = frv_stack_info ();
int ret = 0;
if (to == STACK_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
ret = info->total_size - info->pretend_size;
else if (to == STACK_POINTER_REGNUM && from == FRAME_POINTER_REGNUM)
ret = info->reg_offset[FRAME_POINTER_REGNUM];
else if (to == FRAME_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
ret = (info->total_size
- info->reg_offset[FRAME_POINTER_REGNUM]
- info->pretend_size);
else
abort ();
if (TARGET_DEBUG_STACK)
fprintf (stderr, "Eliminate %s to %s by adding %d\n",
reg_names [from], reg_names[to], ret);
return ret;
}
static void
frv_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
tree type ATTRIBUTE_UNUSED,
int *pretend_size,
int second_time)
{
if (TARGET_DEBUG_ARG)
fprintf (stderr,
"setup_vararg: words = %2d, mode = %4s, pretend_size = %d, second_time = %d\n",
*cum, GET_MODE_NAME (mode), *pretend_size, second_time);
}
static rtx
frv_expand_builtin_saveregs (void)
{
int offset = UNITS_PER_WORD * FRV_NUM_ARG_REGS;
if (TARGET_DEBUG_ARG)
fprintf (stderr, "expand_builtin_saveregs: offset from ap = %d\n",
offset);
return gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx, GEN_INT (- offset));
}
void
frv_expand_builtin_va_start (tree valist, rtx nextarg)
{
tree t;
int num = cfun->args_info - FIRST_ARG_REGNUM - FRV_NUM_ARG_REGS;
nextarg = gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx,
GEN_INT (UNITS_PER_WORD * num));
if (TARGET_DEBUG_ARG)
{
fprintf (stderr, "va_start: args_info = %d, num = %d\n",
cfun->args_info, num);
debug_rtx (nextarg);
}
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
make_tree (ptr_type_node, nextarg));
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
#ifndef MAX_MOVE_REG
#define MAX_MOVE_REG 4
#endif
#ifndef TOTAL_MOVE_REG
#define TOTAL_MOVE_REG 8
#endif
int
frv_expand_block_move (rtx operands[])
{
rtx orig_dest = operands[0];
rtx orig_src = operands[1];
rtx bytes_rtx = operands[2];
rtx align_rtx = operands[3];
int constp = (GET_CODE (bytes_rtx) == CONST_INT);
int align;
int bytes;
int offset;
int num_reg;
int i;
rtx src_reg;
rtx dest_reg;
rtx src_addr;
rtx dest_addr;
rtx src_mem;
rtx dest_mem;
rtx tmp_reg;
rtx stores[MAX_MOVE_REG];
int move_bytes;
enum machine_mode mode;
if (! constp)
return FALSE;
if (GET_CODE (align_rtx) != CONST_INT)
abort ();
align = INTVAL (align_rtx);
bytes = INTVAL (bytes_rtx);
if (bytes <= 0)
return TRUE;
if (bytes > TOTAL_MOVE_REG*align)
return FALSE;
dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
src_reg = copy_addr_to_reg (XEXP (orig_src, 0));
num_reg = offset = 0;
for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
{
if (offset == 0)
{
src_addr = src_reg;
dest_addr = dest_reg;
}
else
{
src_addr = plus_constant (src_reg, offset);
dest_addr = plus_constant (dest_reg, offset);
}
if (bytes >= 4 && align >= 4)
mode = SImode;
else if (bytes >= 2 && align >= 2)
mode = HImode;
else
mode = QImode;
move_bytes = GET_MODE_SIZE (mode);
tmp_reg = gen_reg_rtx (mode);
src_mem = change_address (orig_src, mode, src_addr);
dest_mem = change_address (orig_dest, mode, dest_addr);
emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, src_mem));
stores[num_reg++] = gen_rtx_SET (VOIDmode, dest_mem, tmp_reg);
if (num_reg >= MAX_MOVE_REG)
{
for (i = 0; i < num_reg; i++)
emit_insn (stores[i]);
num_reg = 0;
}
}
for (i = 0; i < num_reg; i++)
emit_insn (stores[i]);
return TRUE;
}
int
frv_expand_block_clear (rtx operands[])
{
rtx orig_dest = operands[0];
rtx bytes_rtx = operands[1];
rtx align_rtx = operands[2];
int constp = (GET_CODE (bytes_rtx) == CONST_INT);
int align;
int bytes;
int offset;
int num_reg;
rtx dest_reg;
rtx dest_addr;
rtx dest_mem;
int clear_bytes;
enum machine_mode mode;
if (! constp)
return FALSE;
if (GET_CODE (align_rtx) != CONST_INT)
abort ();
align = INTVAL (align_rtx);
bytes = INTVAL (bytes_rtx);
if (bytes <= 0)
return TRUE;
if (bytes > TOTAL_MOVE_REG*align)
return FALSE;
dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
num_reg = offset = 0;
for ( ; bytes > 0; (bytes -= clear_bytes), (offset += clear_bytes))
{
dest_addr = ((offset == 0)
? dest_reg
: plus_constant (dest_reg, offset));
if (bytes >= 4 && align >= 4)
mode = SImode;
else if (bytes >= 2 && align >= 2)
mode = HImode;
else
mode = QImode;
clear_bytes = GET_MODE_SIZE (mode);
dest_mem = change_address (orig_dest, mode, dest_addr);
emit_insn (gen_rtx_SET (VOIDmode, dest_mem, const0_rtx));
}
return TRUE;
}
static rtx *frv_insn_operands;
const char *
frv_asm_output_opcode (FILE *f, const char *ptr)
{
int c;
if (frv_insn_packing_flag <= 0)
return ptr;
for (; *ptr && *ptr != ' ' && *ptr != '\t';)
{
c = *ptr++;
if (c == '%' && ((*ptr >= 'a' && *ptr <= 'z')
|| (*ptr >= 'A' && *ptr <= 'Z')))
{
int letter = *ptr++;
c = atoi (ptr);
frv_print_operand (f, frv_insn_operands [c], letter);
while ((c = *ptr) >= '0' && c <= '9')
ptr++;
}
else
fputc (c, f);
}
fprintf (f, ".p");
return ptr;
}
void
frv_final_prescan_insn (rtx insn, rtx *opvec,
int noperands ATTRIBUTE_UNUSED)
{
if (INSN_P (insn))
{
if (frv_insn_packing_flag >= 0)
{
frv_insn_operands = opvec;
frv_insn_packing_flag = PACKING_FLAG_P (insn);
}
else if (recog_memoized (insn) >= 0
&& get_attr_acc_group (insn) == ACC_GROUP_ODD)
fprintf (asm_out_file, "\tmnop.p\n");
}
}
rtx
frv_dynamic_chain_address (rtx frame)
{
cfun->machine->frame_needed = 1;
return frame;
}
rtx
frv_return_addr_rtx (int count, rtx frame)
{
if (count != 0)
return const0_rtx;
cfun->machine->frame_needed = 1;
return gen_rtx_MEM (Pmode, plus_constant (frame, 8));
}
rtx
frv_index_memory (rtx memref, enum machine_mode mode, int index)
{
rtx base = XEXP (memref, 0);
if (GET_CODE (base) == PRE_MODIFY)
base = XEXP (base, 0);
return change_address (memref, mode,
plus_constant (base, index * GET_MODE_SIZE (mode)));
}
void
frv_print_operand_address (FILE * stream, rtx x)
{
if (GET_CODE (x) == MEM)
x = XEXP (x, 0);
switch (GET_CODE (x))
{
case REG:
fputs (reg_names [ REGNO (x)], stream);
return;
case CONST_INT:
fprintf (stream, "%ld", (long) INTVAL (x));
return;
case SYMBOL_REF:
assemble_name (stream, XSTR (x, 0));
return;
case LABEL_REF:
case CONST:
output_addr_const (stream, x);
return;
default:
break;
}
fatal_insn ("Bad insn to frv_print_operand_address:", x);
}
static void
frv_print_operand_memory_reference_reg (FILE * stream, rtx x)
{
int regno = true_regnum (x);
if (GPR_P (regno))
fputs (reg_names[regno], stream);
else
fatal_insn ("Bad register to frv_print_operand_memory_reference_reg:", x);
}
static void
frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
{
struct frv_unspec unspec;
rtx x0 = NULL_RTX;
rtx x1 = NULL_RTX;
switch (GET_CODE (x))
{
case SUBREG:
case REG:
x0 = x;
break;
case PRE_MODIFY:
x0 = XEXP (x, 0);
x1 = XEXP (XEXP (x, 1), 1);
break;
case CONST_INT:
x1 = x;
break;
case PLUS:
x0 = XEXP (x, 0);
x1 = XEXP (x, 1);
if (GET_CODE (x0) == CONST_INT)
{
x0 = XEXP (x, 1);
x1 = XEXP (x, 0);
}
break;
default:
fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
break;
}
if (addr_offset)
{
if (!x1)
x1 = const0_rtx;
else if (GET_CODE (x1) != CONST_INT)
fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
}
fputs ("@(", stream);
if (!x0)
fputs (reg_names[GPR_R0], stream);
else if (GET_CODE (x0) == REG || GET_CODE (x0) == SUBREG)
frv_print_operand_memory_reference_reg (stream, x0);
else
fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
fputs (",", stream);
if (!x1)
fputs (reg_names [GPR_R0], stream);
else
{
switch (GET_CODE (x1))
{
case SUBREG:
case REG:
frv_print_operand_memory_reference_reg (stream, x1);
break;
case CONST_INT:
fprintf (stream, "%ld", (long) (INTVAL (x1) + addr_offset));
break;
case CONST:
if (!frv_const_unspec_p (x1, &unspec))
fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x1);
frv_output_const_unspec (stream, &unspec);
break;
default:
fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
}
}
fputs (")", stream);
}
#define FRV_JUMP_LIKELY 2
#define FRV_JUMP_NOT_LIKELY 0
static int
frv_print_operand_jump_hint (rtx insn)
{
rtx note;
rtx labelref;
int ret;
HOST_WIDE_INT prob = -1;
enum { UNKNOWN, BACKWARD, FORWARD } jump_type = UNKNOWN;
if (GET_CODE (insn) != JUMP_INSN)
abort ();
if (! any_condjump_p (insn))
ret = FRV_JUMP_LIKELY;
else
{
labelref = condjump_label (insn);
if (labelref)
{
rtx label = XEXP (labelref, 0);
jump_type = (insn_current_address > INSN_ADDRESSES (INSN_UID (label))
? BACKWARD
: FORWARD);
}
note = find_reg_note (insn, REG_BR_PROB, 0);
if (!note)
ret = ((jump_type == BACKWARD) ? FRV_JUMP_LIKELY : FRV_JUMP_NOT_LIKELY);
else
{
prob = INTVAL (XEXP (note, 0));
ret = ((prob >= (REG_BR_PROB_BASE / 2))
? FRV_JUMP_LIKELY
: FRV_JUMP_NOT_LIKELY);
}
}
#if 0
if (TARGET_DEBUG)
{
char *direction;
switch (jump_type)
{
default:
case UNKNOWN: direction = "unknown jump direction"; break;
case BACKWARD: direction = "jump backward"; break;
case FORWARD: direction = "jump forward"; break;
}
fprintf (stderr,
"%s: uid %ld, %s, probability = %ld, max prob. = %ld, hint = %d\n",
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
(long)INSN_UID (insn), direction, (long)prob,
(long)REG_BR_PROB_BASE, ret);
}
#endif
return ret;
}
static const char *
comparison_string (enum rtx_code code, rtx op0)
{
bool is_nz_p = GET_MODE (op0) == CC_NZmode;
switch (code)
{
default: output_operand_lossage ("bad condition code");
case EQ: return "eq";
case NE: return "ne";
case LT: return is_nz_p ? "n" : "lt";
case LE: return "le";
case GT: return "gt";
case GE: return is_nz_p ? "p" : "ge";
case LTU: return is_nz_p ? "no" : "c";
case LEU: return is_nz_p ? "eq" : "ls";
case GTU: return is_nz_p ? "ne" : "hi";
case GEU: return is_nz_p ? "ra" : "nc";
}
}
void
frv_print_operand (FILE * file, rtx x, int code)
{
struct frv_unspec unspec;
HOST_WIDE_INT value;
int offset;
if (code != 0 && !isalpha (code))
value = 0;
else if (GET_CODE (x) == CONST_INT)
value = INTVAL (x);
else if (GET_CODE (x) == CONST_DOUBLE)
{
if (GET_MODE (x) == SFmode)
{
REAL_VALUE_TYPE rv;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
}
else if (GET_MODE (x) == VOIDmode)
value = CONST_DOUBLE_LOW (x);
else
fatal_insn ("Bad insn in frv_print_operand, bad const_double", x);
}
else
value = 0;
switch (code)
{
case '.':
fputs (reg_names[GPR_R0], file);
break;
case '#':
fprintf (file, "%d", frv_print_operand_jump_hint (current_output_insn));
break;
case '@':
fputs (reg_names[SDA_BASE_REG], file);
break;
case '~':
fputs (reg_names[PIC_REGNO], file);
break;
case '*':
fputs (reg_names[ICR_TEMP], file);
break;
case '&':
fputs (reg_names[ICC_TEMP], file);
break;
case 'C':
fputs (comparison_string (reverse_condition (GET_CODE (x)),
XEXP (x, 0)), file);
break;
case 'c':
fputs (comparison_string (GET_CODE (x), XEXP (x, 0)), file);
break;
case 'e':
if (GET_CODE (x) == NE)
fputs ("1", file);
else if (GET_CODE (x) == EQ)
fputs ("0", file);
else
fatal_insn ("Bad insn to frv_print_operand, 'e' modifier:", x);
break;
case 'F':
switch (GET_CODE (x))
{
default:
fatal_insn ("Bad insn to frv_print_operand, 'F' modifier:", x);
case EQ: fputs ("ne", file); break;
case NE: fputs ("eq", file); break;
case LT: fputs ("uge", file); break;
case LE: fputs ("ug", file); break;
case GT: fputs ("ule", file); break;
case GE: fputs ("ul", file); break;
}
break;
case 'f':
switch (GET_CODE (x))
{
default:
fatal_insn ("Bad insn to frv_print_operand, 'f' modifier:", x);
case EQ: fputs ("eq", file); break;
case NE: fputs ("ne", file); break;
case LT: fputs ("lt", file); break;
case LE: fputs ("le", file); break;
case GT: fputs ("gt", file); break;
case GE: fputs ("ge", file); break;
}
break;
case 'g':
if (GET_CODE (x) != CONST_INT)
fatal_insn ("Bad insn to frv_print_operand, 'g' modifier:", x);
fputs (unspec_got_name (INTVAL (x)), file);
break;
case 'I':
if (GET_CODE (x) == MEM)
x = ((GET_CODE (XEXP (x, 0)) == PLUS)
? XEXP (XEXP (x, 0), 1)
: XEXP (x, 0));
else if (GET_CODE (x) == PLUS)
x = XEXP (x, 1);
switch (GET_CODE (x))
{
default:
break;
case CONST_INT:
case SYMBOL_REF:
case CONST:
fputs ("i", file);
break;
}
break;
case 'i':
if (GET_CODE (x) == CONST_INT)
fputs ("i", file);
else
{
if (GET_CODE (x) == CONST_INT
|| (GET_CODE (x) == PLUS
&& (GET_CODE (XEXP (x, 1)) == CONST_INT
|| GET_CODE (XEXP (x, 0)) == CONST_INT)))
fputs ("i", file);
}
break;
case 'L':
if (GET_CODE (x) == REG)
fputs (reg_names[ REGNO (x)+1 ], file);
else
fatal_insn ("Bad insn to frv_print_operand, 'L' modifier:", x);
break;
case 'M':
case 'N':
offset = (code == 'M') ? 0 : UNITS_PER_WORD;
switch (GET_CODE (x))
{
default:
fatal_insn ("Bad insn to frv_print_operand, 'M/N' modifier:", x);
case MEM:
frv_print_operand_memory_reference (file, XEXP (x, 0), offset);
break;
case REG:
case SUBREG:
case CONST_INT:
case PLUS:
case SYMBOL_REF:
frv_print_operand_memory_reference (file, x, offset);
break;
}
break;
case 'O':
switch (GET_CODE (x))
{
default:
fatal_insn ("Bad insn to frv_print_operand, 'O' modifier:", x);
case PLUS: fputs ("add", file); break;
case MINUS: fputs ("sub", file); break;
case AND: fputs ("and", file); break;
case IOR: fputs ("or", file); break;
case XOR: fputs ("xor", file); break;
case ASHIFT: fputs ("sll", file); break;
case ASHIFTRT: fputs ("sra", file); break;
case LSHIFTRT: fputs ("srl", file); break;
}
break;
case 'P':
if (GET_CODE (x) != CONST_INT)
fatal_insn ("Bad insn to frv_print_operand, P modifier:", x);
fprintf (file, ".LCF%ld", (long)INTVAL (x));
break;
case 'U':
if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
fputs ("u", file);
break;
case 'z':
if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
fputs (reg_names[GPR_R0], file);
else if (GET_CODE (x) == REG)
fputs (reg_names [REGNO (x)], file);
else
fatal_insn ("Bad insn in frv_print_operand, z case", x);
break;
case 'x':
if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
{
fprintf (file, "%s0x%.4lx", IMMEDIATE_PREFIX, (long) value);
break;
}
case '\0':
if (GET_CODE (x) == REG)
fputs (reg_names [REGNO (x)], file);
else if (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE)
fprintf (file, "%s%ld", IMMEDIATE_PREFIX, (long) value);
else if (frv_const_unspec_p (x, &unspec))
frv_output_const_unspec (file, &unspec);
else if (GET_CODE (x) == MEM)
frv_print_operand_address (file, XEXP (x, 0));
else if (CONSTANT_ADDRESS_P (x))
frv_print_operand_address (file, x);
else
fatal_insn ("Bad insn in frv_print_operand, 0 case", x);
break;
default:
fatal_insn ("frv_print_operand: unknown code", x);
break;
}
return;
}
void
frv_init_cumulative_args (CUMULATIVE_ARGS *cum,
tree fntype,
rtx libname,
tree fndecl,
int incoming)
{
*cum = FIRST_ARG_REGNUM;
if (TARGET_DEBUG_ARG)
{
fprintf (stderr, "\ninit_cumulative_args:");
if (!fndecl && fntype)
fputs (" indirect", stderr);
if (incoming)
fputs (" incoming", stderr);
if (fntype)
{
tree ret_type = TREE_TYPE (fntype);
fprintf (stderr, " return=%s,",
tree_code_name[ (int)TREE_CODE (ret_type) ]);
}
if (libname && GET_CODE (libname) == SYMBOL_REF)
fprintf (stderr, " libname=%s", XSTR (libname, 0));
if (cfun->returns_struct)
fprintf (stderr, " return-struct");
putc ('\n', stderr);
}
}
static bool
frv_must_pass_in_stack (enum machine_mode mode, tree type)
{
if (mode == BLKmode)
return true;
if (type == NULL)
return false;
return AGGREGATE_TYPE_P (type);
}
int
frv_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED)
{
return BITS_PER_WORD;
}
rtx
frv_function_arg (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
tree type ATTRIBUTE_UNUSED,
int named,
int incoming ATTRIBUTE_UNUSED)
{
enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
int arg_num = *cum;
rtx ret;
const char *debstr;
if (xmode == VOIDmode)
{
ret = const0_rtx;
debstr = "<0>";
}
else if (arg_num <= LAST_ARG_REGNUM)
{
ret = gen_rtx_REG (xmode, arg_num);
debstr = reg_names[arg_num];
}
else
{
ret = NULL_RTX;
debstr = "memory";
}
if (TARGET_DEBUG_ARG)
fprintf (stderr,
"function_arg: words = %2d, mode = %4s, named = %d, size = %3d, arg = %s\n",
arg_num, GET_MODE_NAME (mode), named, GET_MODE_SIZE (mode), debstr);
return ret;
}
void
frv_function_arg_advance (CUMULATIVE_ARGS *cum,
enum machine_mode mode,
tree type ATTRIBUTE_UNUSED,
int named)
{
enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
int bytes = GET_MODE_SIZE (xmode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int arg_num = *cum;
*cum = arg_num + words;
if (TARGET_DEBUG_ARG)
fprintf (stderr,
"function_adv: words = %2d, mode = %4s, named = %d, size = %3d\n",
arg_num, GET_MODE_NAME (mode), named, words * UNITS_PER_WORD);
}
static int
frv_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED)
{
enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
int bytes = GET_MODE_SIZE (xmode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int arg_num = *cum;
int ret;
ret = ((arg_num <= LAST_ARG_REGNUM && arg_num + words > LAST_ARG_REGNUM+1)
? LAST_ARG_REGNUM - arg_num + 1
: 0);
ret *= UNITS_PER_WORD;
if (TARGET_DEBUG_ARG && ret)
fprintf (stderr, "frv_arg_partial_bytes: %d\n", ret);
return ret;
}
static FRV_INLINE int
frv_regno_ok_for_base_p (int regno, int strict_p)
{
if (GPR_P (regno))
return TRUE;
if (strict_p)
return (reg_renumber[regno] >= 0 && GPR_P (reg_renumber[regno]));
if (regno == ARG_POINTER_REGNUM)
return TRUE;
return (regno >= FIRST_PSEUDO_REGISTER);
}
int
frv_legitimate_address_p (enum machine_mode mode,
rtx x,
int strict_p,
int condexec_p,
int allow_double_reg_p)
{
rtx x0, x1;
int ret = 0;
HOST_WIDE_INT value;
unsigned regno0;
if (FRV_SYMBOL_REF_TLS_P (x))
return 0;
switch (GET_CODE (x))
{
default:
break;
case SUBREG:
x = SUBREG_REG (x);
if (GET_CODE (x) != REG)
break;
case REG:
ret = frv_regno_ok_for_base_p (REGNO (x), strict_p);
break;
case PRE_MODIFY:
x0 = XEXP (x, 0);
x1 = XEXP (x, 1);
if (GET_CODE (x0) != REG
|| ! frv_regno_ok_for_base_p (REGNO (x0), strict_p)
|| GET_CODE (x1) != PLUS
|| ! rtx_equal_p (x0, XEXP (x1, 0))
|| GET_CODE (XEXP (x1, 1)) != REG
|| ! frv_regno_ok_for_base_p (REGNO (XEXP (x1, 1)), strict_p))
break;
ret = 1;
break;
case CONST_INT:
if (condexec_p)
ret = FALSE;
else
{
ret = IN_RANGE_P (INTVAL (x), -2048, 2047);
if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
ret = IN_RANGE_P (INTVAL (x) + GET_MODE_SIZE (mode) - 1,
-2048, 2047);
}
break;
case PLUS:
x0 = XEXP (x, 0);
x1 = XEXP (x, 1);
if (GET_CODE (x0) == SUBREG)
x0 = SUBREG_REG (x0);
if (GET_CODE (x0) != REG)
break;
regno0 = REGNO (x0);
if (!frv_regno_ok_for_base_p (regno0, strict_p))
break;
switch (GET_CODE (x1))
{
default:
break;
case SUBREG:
x1 = SUBREG_REG (x1);
if (GET_CODE (x1) != REG)
break;
case REG:
if (!allow_double_reg_p && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
ret = FALSE;
else
ret = frv_regno_ok_for_base_p (REGNO (x1), strict_p);
break;
case CONST_INT:
if (condexec_p)
ret = FALSE;
else
{
value = INTVAL (x1);
ret = IN_RANGE_P (value, -2048, 2047);
if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
ret = IN_RANGE_P (value + GET_MODE_SIZE (mode) - 1, -2048, 2047);
}
break;
case CONST:
if (!condexec_p && got12_operand (x1, VOIDmode))
ret = TRUE;
break;
}
break;
}
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, mode = %s, result = %d, addresses are %sstrict%s\n",
GET_MODE_NAME (mode), ret, (strict_p) ? "" : "not ",
(condexec_p) ? ", inside conditional code" : "");
debug_rtx (x);
}
return ret;
}
static rtx
gen_inlined_tls_plt (rtx addr)
{
rtx mem, retval, dest;
rtx picreg = get_hard_reg_initial_val (Pmode, FDPIC_REG);
dest = gen_reg_rtx (DImode);
if (flag_pic == 1)
{
emit_insn (gen_tls_lddi (dest, addr, picreg));
}
else
{
rtx reguse = gen_reg_rtx (Pmode);
emit_insn (gen_tlsoff_hilo (reguse, addr, GEN_INT (R_FRV_GOTTLSDESCHI)));
emit_insn (gen_tls_tlsdesc_ldd (dest, picreg, reguse, addr));
}
retval = gen_reg_rtx (Pmode);
emit_insn (gen_tls_indirect_call (retval, addr, dest, picreg));
return retval;
}
static rtx
gen_tlsmoff (rtx addr, rtx reg)
{
rtx dest = gen_reg_rtx (Pmode);
if (TARGET_BIG_TLS)
{
dest = gen_reg_rtx (Pmode);
emit_insn (gen_tlsoff_hilo (dest, addr,
GEN_INT (R_FRV_TLSMOFFHI)));
dest = gen_rtx_PLUS (Pmode, dest, reg);
}
else
{
dest = gen_reg_rtx (Pmode);
emit_insn (gen_symGOTOFF2reg_i (dest, addr, reg,
GEN_INT (R_FRV_TLSMOFF12)));
}
return dest;
}
static rtx
frv_legitimize_tls_address (rtx addr, enum tls_model model)
{
rtx dest, tp = gen_rtx_REG (Pmode, 29);
rtx picreg = get_hard_reg_initial_val (Pmode, 15);
switch (model)
{
case TLS_MODEL_INITIAL_EXEC:
if (flag_pic == 1)
{
dest = gen_reg_rtx (Pmode);
emit_insn (gen_tls_load_gottlsoff12 (dest, addr, picreg));
dest = gen_rtx_PLUS (Pmode, tp, dest);
}
else
{
rtx tmp = gen_reg_rtx (Pmode);
dest = gen_reg_rtx (Pmode);
emit_insn (gen_tlsoff_hilo (tmp, addr,
GEN_INT (R_FRV_GOTTLSOFF_HI)));
emit_insn (gen_tls_tlsoff_ld (dest, picreg, tmp, addr));
dest = gen_rtx_PLUS (Pmode, tp, dest);
}
break;
case TLS_MODEL_LOCAL_DYNAMIC:
{
rtx reg, retval;
if (TARGET_INLINE_PLT)
retval = gen_inlined_tls_plt (GEN_INT (0));
else
{
retval = gen_reg_rtx (Pmode);
emit_insn (gen_call_gettlsoff (retval, GEN_INT (0), picreg));
}
reg = gen_reg_rtx (Pmode);
emit_insn (gen_rtx_SET (VOIDmode, reg,
gen_rtx_PLUS (Pmode,
retval, tp)));
dest = gen_tlsmoff (addr, reg);
break;
}
case TLS_MODEL_LOCAL_EXEC:
dest = gen_tlsmoff (addr, gen_rtx_REG (Pmode, 29));
break;
case TLS_MODEL_GLOBAL_DYNAMIC:
{
rtx retval;
if (TARGET_INLINE_PLT)
retval = gen_inlined_tls_plt (addr);
else
{
retval = gen_reg_rtx (Pmode);
emit_insn (gen_call_gettlsoff (retval, addr, picreg));
}
dest = gen_rtx_PLUS (Pmode, retval, tp);
break;
}
default:
abort ();
}
return dest;
}
rtx
frv_legitimize_address (rtx x,
rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (x) == SYMBOL_REF)
{
enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
if (model != 0)
return frv_legitimize_tls_address (x, model);
}
return NULL_RTX;
}
static bool
frv_local_funcdesc_p (rtx fnx)
{
tree fn;
enum symbol_visibility vis;
bool ret;
if (! SYMBOL_REF_LOCAL_P (fnx))
return FALSE;
fn = SYMBOL_REF_DECL (fnx);
if (! fn)
return FALSE;
vis = DECL_VISIBILITY (fn);
if (vis == VISIBILITY_PROTECTED)
vis = VISIBILITY_DEFAULT;
else if (flag_shlib)
return TRUE;
ret = default_binds_local_p_1 (fn, flag_pic);
DECL_VISIBILITY (fn) = vis;
return ret;
}
rtx
frv_gen_GPsym2reg (rtx dest, rtx src)
{
tree gp = get_identifier ("_gp");
rtx gp_sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (gp));
return gen_symGOT2reg (dest, gp_sym, src, GEN_INT (R_FRV_GOT12));
}
static const char *
unspec_got_name (int i)
{
switch (i)
{
case R_FRV_GOT12: return "got12";
case R_FRV_GOTHI: return "gothi";
case R_FRV_GOTLO: return "gotlo";
case R_FRV_FUNCDESC: return "funcdesc";
case R_FRV_FUNCDESC_GOT12: return "gotfuncdesc12";
case R_FRV_FUNCDESC_GOTHI: return "gotfuncdeschi";
case R_FRV_FUNCDESC_GOTLO: return "gotfuncdesclo";
case R_FRV_FUNCDESC_VALUE: return "funcdescvalue";
case R_FRV_FUNCDESC_GOTOFF12: return "gotofffuncdesc12";
case R_FRV_FUNCDESC_GOTOFFHI: return "gotofffuncdeschi";
case R_FRV_FUNCDESC_GOTOFFLO: return "gotofffuncdesclo";
case R_FRV_GOTOFF12: return "gotoff12";
case R_FRV_GOTOFFHI: return "gotoffhi";
case R_FRV_GOTOFFLO: return "gotofflo";
case R_FRV_GPREL12: return "gprel12";
case R_FRV_GPRELHI: return "gprelhi";
case R_FRV_GPRELLO: return "gprello";
case R_FRV_GOTTLSOFF_HI: return "gottlsoffhi";
case R_FRV_GOTTLSOFF_LO: return "gottlsofflo";
case R_FRV_TLSMOFFHI: return "tlsmoffhi";
case R_FRV_TLSMOFFLO: return "tlsmofflo";
case R_FRV_TLSMOFF12: return "tlsmoff12";
case R_FRV_TLSDESCHI: return "tlsdeschi";
case R_FRV_TLSDESCLO: return "tlsdesclo";
case R_FRV_GOTTLSDESCHI: return "gottlsdeschi";
case R_FRV_GOTTLSDESCLO: return "gottlsdesclo";
default: abort ();
}
}
static void
frv_output_const_unspec (FILE *stream, const struct frv_unspec *unspec)
{
fprintf (stream, "#%s(", unspec_got_name (unspec->reloc));
output_addr_const (stream, plus_constant (unspec->symbol, unspec->offset));
fputs (")", stream);
}
rtx
frv_find_base_term (rtx x)
{
struct frv_unspec unspec;
if (frv_const_unspec_p (x, &unspec)
&& frv_small_data_reloc_p (unspec.symbol, unspec.reloc))
return plus_constant (unspec.symbol, unspec.offset);
return x;
}
static int
frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
{
return ((GET_MODE (op) == mode || mode == VOIDmode)
&& GET_CODE (op) == MEM
&& frv_legitimate_address_p (mode, XEXP (op, 0),
reload_completed, condexec_p, FALSE));
}
void
frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
{
rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG);
rtx c, rvrtx=0;
rtx addr;
if (ret_value)
{
rvrtx = operands[0];
operands ++;
}
addr = XEXP (operands[0], 0);
if (GET_CODE (addr) == SYMBOL_REF
&& ((!SYMBOL_REF_LOCAL_P (addr) && TARGET_INLINE_PLT)
|| sibcall))
{
rtx x, dest;
dest = gen_reg_rtx (SImode);
if (flag_pic != 1)
x = gen_symGOTOFF2reg_hilo (dest, addr, OUR_FDPIC_REG,
GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
else
x = gen_symGOTOFF2reg (dest, addr, OUR_FDPIC_REG,
GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
emit_insn (x);
cfun->uses_pic_offset_table = TRUE;
addr = dest;
}
else if (GET_CODE (addr) == SYMBOL_REF)
{
if (ret_value)
c = gen_call_value_fdpicsi (rvrtx, addr, operands[1],
operands[2], picreg, lr);
else
c = gen_call_fdpicsi (addr, operands[1], operands[2], picreg, lr);
emit_call_insn (c);
return;
}
else if (! ldd_address_operand (addr, Pmode))
addr = force_reg (Pmode, addr);
picreg = gen_reg_rtx (DImode);
emit_insn (gen_movdi_ldd (picreg, addr));
if (sibcall && ret_value)
c = gen_sibcall_value_fdpicdi (rvrtx, picreg, const0_rtx);
else if (sibcall)
c = gen_sibcall_fdpicdi (picreg, const0_rtx);
else if (ret_value)
c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr);
else
c = gen_call_fdpicdi (picreg, const0_rtx, lr);
emit_call_insn (c);
}
int
ldd_address_operand (rtx x, enum machine_mode mode)
{
if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
return FALSE;
return frv_legitimate_address_p (DImode, x, reload_completed, FALSE, TRUE);
}
int
fdpic_fptr_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
int
frv_load_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (reload_in_progress)
{
rtx tmp = op;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
op = reg_equiv_memory_loc[REGNO (tmp)];
}
return op && memory_operand (op, mode);
}
int
gpr_or_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE;
}
int
gpr_or_int12_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
if (got12_operand (op, mode))
return true;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
int
gpr_fpr_or_int12_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE;
}
int
fpr_or_int6_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -32, 31);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
}
int
gpr_or_int10_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -512, 511);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
int
gpr_or_int_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return TRUE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
int
int12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), -2048, 2047);
}
int
int6_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), -32, 31);
}
int
int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), -16, 15);
}
int
uint5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 31);
}
int
uint4_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 15);
}
int
uint1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 1);
}
int
int_2word_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
long l;
switch (GET_CODE (op))
{
default:
break;
case LABEL_REF:
if (TARGET_FDPIC)
return FALSE;
return (flag_pic == 0);
case CONST:
if (flag_pic || TARGET_FDPIC)
return FALSE;
op = XEXP (op, 0);
if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
op = XEXP (op, 0);
return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
case SYMBOL_REF:
if (TARGET_FDPIC)
return FALSE;
return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));
case CONST_INT:
return ! IN_RANGE_P (INTVAL (op), -32768, 32767);
case CONST_DOUBLE:
if (GET_MODE (op) == SFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
return ! IN_RANGE_P (value, -32768, 32767);
}
else if (GET_MODE (op) == VOIDmode)
{
value = CONST_DOUBLE_LOW (op);
return ! IN_RANGE_P (value, -32768, 32767);
}
break;
}
return FALSE;
}
int
uint16_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), 0, 0xffff);
}
int
upper_int16_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return ((INTVAL (op) & 0xffff) == 0);
}
int
integer_register_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
int
gpr_no_subreg_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
int
fpr_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
}
int
even_reg_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) == 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) == 0);
return FALSE;
}
int
odd_reg_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) != 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) != 0);
return FALSE;
}
int
even_gpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) == 0);
}
int
odd_gpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) != 0);
}
int
quad_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 3) == 0);
}
int
even_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) == 0);
}
int
odd_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) != 0);
}
int
dbl_memory_one_insn_operand (rtx op, enum machine_mode mode)
{
rtx addr;
rtx addr_reg;
if (! TARGET_DWORD)
return FALSE;
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) == REG)
addr_reg = addr;
else if (GET_CODE (addr) == PLUS)
{
rtx addr0 = XEXP (addr, 0);
rtx addr1 = XEXP (addr, 1);
if (GET_CODE (addr0) != REG)
return FALSE;
if (got12_operand (addr1, VOIDmode))
return TRUE;
if (GET_CODE (addr1) != CONST_INT)
return FALSE;
if ((INTVAL (addr1) & 7) != 0)
return FALSE;
addr_reg = addr0;
}
else
return FALSE;
if (addr_reg == frame_pointer_rtx || addr_reg == stack_pointer_rtx)
return TRUE;
return FALSE;
}
int
dbl_memory_two_insn_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
if (! TARGET_DWORD)
return TRUE;
return ! dbl_memory_one_insn_operand (op, mode);
}
int
move_destination_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
}
int
movcc_fp_destination_operand (rtx op, enum machine_mode mode)
{
if (fcc_operand (op, mode))
return FALSE;
return move_destination_operand (op, mode);
}
static bool
frv_function_symbol_referenced_p (rtx x)
{
const char *format;
int length;
int j;
if (GET_CODE (x) == SYMBOL_REF)
return SYMBOL_REF_FUNCTION_P (x);
length = GET_RTX_LENGTH (GET_CODE (x));
format = GET_RTX_FORMAT (GET_CODE (x));
for (j = 0; j < length; ++j)
{
switch (format[j])
{
case 'e':
if (frv_function_symbol_referenced_p (XEXP (x, j)))
return TRUE;
break;
case 'V':
case 'E':
if (XVEC (x, j) != 0)
{
int k;
for (k = 0; k < XVECLEN (x, j); ++k)
if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
return TRUE;
}
break;
default:
break;
}
}
return FALSE;
}
int
move_source_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return immediate_operand (op, mode);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
}
int
condexec_dest_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
}
int
condexec_source_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
}
int
reg_or_0_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
default:
break;
case REG:
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return register_operand (op, mode);
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
}
return FALSE;
}
int
lr_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != LR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
int
fdpic_operand (rtx op, enum machine_mode mode)
{
if (!TARGET_FDPIC)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
int
got12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
struct frv_unspec unspec;
if (frv_const_unspec_p (op, &unspec))
switch (unspec.reloc)
{
case R_FRV_GOT12:
case R_FRV_GOTOFF12:
case R_FRV_FUNCDESC_GOT12:
case R_FRV_FUNCDESC_GOTOFF12:
case R_FRV_GPREL12:
case R_FRV_TLSMOFF12:
return true;
}
return false;
}
int
const_unspec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
struct frv_unspec unspec;
return frv_const_unspec_p (op, &unspec);
}
int
gpr_or_memory_operand (rtx op, enum machine_mode mode)
{
return (integer_register_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
}
int
gpr_or_memory_operand_with_scratch (rtx op, enum machine_mode mode)
{
rtx addr;
if (gpr_or_memory_operand (op, mode))
return TRUE;
if (GET_CODE (op) != MEM)
return FALSE;
if (GET_MODE (op) != mode)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) != PLUS)
return FALSE;
if (!integer_register_operand (XEXP (addr, 0), Pmode))
return FALSE;
if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
return FALSE;
return TRUE;
}
int
fpr_or_memory_operand (rtx op, enum machine_mode mode)
{
return (fpr_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
}
int
icc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICC_OR_PSEUDO_P (regno);
}
int
fcc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCC_OR_PSEUDO_P (regno);
}
int
cc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CC_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
int
icr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICR_OR_PSEUDO_P (regno);
}
int
fcr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCR_OR_PSEUDO_P (regno);
}
int
cr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
int
call_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
if (GET_CODE (op) == SYMBOL_REF)
return !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);
return gpr_or_int12_operand (op, mode);
}
int
sibcall_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
return gpr_or_int12_operand (op, mode);
}
int
symbolic_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code c = GET_CODE (op);
if (c == CONST)
{
return GET_MODE (op) == SImode
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT;
}
return c == SYMBOL_REF || c == CONST_INT;
}
int
relational_operator (rtx op, enum machine_mode mode)
{
return (integer_relational_operator (op, mode)
|| float_relational_operator (op, mode));
}
int
integer_relational_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
case LT:
case GE:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CCmode);
case LE:
case GT:
return GET_MODE (XEXP (op, 0)) == CCmode;
case GTU:
case GEU:
case LTU:
case LEU:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CC_UNSmode);
}
}
int
float_relational_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ: case NE:
case LE: case LT:
case GE: case GT:
#if 0
case UEQ: case UNE:
case ULE: case ULT:
case UGE: case UGT:
case ORDERED:
case UNORDERED:
#endif
return GET_MODE (XEXP (op, 0)) == CC_FPmode;
}
}
int
ccr_eqne_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
rtx op0;
rtx op1;
int regno;
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
break;
}
op1 = XEXP (op, 1);
if (op1 != const0_rtx)
return FALSE;
op0 = XEXP (op, 0);
if (GET_CODE (op0) != REG)
return FALSE;
regno = REGNO (op0);
if (op_mode == CC_CCRmode && CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
int
minmax_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case SMIN:
case SMAX:
case UMIN:
case UMAX:
break;
}
if (! integer_register_operand (XEXP (op, 0), mode))
return FALSE;
if (! gpr_or_int10_operand (XEXP (op, 1), mode))
return FALSE;
return TRUE;
}
int
condexec_si_binary_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
return TRUE;
}
}
int
condexec_si_media_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case AND:
case IOR:
case XOR:
return TRUE;
}
}
int
condexec_si_divide_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case DIV:
case UDIV:
return TRUE;
}
}
int
condexec_si_unary_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case NOT:
return TRUE;
}
}
int
condexec_sf_conv_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case ABS:
return TRUE;
}
}
int
condexec_sf_add_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
return TRUE;
}
}
int
condexec_memory_operand (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
rtx addr;
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (op_mode)
{
default:
return FALSE;
case QImode:
case HImode:
case SImode:
case SFmode:
break;
}
if (GET_CODE (op) != MEM)
return FALSE;
addr = XEXP (op, 0);
return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
}
int
intop_compare_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFTRT:
case LSHIFTRT:
return GET_MODE (op) == SImode;
}
}
int
acc_operand (rtx op, enum machine_mode mode)
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACC_P (REGNO (op))
&& ((REGNO (op) - ACC_FIRST) & ~ACC_MASK) == 0);
}
int
even_acc_operand (rtx op, enum machine_mode mode)
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0;
}
int
quad_acc_operand (rtx op, enum machine_mode mode)
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
}
int
accg_operand (rtx op, enum machine_mode mode)
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACCG_P (REGNO (op))
&& ((REGNO (op) - ACCG_FIRST) & ~ACC_MASK) == 0);
}
int
direct_return_p (void)
{
frv_stack_t *info;
if (!reload_completed)
return FALSE;
info = frv_stack_info ();
return (info->total_size == 0);
}
void
frv_emit_move (enum machine_mode mode, rtx dest, rtx src)
{
if (GET_CODE (src) == SYMBOL_REF)
{
enum tls_model model = SYMBOL_REF_TLS_MODEL (src);
if (model != 0)
src = frv_legitimize_tls_address (src, model);
}
switch (mode)
{
case SImode:
if (frv_emit_movsi (dest, src))
return;
break;
case QImode:
case HImode:
case DImode:
case SFmode:
case DFmode:
if (!reload_in_progress
&& !reload_completed
&& !register_operand (dest, mode)
&& !reg_or_0_operand (src, mode))
src = copy_to_mode_reg (mode, src);
break;
default:
abort ();
}
emit_insn (gen_rtx_SET (VOIDmode, dest, src));
}
int
frv_emit_movsi (rtx dest, rtx src)
{
int base_regno = -1;
int unspec = 0;
rtx sym = src;
struct frv_unspec old_unspec;
if (!reload_in_progress
&& !reload_completed
&& !register_operand (dest, SImode)
&& (!reg_or_0_operand (src, SImode)
|| (GET_CODE (src) == REG
&& IN_RANGE_P (REGNO (src),
FIRST_VIRTUAL_REGISTER,
LAST_VIRTUAL_REGISTER))))
{
emit_insn (gen_rtx_SET (VOIDmode, dest, copy_to_mode_reg (SImode, src)));
return TRUE;
}
switch (GET_CODE (src))
{
default:
break;
case LABEL_REF:
handle_label:
if (TARGET_FDPIC)
{
if (TARGET_GPREL_RO)
unspec = R_FRV_GPREL12;
else
unspec = R_FRV_GOT12;
}
else if (flag_pic)
base_regno = PIC_REGNO;
break;
case CONST:
if (frv_const_unspec_p (src, &old_unspec))
break;
if (TARGET_FDPIC && frv_function_symbol_referenced_p (XEXP (src, 0)))
{
handle_whatever:
src = force_reg (GET_MODE (XEXP (src, 0)), XEXP (src, 0));
emit_move_insn (dest, src);
return TRUE;
}
else
{
sym = XEXP (sym, 0);
if (GET_CODE (sym) == PLUS
&& GET_CODE (XEXP (sym, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (sym, 1)) == CONST_INT)
sym = XEXP (sym, 0);
if (GET_CODE (sym) == SYMBOL_REF)
goto handle_sym;
else if (GET_CODE (sym) == LABEL_REF)
goto handle_label;
else
goto handle_whatever;
}
break;
case SYMBOL_REF:
handle_sym:
if (TARGET_FDPIC)
{
enum tls_model model = SYMBOL_REF_TLS_MODEL (sym);
if (model != 0)
{
src = frv_legitimize_tls_address (src, model);
emit_move_insn (dest, src);
return TRUE;
}
if (SYMBOL_REF_FUNCTION_P (sym))
{
if (frv_local_funcdesc_p (sym))
unspec = R_FRV_FUNCDESC_GOTOFF12;
else
unspec = R_FRV_FUNCDESC_GOT12;
}
else
{
if (CONSTANT_POOL_ADDRESS_P (sym))
switch (GET_CODE (get_pool_constant (sym)))
{
case CONST:
case SYMBOL_REF:
case LABEL_REF:
if (flag_pic)
{
unspec = R_FRV_GOTOFF12;
break;
}
default:
if (TARGET_GPREL_RO)
unspec = R_FRV_GPREL12;
else
unspec = R_FRV_GOT12;
break;
}
else if (SYMBOL_REF_LOCAL_P (sym)
&& !SYMBOL_REF_EXTERNAL_P (sym)
&& SYMBOL_REF_DECL (sym)
&& (!DECL_P (SYMBOL_REF_DECL (sym))
|| !DECL_COMMON (SYMBOL_REF_DECL (sym))))
{
tree decl = SYMBOL_REF_DECL (sym);
tree init = TREE_CODE (decl) == VAR_DECL
? DECL_INITIAL (decl)
: TREE_CODE (decl) == CONSTRUCTOR
? decl : 0;
int reloc = 0;
bool named_section, readonly;
if (init && init != error_mark_node)
reloc = compute_reloc_for_constant (init);
named_section = TREE_CODE (decl) == VAR_DECL
&& lookup_attribute ("section", DECL_ATTRIBUTES (decl));
readonly = decl_readonly_section (decl, reloc);
if (named_section)
unspec = R_FRV_GOT12;
else if (!readonly)
unspec = R_FRV_GOTOFF12;
else if (readonly && TARGET_GPREL_RO)
unspec = R_FRV_GPREL12;
else
unspec = R_FRV_GOT12;
}
else
unspec = R_FRV_GOT12;
}
}
else if (SYMBOL_REF_SMALL_P (sym))
base_regno = SDA_BASE_REG;
else if (flag_pic)
base_regno = PIC_REGNO;
break;
}
if (base_regno >= 0)
{
if (GET_CODE (sym) == SYMBOL_REF && SYMBOL_REF_SMALL_P (sym))
emit_insn (gen_symGOTOFF2reg (dest, src,
gen_rtx_REG (Pmode, base_regno),
GEN_INT (R_FRV_GPREL12)));
else
emit_insn (gen_symGOTOFF2reg_hilo (dest, src,
gen_rtx_REG (Pmode, base_regno),
GEN_INT (R_FRV_GPREL12)));
if (base_regno == PIC_REGNO)
cfun->uses_pic_offset_table = TRUE;
return TRUE;
}
if (unspec)
{
rtx x;
if (reload_in_progress || reload_completed)
abort ();
switch (unspec)
{
case R_FRV_GOTOFF12:
if (!frv_small_data_reloc_p (sym, unspec))
x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
GEN_INT (unspec));
else
x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
break;
case R_FRV_GPREL12:
if (!frv_small_data_reloc_p (sym, unspec))
x = gen_symGPREL2reg_hilo (dest, src, OUR_FDPIC_REG,
GEN_INT (unspec));
else
x = gen_symGPREL2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
break;
case R_FRV_FUNCDESC_GOTOFF12:
if (flag_pic != 1)
x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
GEN_INT (unspec));
else
x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
break;
default:
if (flag_pic != 1)
x = gen_symGOT2reg_hilo (dest, src, OUR_FDPIC_REG,
GEN_INT (unspec));
else
x = gen_symGOT2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
break;
}
emit_insn (x);
cfun->uses_pic_offset_table = TRUE;
return TRUE;
}
return FALSE;
}
const char *
output_move_single (rtx operands[], rtx insn)
{
rtx dest = operands[0];
rtx src = operands[1];
if (GET_CODE (dest) == REG)
{
int dest_regno = REGNO (dest);
enum machine_mode mode = GET_MODE (dest);
if (GPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "mov %1, %0";
else if (FPR_P (src_regno))
return "movfg %1, %0";
else if (SPR_P (src_regno))
return "movsg %1, %0";
}
else if (GET_CODE (src) == MEM)
{
switch (mode)
{
default:
break;
case QImode:
return "ldsb%I1%U1 %M1,%0";
case HImode:
return "ldsh%I1%U1 %M1,%0";
case SImode:
case SFmode:
return "ld%I1%U1 %M1, %0";
}
}
else if (GET_CODE (src) == CONST_INT
|| GET_CODE (src) == CONST_DOUBLE)
{
HOST_WIDE_INT value;
if (GET_CODE (src) == CONST_INT)
value = INTVAL (src);
else if (mode == SFmode)
{
REAL_VALUE_TYPE rv;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (rv, src);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
}
else
value = CONST_DOUBLE_LOW (src);
if (IN_RANGE_P (value, -32768, 32767))
return "setlos %1, %0";
return "#";
}
else if (GET_CODE (src) == SYMBOL_REF
|| GET_CODE (src) == LABEL_REF
|| GET_CODE (src) == CONST)
{
return "#";
}
}
else if (FPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "movgf %1, %0";
else if (FPR_P (src_regno))
{
if (TARGET_HARD_FLOAT)
return "fmovs %1, %0";
else
return "mor %1, %1, %0";
}
}
else if (GET_CODE (src) == MEM)
{
switch (mode)
{
default:
break;
case QImode:
return "ldbf%I1%U1 %M1,%0";
case HImode:
return "ldhf%I1%U1 %M1,%0";
case SImode:
case SFmode:
return "ldf%I1%U1 %M1, %0";
}
}
else if (ZERO_P (src))
return "movgf %., %0";
}
else if (SPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "movgs %1, %0";
}
else if (ZERO_P (src))
return "movgs %., %0";
}
}
else if (GET_CODE (dest) == MEM)
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
enum machine_mode mode = GET_MODE (dest);
if (GPR_P (src_regno))
{
switch (mode)
{
default:
break;
case QImode:
return "stb%I0%U0 %1, %M0";
case HImode:
return "sth%I0%U0 %1, %M0";
case SImode:
case SFmode:
return "st%I0%U0 %1, %M0";
}
}
else if (FPR_P (src_regno))
{
switch (mode)
{
default:
break;
case QImode:
return "stbf%I0%U0 %1, %M0";
case HImode:
return "sthf%I0%U0 %1, %M0";
case SImode:
case SFmode:
return "stf%I0%U0 %1, %M0";
}
}
}
else if (ZERO_P (src))
{
switch (GET_MODE (dest))
{
default:
break;
case QImode:
return "stb%I0%U0 %., %M0";
case HImode:
return "sth%I0%U0 %., %M0";
case SImode:
case SFmode:
return "st%I0%U0 %., %M0";
}
}
}
fatal_insn ("Bad output_move_single operand", insn);
return "";
}
const char *
output_move_double (rtx operands[], rtx insn)
{
rtx dest = operands[0];
rtx src = operands[1];
enum machine_mode mode = GET_MODE (dest);
if (GET_CODE (dest) == REG)
{
int dest_regno = REGNO (dest);
if (GPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "#";
else if (FPR_P (src_regno))
{
if (((dest_regno - GPR_FIRST) & 1) == 0
&& ((src_regno - FPR_FIRST) & 1) == 0)
return "movfgd %1, %0";
return "#";
}
}
else if (GET_CODE (src) == MEM)
{
if (dbl_memory_one_insn_operand (src, mode))
return "ldd%I1%U1 %M1, %0";
return "#";
}
else if (GET_CODE (src) == CONST_INT
|| GET_CODE (src) == CONST_DOUBLE)
return "#";
}
else if (FPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
{
if (((dest_regno - FPR_FIRST) & 1) == 0
&& ((src_regno - GPR_FIRST) & 1) == 0)
return "movgfd %1, %0";
return "#";
}
else if (FPR_P (src_regno))
{
if (TARGET_DOUBLE
&& ((dest_regno - FPR_FIRST) & 1) == 0
&& ((src_regno - FPR_FIRST) & 1) == 0)
return "fmovd %1, %0";
return "#";
}
}
else if (GET_CODE (src) == MEM)
{
if (dbl_memory_one_insn_operand (src, mode))
return "lddf%I1%U1 %M1, %0";
return "#";
}
else if (ZERO_P (src))
return "#";
}
}
else if (GET_CODE (dest) == MEM)
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
{
if (((src_regno - GPR_FIRST) & 1) == 0
&& dbl_memory_one_insn_operand (dest, mode))
return "std%I0%U0 %1, %M0";
return "#";
}
if (FPR_P (src_regno))
{
if (((src_regno - FPR_FIRST) & 1) == 0
&& dbl_memory_one_insn_operand (dest, mode))
return "stdf%I0%U0 %1, %M0";
return "#";
}
}
else if (ZERO_P (src))
{
if (dbl_memory_one_insn_operand (dest, mode))
return "std%I0%U0 %., %M0";
return "#";
}
}
fatal_insn ("Bad output_move_double operand", insn);
return "";
}
const char *
output_condmove_single (rtx operands[], rtx insn)
{
rtx dest = operands[2];
rtx src = operands[3];
if (GET_CODE (dest) == REG)
{
int dest_regno = REGNO (dest);
enum machine_mode mode = GET_MODE (dest);
if (GPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "cmov %z3, %2, %1, %e0";
else if (FPR_P (src_regno))
return "cmovfg %3, %2, %1, %e0";
}
else if (GET_CODE (src) == MEM)
{
switch (mode)
{
default:
break;
case QImode:
return "cldsb%I3%U3 %M3, %2, %1, %e0";
case HImode:
return "cldsh%I3%U3 %M3, %2, %1, %e0";
case SImode:
case SFmode:
return "cld%I3%U3 %M3, %2, %1, %e0";
}
}
else if (ZERO_P (src))
return "cmov %., %2, %1, %e0";
}
else if (FPR_P (dest_regno))
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
if (GPR_P (src_regno))
return "cmovgf %3, %2, %1, %e0";
else if (FPR_P (src_regno))
{
if (TARGET_HARD_FLOAT)
return "cfmovs %3,%2,%1,%e0";
else
return "cmor %3, %3, %2, %1, %e0";
}
}
else if (GET_CODE (src) == MEM)
{
if (mode == SImode || mode == SFmode)
return "cldf%I3%U3 %M3, %2, %1, %e0";
}
else if (ZERO_P (src))
return "cmovgf %., %2, %1, %e0";
}
}
else if (GET_CODE (dest) == MEM)
{
if (GET_CODE (src) == REG)
{
int src_regno = REGNO (src);
enum machine_mode mode = GET_MODE (dest);
if (GPR_P (src_regno))
{
switch (mode)
{
default:
break;
case QImode:
return "cstb%I2%U2 %3, %M2, %1, %e0";
case HImode:
return "csth%I2%U2 %3, %M2, %1, %e0";
case SImode:
case SFmode:
return "cst%I2%U2 %3, %M2, %1, %e0";
}
}
else if (FPR_P (src_regno) && (mode == SImode || mode == SFmode))
return "cstf%I2%U2 %3, %M2, %1, %e0";
}
else if (ZERO_P (src))
{
enum machine_mode mode = GET_MODE (dest);
switch (mode)
{
default:
break;
case QImode:
return "cstb%I2%U2 %., %M2, %1, %e0";
case HImode:
return "csth%I2%U2 %., %M2, %1, %e0";
case SImode:
case SFmode:
return "cst%I2%U2 %., %M2, %1, %e0";
}
}
}
fatal_insn ("Bad output_condmove_single operand", insn);
return "";
}
static rtx
frv_emit_comparison (enum rtx_code test, rtx op0, rtx op1)
{
enum machine_mode cc_mode;
rtx cc_reg;
if (GET_MODE (op0) == CC_FPmode && GET_CODE (op1) != REG)
op1 = force_reg (GET_MODE (op0), op1);
cc_mode = SELECT_CC_MODE (test, op0, op1);
cc_reg = ((TARGET_ALLOC_CC)
? gen_reg_rtx (cc_mode)
: gen_rtx_REG (cc_mode,
(cc_mode == CC_FPmode) ? FCC_FIRST : ICC_FIRST));
emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
gen_rtx_COMPARE (cc_mode, op0, op1)));
return cc_reg;
}
int
frv_emit_cond_branch (enum rtx_code test, rtx label)
{
rtx test_rtx;
rtx label_ref;
rtx if_else;
rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
enum machine_mode cc_mode = GET_MODE (cc_reg);
label_ref = gen_rtx_LABEL_REF (VOIDmode, label);
test_rtx = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx);
if_else = gen_rtx_IF_THEN_ELSE (cc_mode, test_rtx, label_ref, pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_else));
return TRUE;
}
int
frv_emit_scc (enum rtx_code test, rtx target)
{
rtx set;
rtx test_rtx;
rtx clobber;
rtx cr_reg;
rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
test_rtx = gen_rtx_fmt_ee (test, SImode, cc_reg, const0_rtx);
set = gen_rtx_SET (VOIDmode, target, test_rtx);
cr_reg = ((TARGET_ALLOC_CC)
? gen_reg_rtx (CC_CCRmode)
: gen_rtx_REG (CC_CCRmode,
((GET_MODE (cc_reg) == CC_FPmode)
? FCR_FIRST
: ICR_FIRST)));
clobber = gen_rtx_CLOBBER (VOIDmode, cr_reg);
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
return TRUE;
}
rtx
frv_split_scc (rtx dest, rtx test, rtx cc_reg, rtx cr_reg, HOST_WIDE_INT value)
{
rtx ret;
start_sequence ();
emit_insn (gen_rtx_SET (VOIDmode,
cr_reg,
gen_rtx_fmt_ee (GET_CODE (test),
GET_MODE (cr_reg),
cc_reg,
const0_rtx)));
emit_move_insn (dest, GEN_INT (value));
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_EQ (GET_MODE (cr_reg),
cr_reg,
const0_rtx),
gen_rtx_SET (VOIDmode, dest, const0_rtx)));
ret = get_insns ();
end_sequence ();
return ret;
}
int
frv_emit_cond_move (rtx dest, rtx test_rtx, rtx src1, rtx src2)
{
rtx set;
rtx clobber_cc;
rtx test2;
rtx cr_reg;
rtx if_rtx;
enum rtx_code test = GET_CODE (test_rtx);
rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
enum machine_mode cc_mode = GET_MODE (cc_reg);
if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
{
HOST_WIDE_INT value1 = INTVAL (src1);
HOST_WIDE_INT value2 = INTVAL (src2);
if (value1 == 0 || value2 == 0)
;
else if (IN_RANGE_P (value1, -2048, 2047)
&& IN_RANGE_P (value2 - value1, -2048, 2047))
;
else
{
src1 = force_reg (GET_MODE (dest), src1);
src2 = force_reg (GET_MODE (dest), src2);
}
}
else
{
if (GET_CODE (src1) == CONST_INT && INTVAL (src1) != 0)
src1 = force_reg (GET_MODE (dest), src1);
if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
src2 = force_reg (GET_MODE (dest), src2);
}
test2 = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx);
if_rtx = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), test2, src1, src2);
set = gen_rtx_SET (VOIDmode, dest, if_rtx);
cr_reg = ((TARGET_ALLOC_CC)
? gen_reg_rtx (CC_CCRmode)
: gen_rtx_REG (CC_CCRmode,
(cc_mode == CC_FPmode) ? FCR_FIRST : ICR_FIRST));
clobber_cc = gen_rtx_CLOBBER (VOIDmode, cr_reg);
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber_cc)));
return TRUE;
}
rtx
frv_split_cond_move (rtx operands[])
{
rtx dest = operands[0];
rtx test = operands[1];
rtx cc_reg = operands[2];
rtx src1 = operands[3];
rtx src2 = operands[4];
rtx cr_reg = operands[5];
rtx ret;
enum machine_mode cr_mode = GET_MODE (cr_reg);
start_sequence ();
emit_insn (gen_rtx_SET (VOIDmode,
cr_reg,
gen_rtx_fmt_ee (GET_CODE (test),
GET_MODE (cr_reg),
cc_reg,
const0_rtx)));
if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
{
HOST_WIDE_INT value1 = INTVAL (src1);
HOST_WIDE_INT value2 = INTVAL (src2);
if (value1 == 0)
{
emit_move_insn (dest, src2);
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (cr_mode, cr_reg,
const0_rtx),
gen_rtx_SET (VOIDmode, dest, src1)));
}
else if (value2 == 0)
{
emit_move_insn (dest, src1);
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_EQ (cr_mode, cr_reg,
const0_rtx),
gen_rtx_SET (VOIDmode, dest, src2)));
}
else if (IN_RANGE_P (value1, -2048, 2047)
&& IN_RANGE_P (value2 - value1, -2048, 2047))
{
rtx dest_si = ((GET_MODE (dest) == SImode)
? dest
: gen_rtx_SUBREG (SImode, dest, 0));
emit_move_insn (dest_si, GEN_INT (value2 - value1));
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (cr_mode, cr_reg,
const0_rtx),
gen_rtx_SET (VOIDmode, dest_si,
const0_rtx)));
emit_insn (gen_addsi3 (dest_si, dest_si, src1));
}
else
abort ();
}
else
{
if (! rtx_equal_p (dest, src1))
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src1)));
if (! rtx_equal_p (dest, src2))
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src2)));
}
ret = get_insns ();
end_sequence ();
return ret;
}
void
frv_split_double_load (rtx dest, rtx source)
{
int regno = REGNO (dest);
rtx dest1 = gen_highpart (SImode, dest);
rtx dest2 = gen_lowpart (SImode, dest);
rtx address = XEXP (source, 0);
if (GET_CODE (address) == PRE_MODIFY
|| ! refers_to_regno_p (regno, regno + 1, address, NULL))
{
emit_move_insn (dest1, change_address (source, SImode, NULL));
emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
}
else
{
emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
emit_move_insn (dest1, change_address (source, SImode, NULL));
}
}
void
frv_split_double_store (rtx dest, rtx source)
{
rtx dest1 = change_address (dest, SImode, NULL);
rtx dest2 = frv_index_memory (dest, SImode, 1);
if (ZERO_P (source))
{
emit_move_insn (dest1, CONST0_RTX (SImode));
emit_move_insn (dest2, CONST0_RTX (SImode));
}
else
{
emit_move_insn (dest1, gen_highpart (SImode, source));
emit_move_insn (dest2, gen_lowpart (SImode, source));
}
}
rtx
frv_split_minmax (rtx operands[])
{
rtx dest = operands[0];
rtx minmax = operands[1];
rtx src1 = operands[2];
rtx src2 = operands[3];
rtx cc_reg = operands[4];
rtx cr_reg = operands[5];
rtx ret;
enum rtx_code test_code;
enum machine_mode cr_mode = GET_MODE (cr_reg);
start_sequence ();
switch (GET_CODE (minmax))
{
default:
abort ();
case SMIN: test_code = LT; break;
case SMAX: test_code = GT; break;
case UMIN: test_code = LTU; break;
case UMAX: test_code = GTU; break;
}
emit_insn (gen_rtx_SET (VOIDmode,
cc_reg,
gen_rtx_COMPARE (GET_MODE (cc_reg),
src1, src2)));
emit_insn (gen_rtx_SET (VOIDmode,
cr_reg,
gen_rtx_fmt_ee (test_code,
GET_MODE (cr_reg),
cc_reg,
const0_rtx)));
if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
{
if (rtx_equal_p (dest, src1))
abort ();
emit_move_insn (dest, src2);
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src1)));
}
else
{
if (! rtx_equal_p (dest, src1))
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src1)));
if (! rtx_equal_p (dest, src2))
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src2)));
}
ret = get_insns ();
end_sequence ();
return ret;
}
rtx
frv_split_abs (rtx operands[])
{
rtx dest = operands[0];
rtx src = operands[1];
rtx cc_reg = operands[2];
rtx cr_reg = operands[3];
rtx ret;
start_sequence ();
emit_insn (gen_rtx_SET (VOIDmode,
cc_reg,
gen_rtx_COMPARE (CCmode, src, const0_rtx)));
emit_insn (gen_rtx_SET (VOIDmode,
cr_reg,
gen_rtx_fmt_ee (LT, CC_CCRmode, cc_reg, const0_rtx)));
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_NE (CC_CCRmode, cr_reg, const0_rtx),
gen_negsi2 (dest, src)));
if (! rtx_equal_p (dest, src))
emit_insn (gen_rtx_COND_EXEC (VOIDmode,
gen_rtx_EQ (CC_CCRmode, cr_reg, const0_rtx),
gen_rtx_SET (VOIDmode, dest, src)));
ret = get_insns ();
end_sequence ();
return ret;
}
static int
frv_clear_registers_used (rtx *ptr, void *data)
{
if (GET_CODE (*ptr) == REG)
{
int regno = REGNO (*ptr);
HARD_REG_SET *p_regs = (HARD_REG_SET *)data;
if (regno < FIRST_PSEUDO_REGISTER)
{
int reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (*ptr));
while (regno < reg_max)
{
CLEAR_HARD_REG_BIT (*p_regs, regno);
regno++;
}
}
}
return 0;
}
void
frv_ifcvt_init_extra_fields (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
{
frv_ifcvt.added_insns_list = NULL_RTX;
frv_ifcvt.cur_scratch_regs = 0;
frv_ifcvt.num_nested_cond_exec = 0;
frv_ifcvt.cr_reg = NULL_RTX;
frv_ifcvt.nested_cc_reg = NULL_RTX;
frv_ifcvt.extra_int_cr = NULL_RTX;
frv_ifcvt.extra_fp_cr = NULL_RTX;
frv_ifcvt.last_nested_if_cr = NULL_RTX;
}
static void
frv_ifcvt_add_insn (rtx pattern, rtx insn, int before_p)
{
rtx link = alloc_EXPR_LIST (VOIDmode, pattern, insn);
link->jump = before_p;
frv_ifcvt.added_insns_list = alloc_EXPR_LIST (VOIDmode, link,
frv_ifcvt.added_insns_list);
if (TARGET_DEBUG_COND_EXEC)
{
fprintf (stderr,
"\n:::::::::: frv_ifcvt_add_insn: add the following %s insn %d:\n",
(before_p) ? "before" : "after",
(int)INSN_UID (insn));
debug_rtx (pattern);
}
}
void
frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
{
basic_block test_bb = ce_info->test_bb;
basic_block then_bb = ce_info->then_bb;
basic_block else_bb = ce_info->else_bb;
basic_block join_bb = ce_info->join_bb;
rtx true_expr = *p_true;
rtx cr;
rtx cc;
rtx nested_cc;
enum machine_mode mode = GET_MODE (true_expr);
int j;
basic_block *bb;
int num_bb;
frv_tmp_reg_t *tmp_reg = &frv_ifcvt.tmp_reg;
rtx check_insn;
rtx sub_cond_exec_reg;
enum rtx_code code;
enum rtx_code code_true;
enum rtx_code code_false;
enum reg_class cc_class;
enum reg_class cr_class;
int cc_first;
int cc_last;
reg_set_iterator rsi;
if (!reload_completed || TARGET_NO_COND_EXEC
|| (TARGET_NO_NESTED_CE && ce_info->pass > 1))
goto fail;
memset (&tmp_reg->regs, 0, sizeof (tmp_reg->regs));
COPY_HARD_REG_SET (tmp_reg->regs, call_used_reg_set);
AND_COMPL_HARD_REG_SET (tmp_reg->regs, fixed_reg_set);
SET_HARD_REG_BIT (tmp_reg->regs, ICC_TEMP);
SET_HARD_REG_BIT (tmp_reg->regs, ICR_TEMP);
if (ce_info->pass > 1)
{
CLEAR_HARD_REG_SET (frv_ifcvt.nested_cc_ok_rewrite);
for (j = CC_FIRST; j <= CC_LAST; j++)
if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
{
if (REGNO_REG_SET_P (then_bb->global_live_at_start, j))
continue;
if (else_bb && REGNO_REG_SET_P (else_bb->global_live_at_start, j))
continue;
if (join_bb && REGNO_REG_SET_P (join_bb->global_live_at_start, j))
continue;
SET_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j);
}
}
for (j = 0; j < frv_ifcvt.cur_scratch_regs; j++)
frv_ifcvt.scratch_regs[j] = NULL_RTX;
frv_ifcvt.added_insns_list = NULL_RTX;
frv_ifcvt.cur_scratch_regs = 0;
bb = (basic_block *) alloca ((2 + ce_info->num_multiple_test_blocks)
* sizeof (basic_block));
if (join_bb)
{
int regno;
EXECUTE_IF_SET_IN_REG_SET (join_bb->global_live_at_start, 0, regno, rsi)
{
if (regno < FIRST_PSEUDO_REGISTER)
CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
}
}
num_bb = 0;
if (ce_info->num_multiple_test_blocks)
{
basic_block multiple_test_bb = ce_info->last_test_bb;
while (multiple_test_bb != test_bb)
{
bb[num_bb++] = multiple_test_bb;
multiple_test_bb = EDGE_PRED (multiple_test_bb, 0)->src;
}
}
bb[num_bb++] = then_bb;
if (else_bb)
bb[num_bb++] = else_bb;
sub_cond_exec_reg = NULL_RTX;
frv_ifcvt.num_nested_cond_exec = 0;
for (j = 0; j < num_bb; j++)
{
rtx last_insn = BB_END (bb[j]);
rtx insn = BB_HEAD (bb[j]);
int regno;
if (dump_file)
fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
(bb[j] == else_bb) ? "else" : ((bb[j] == then_bb) ? "then" : "test"),
(int) bb[j]->index,
(int) INSN_UID (BB_HEAD (bb[j])),
(int) INSN_UID (BB_END (bb[j])));
EXECUTE_IF_SET_IN_REG_SET (bb[j]->global_live_at_start, 0, regno, rsi)
{
if (regno < FIRST_PSEUDO_REGISTER)
CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
}
for (;;)
{
if (INSN_P (insn))
{
rtx pattern;
rtx set;
int skip_nested_if = FALSE;
for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
(void *)&tmp_reg->regs);
pattern = PATTERN (insn);
if (GET_CODE (pattern) == COND_EXEC)
{
rtx reg = XEXP (COND_EXEC_TEST (pattern), 0);
if (reg != sub_cond_exec_reg)
{
sub_cond_exec_reg = reg;
frv_ifcvt.num_nested_cond_exec++;
}
}
set = single_set_pattern (pattern);
if (set)
{
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
if (GET_CODE (dest) == REG)
{
int regno = REGNO (dest);
enum rtx_code src_code = GET_CODE (src);
if (CC_P (regno) && src_code == COMPARE)
skip_nested_if = TRUE;
else if (CR_P (regno)
&& (src_code == IF_THEN_ELSE
|| COMPARISON_P (src)))
skip_nested_if = TRUE;
}
}
if (! skip_nested_if)
for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
(void *)&frv_ifcvt.nested_cc_ok_rewrite);
}
if (insn == last_insn)
break;
insn = NEXT_INSN (insn);
}
}
if (ce_info->pass > 1)
{
for (j = CC_FIRST; j <= CC_LAST; j++)
if (TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j))
SET_HARD_REG_BIT (tmp_reg->regs, j);
else
CLEAR_HARD_REG_BIT (tmp_reg->regs, j);
}
if (dump_file)
{
int num_gprs = 0;
fprintf (dump_file, "Available GPRs: ");
for (j = GPR_FIRST; j <= GPR_LAST; j++)
if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
{
fprintf (dump_file, " %d [%s]", j, reg_names[j]);
if (++num_gprs > GPR_TEMP_NUM+2)
break;
}
fprintf (dump_file, "%s\nAvailable CRs: ",
(num_gprs > GPR_TEMP_NUM+2) ? " ..." : "");
for (j = CR_FIRST; j <= CR_LAST; j++)
if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
fprintf (dump_file, " %d [%s]", j, reg_names[j]);
fputs ("\n", dump_file);
if (ce_info->pass > 1)
{
fprintf (dump_file, "Modifiable CCs: ");
for (j = CC_FIRST; j <= CC_LAST; j++)
if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
fprintf (dump_file, " %d [%s]", j, reg_names[j]);
fprintf (dump_file, "\n%d nested COND_EXEC statements\n",
frv_ifcvt.num_nested_cond_exec);
}
}
if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
{
cr_class = ICR_REGS;
cc_class = ICC_REGS;
cc_first = ICC_FIRST;
cc_last = ICC_LAST;
}
else if (mode == CC_FPmode)
{
cr_class = FCR_REGS;
cc_class = FCC_REGS;
cc_first = FCC_FIRST;
cc_last = FCC_LAST;
}
else
{
cc_first = cc_last = 0;
cr_class = cc_class = NO_REGS;
}
cc = XEXP (true_expr, 0);
nested_cc = cr = NULL_RTX;
if (cc_class != NO_REGS)
{
int cc_regno;
for (cc_regno = cc_first; cc_regno <= cc_last; cc_regno++)
{
int cr_regno = cc_regno - CC_FIRST + CR_FIRST;
if (TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cc_regno)
&& TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cr_regno))
{
frv_ifcvt.tmp_reg.next_reg[ (int)cr_class ] = cr_regno;
cr = frv_alloc_temp_reg (tmp_reg, cr_class, CC_CCRmode, TRUE,
TRUE);
frv_ifcvt.tmp_reg.next_reg[ (int)cc_class ] = cc_regno;
nested_cc = frv_alloc_temp_reg (tmp_reg, cc_class, CCmode,
TRUE, TRUE);
break;
}
}
}
if (! cr)
{
if (dump_file)
fprintf (dump_file, "Could not allocate a CR temporary register\n");
goto fail;
}
if (dump_file)
fprintf (dump_file,
"Will use %s for conditional execution, %s for nested comparisons\n",
reg_names[ REGNO (cr)],
(nested_cc) ? reg_names[ REGNO (nested_cc) ] : "<none>");
code = GET_CODE (true_expr);
if (GET_MODE (cc) != CC_FPmode)
{
code = reverse_condition (code);
code_true = EQ;
code_false = NE;
}
else
{
code_true = NE;
code_false = EQ;
}
check_insn = gen_rtx_SET (VOIDmode, cr,
gen_rtx_fmt_ee (code, CC_CCRmode, cc, const0_rtx));
frv_ifcvt_add_insn (check_insn, BB_END (test_bb), TRUE);
frv_ifcvt.cr_reg = cr;
frv_ifcvt.nested_cc_reg = nested_cc;
*p_true = gen_rtx_fmt_ee (code_true, CC_CCRmode, cr, const0_rtx);
*p_false = gen_rtx_fmt_ee (code_false, CC_CCRmode, cr, const0_rtx);
return;
fail:
*p_true = NULL_RTX;
*p_false = NULL_RTX;
if (dump_file)
fprintf (dump_file, "Disabling this conditional execution.\n");
return;
}
void
frv_ifcvt_modify_multiple_tests (ce_if_block_t *ce_info,
basic_block bb,
rtx *p_true,
rtx *p_false)
{
rtx old_true = XEXP (*p_true, 0);
rtx old_false = XEXP (*p_false, 0);
rtx true_expr = XEXP (*p_true, 1);
rtx false_expr = XEXP (*p_false, 1);
rtx test_expr;
rtx old_test;
rtx cr = XEXP (old_true, 0);
rtx check_insn;
rtx new_cr = NULL_RTX;
rtx *p_new_cr = (rtx *)0;
rtx if_else;
rtx compare;
rtx cc;
enum reg_class cr_class;
enum machine_mode mode = GET_MODE (true_expr);
rtx (*logical_func)(rtx, rtx, rtx);
if (TARGET_DEBUG_COND_EXEC)
{
fprintf (stderr,
"\n:::::::::: frv_ifcvt_modify_multiple_tests, before modification for %s\ntrue insn:\n",
ce_info->and_and_p ? "&&" : "||");
debug_rtx (*p_true);
fputs ("\nfalse insn:\n", stderr);
debug_rtx (*p_false);
}
if (TARGET_NO_MULTI_CE)
goto fail;
if (GET_CODE (cr) != REG)
goto fail;
if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
{
cr_class = ICR_REGS;
p_new_cr = &frv_ifcvt.extra_int_cr;
}
else if (mode == CC_FPmode)
{
cr_class = FCR_REGS;
p_new_cr = &frv_ifcvt.extra_fp_cr;
}
else
goto fail;
new_cr = *p_new_cr;
if (! new_cr)
{
new_cr = *p_new_cr = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, cr_class,
CC_CCRmode, TRUE, TRUE);
if (! new_cr)
goto fail;
}
if (ce_info->and_and_p)
{
old_test = old_false;
test_expr = true_expr;
logical_func = (GET_CODE (old_true) == EQ) ? gen_andcr : gen_andncr;
*p_true = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
*p_false = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
}
else
{
old_test = old_false;
test_expr = false_expr;
logical_func = (GET_CODE (old_false) == EQ) ? gen_orcr : gen_orncr;
*p_true = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
*p_false = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
}
frv_ifcvt_add_insn ((*logical_func) (cr, cr, new_cr), BB_END (bb), TRUE);
cc = XEXP (test_expr, 0);
compare = gen_rtx_fmt_ee (GET_CODE (test_expr), CC_CCRmode, cc, const0_rtx);
if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, old_test, compare, const0_rtx);
check_insn = gen_rtx_SET (VOIDmode, new_cr, if_else);
frv_ifcvt_add_insn (check_insn, BB_END (bb), TRUE);
if (TARGET_DEBUG_COND_EXEC)
{
fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, after modification\ntrue insn:\n",
stderr);
debug_rtx (*p_true);
fputs ("\nfalse insn:\n", stderr);
debug_rtx (*p_false);
}
return;
fail:
*p_true = *p_false = NULL_RTX;
if (new_cr)
{
CLEAR_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, REGNO (new_cr));
*p_new_cr = NULL_RTX;
}
if (TARGET_DEBUG_COND_EXEC)
fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, failed.\n", stderr);
return;
}
static rtx
frv_ifcvt_load_value (rtx value, rtx insn ATTRIBUTE_UNUSED)
{
int num_alloc = frv_ifcvt.cur_scratch_regs;
int i;
rtx reg;
if (value == const0_rtx)
return gen_rtx_REG (SImode, GPR_FIRST);
if (CONSTANT_P (value)
|| (GET_CODE (value) == REG && REGNO (value) == LR_REGNO))
{
for (i = 0; i < num_alloc; i++)
{
if (rtx_equal_p (SET_SRC (frv_ifcvt.scratch_regs[i]), value))
return SET_DEST (frv_ifcvt.scratch_regs[i]);
}
}
if (num_alloc >= GPR_TEMP_NUM)
{
if (dump_file)
fprintf (dump_file, "Too many temporary registers allocated\n");
return NULL_RTX;
}
reg = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, GPR_REGS, SImode, TRUE, TRUE);
if (! reg)
{
if (dump_file)
fputs ("Could not find a scratch register\n", dump_file);
return NULL_RTX;
}
frv_ifcvt.cur_scratch_regs++;
frv_ifcvt.scratch_regs[num_alloc] = gen_rtx_SET (VOIDmode, reg, value);
if (dump_file)
{
if (GET_CODE (value) == CONST_INT)
fprintf (dump_file, "Register %s will hold %ld\n",
reg_names[ REGNO (reg)], (long)INTVAL (value));
else if (GET_CODE (value) == REG && REGNO (value) == LR_REGNO)
fprintf (dump_file, "Register %s will hold LR\n",
reg_names[ REGNO (reg)]);
else
fprintf (dump_file, "Register %s will hold a saved value\n",
reg_names[ REGNO (reg)]);
}
return reg;
}
static rtx
frv_ifcvt_rewrite_mem (rtx mem, enum machine_mode mode, rtx insn)
{
rtx addr = XEXP (mem, 0);
if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE))
{
if (GET_CODE (addr) == PLUS)
{
rtx addr_op0 = XEXP (addr, 0);
rtx addr_op1 = XEXP (addr, 1);
if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
{
rtx reg = frv_ifcvt_load_value (addr_op1, insn);
if (!reg)
return NULL_RTX;
addr = gen_rtx_PLUS (Pmode, addr_op0, reg);
}
else
return NULL_RTX;
}
else if (CONSTANT_P (addr))
addr = frv_ifcvt_load_value (addr, insn);
else
return NULL_RTX;
if (addr == NULL_RTX)
return NULL_RTX;
else if (XEXP (mem, 0) != addr)
return change_address (mem, mode, addr);
}
return mem;
}
static rtx
single_set_pattern (rtx pattern)
{
rtx set;
int i;
if (GET_CODE (pattern) == COND_EXEC)
pattern = COND_EXEC_CODE (pattern);
if (GET_CODE (pattern) == SET)
return pattern;
else if (GET_CODE (pattern) == PARALLEL)
{
for (i = 0, set = 0; i < XVECLEN (pattern, 0); i++)
{
rtx sub = XVECEXP (pattern, 0, i);
switch (GET_CODE (sub))
{
case USE:
case CLOBBER:
break;
case SET:
if (set)
return 0;
else
set = sub;
break;
default:
return 0;
}
}
return set;
}
return 0;
}
rtx
frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
rtx pattern,
rtx insn)
{
rtx orig_ce_pattern = pattern;
rtx set;
rtx op0;
rtx op1;
rtx test;
if (GET_CODE (pattern) != COND_EXEC)
abort ();
test = COND_EXEC_TEST (pattern);
if (GET_CODE (test) == AND)
{
rtx cr = frv_ifcvt.cr_reg;
rtx test_reg;
op0 = XEXP (test, 0);
if (! rtx_equal_p (cr, XEXP (op0, 0)))
goto fail;
op1 = XEXP (test, 1);
test_reg = XEXP (op1, 0);
if (GET_CODE (test_reg) != REG)
goto fail;
if (! frv_ifcvt.last_nested_if_cr)
{
rtx and_op;
frv_ifcvt.last_nested_if_cr = test_reg;
if (GET_CODE (op0) == NE)
and_op = gen_andcr (test_reg, cr, test_reg);
else
and_op = gen_andncr (test_reg, cr, test_reg);
frv_ifcvt_add_insn (and_op, insn, TRUE);
}
else if (! rtx_equal_p (test_reg, frv_ifcvt.last_nested_if_cr))
goto fail;
COND_EXEC_TEST (pattern) = test = op1;
}
else
{
frv_ifcvt.last_nested_if_cr = NULL_RTX;
}
set = single_set_pattern (pattern);
if (set)
{
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
enum machine_mode mode = GET_MODE (dest);
if (mode == SImode && ARITHMETIC_P (src))
{
op0 = XEXP (src, 0);
op1 = XEXP (src, 1);
if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
{
op1 = frv_ifcvt_load_value (op1, insn);
if (op1)
COND_EXEC_CODE (pattern)
= gen_rtx_SET (VOIDmode, dest, gen_rtx_fmt_ee (GET_CODE (src),
GET_MODE (src),
op0, op1));
else
goto fail;
}
}
else if (mode == DImode && GET_CODE (src) == MULT)
{
op0 = XEXP (src, 0);
op1 = XEXP (src, 1);
if (GET_CODE (op0) == SIGN_EXTEND && GET_CODE (op1) == CONST_INT)
{
op1 = frv_ifcvt_load_value (op1, insn);
if (op1)
{
op1 = gen_rtx_SIGN_EXTEND (DImode, op1);
COND_EXEC_CODE (pattern)
= gen_rtx_SET (VOIDmode, dest,
gen_rtx_MULT (DImode, op0, op1));
}
else
goto fail;
}
frv_ifcvt_add_insn (gen_rtx_USE (VOIDmode, dest), insn, FALSE);
}
else if (frv_ifcvt.scratch_insns_bitmap
&& bitmap_bit_p (frv_ifcvt.scratch_insns_bitmap,
INSN_UID (insn))
&& REG_P (SET_DEST (set))
&& ce_info->join_bb
&& ! (REGNO_REG_SET_P
(ce_info->join_bb->global_live_at_start,
REGNO (SET_DEST (set))))
&& (! ce_info->else_bb
|| BLOCK_FOR_INSN (insn) == ce_info->else_bb
|| ! (REGNO_REG_SET_P
(ce_info->else_bb->global_live_at_start,
REGNO (SET_DEST (set))))))
pattern = set;
else if (mode == QImode || mode == HImode || mode == SImode
|| mode == SFmode)
{
int changed_p = FALSE;
if (CONSTANT_P (src) && integer_register_operand (dest, mode))
{
src = frv_ifcvt_load_value (src, insn);
if (!src)
goto fail;
changed_p = TRUE;
}
if (GET_CODE (dest) == MEM)
{
rtx new_mem = frv_ifcvt_rewrite_mem (dest, mode, insn);
if (!new_mem)
goto fail;
else if (new_mem != dest)
{
changed_p = TRUE;
dest = new_mem;
}
}
if (GET_CODE (src) == MEM)
{
rtx new_mem = frv_ifcvt_rewrite_mem (src, mode, insn);
if (!new_mem)
goto fail;
else if (new_mem != src)
{
changed_p = TRUE;
src = new_mem;
}
}
if (changed_p)
COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
}
else if (mode == CC_CCRmode && COMPARISON_P (src))
{
int regno = REGNO (XEXP (src, 0));
rtx if_else;
if (ce_info->pass > 1
&& regno != (int)REGNO (frv_ifcvt.nested_cc_reg)
&& TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, regno))
{
src = gen_rtx_fmt_ee (GET_CODE (src),
CC_CCRmode,
frv_ifcvt.nested_cc_reg,
XEXP (src, 1));
}
if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, test, src, const0_rtx);
pattern = gen_rtx_SET (VOIDmode, dest, if_else);
}
else if (ce_info->pass > 1
&& GET_CODE (dest) == REG
&& CC_P (REGNO (dest))
&& REGNO (dest) != REGNO (frv_ifcvt.nested_cc_reg)
&& TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite,
REGNO (dest))
&& GET_CODE (src) == COMPARE)
{
PUT_MODE (frv_ifcvt.nested_cc_reg, GET_MODE (dest));
COND_EXEC_CODE (pattern)
= gen_rtx_SET (VOIDmode, frv_ifcvt.nested_cc_reg, copy_rtx (src));
}
}
if (TARGET_DEBUG_COND_EXEC)
{
rtx orig_pattern = PATTERN (insn);
PATTERN (insn) = pattern;
fprintf (stderr,
"\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn after modification:\n",
ce_info->pass);
debug_rtx (insn);
PATTERN (insn) = orig_pattern;
}
return pattern;
fail:
if (TARGET_DEBUG_COND_EXEC)
{
rtx orig_pattern = PATTERN (insn);
PATTERN (insn) = orig_ce_pattern;
fprintf (stderr,
"\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn could not be modified:\n",
ce_info->pass);
debug_rtx (insn);
PATTERN (insn) = orig_pattern;
}
return NULL_RTX;
}
void
frv_ifcvt_modify_final (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
{
rtx existing_insn;
rtx check_insn;
rtx p = frv_ifcvt.added_insns_list;
int i;
if (! p)
abort ();
do
{
rtx check_and_insert_insns = XEXP (p, 0);
rtx old_p = p;
check_insn = XEXP (check_and_insert_insns, 0);
existing_insn = XEXP (check_and_insert_insns, 1);
p = XEXP (p, 1);
if (check_and_insert_insns->jump)
{
emit_insn_before (check_insn, existing_insn);
check_and_insert_insns->jump = 0;
}
else
emit_insn_after (check_insn, existing_insn);
free_EXPR_LIST_node (check_and_insert_insns);
free_EXPR_LIST_node (old_p);
}
while (p != NULL_RTX);
for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
{
rtx insn = emit_insn_before (frv_ifcvt.scratch_regs[i], existing_insn);
if (! frv_ifcvt.scratch_insns_bitmap)
frv_ifcvt.scratch_insns_bitmap = BITMAP_ALLOC (NULL);
bitmap_set_bit (frv_ifcvt.scratch_insns_bitmap, INSN_UID (insn));
frv_ifcvt.scratch_regs[i] = NULL_RTX;
}
frv_ifcvt.added_insns_list = NULL_RTX;
frv_ifcvt.cur_scratch_regs = 0;
}
void
frv_ifcvt_modify_cancel (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
{
int i;
rtx p = frv_ifcvt.added_insns_list;
while (p != NULL_RTX)
{
rtx check_and_jump = XEXP (p, 0);
rtx old_p = p;
p = XEXP (p, 1);
free_EXPR_LIST_node (check_and_jump);
free_EXPR_LIST_node (old_p);
}
for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
frv_ifcvt.scratch_regs[i] = NULL_RTX;
frv_ifcvt.added_insns_list = NULL_RTX;
frv_ifcvt.cur_scratch_regs = 0;
return;
}
int
frv_trampoline_size (void)
{
if (TARGET_FDPIC)
return 8 + 6 * 4;
return 5 * 4 ;
}
void
frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
{
rtx sc_reg = force_reg (Pmode, static_chain);
emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
FALSE, VOIDmode, 4,
addr, Pmode,
GEN_INT (frv_trampoline_size ()), SImode,
fnaddr, Pmode,
sc_reg, Pmode);
}
enum reg_class
frv_secondary_reload_class (enum reg_class class,
enum machine_mode mode ATTRIBUTE_UNUSED,
rtx x,
int in_p ATTRIBUTE_UNUSED)
{
enum reg_class ret;
switch (class)
{
default:
ret = NO_REGS;
break;
case QUAD_REGS:
case EVEN_REGS:
case GPR_REGS:
ret = NO_REGS;
if (x && GET_CODE (x) == REG)
{
int regno = REGNO (x);
if (ACC_P (regno) || ACCG_P (regno))
ret = FPR_REGS;
}
break;
case QUAD_FPR_REGS:
case FEVEN_REGS:
case FPR_REGS:
if (x && CONSTANT_P (x) && !ZERO_P (x))
ret = GPR_REGS;
else
ret = NO_REGS;
break;
case ICC_REGS:
case FCC_REGS:
case CC_REGS:
case ICR_REGS:
case FCR_REGS:
case CR_REGS:
case LCR_REG:
case LR_REG:
ret = GPR_REGS;
break;
case ACC_REGS:
case EVEN_ACC_REGS:
case QUAD_ACC_REGS:
case ACCG_REGS:
ret = FPR_REGS;
break;
}
return ret;
}
int
frv_class_likely_spilled_p (enum reg_class class)
{
switch (class)
{
default:
break;
case GR8_REGS:
case GR9_REGS:
case GR89_REGS:
case FDPIC_FPTR_REGS:
case FDPIC_REGS:
case ICC_REGS:
case FCC_REGS:
case CC_REGS:
case ICR_REGS:
case FCR_REGS:
case CR_REGS:
case LCR_REG:
case LR_REG:
case SPR_REGS:
case QUAD_ACC_REGS:
case EVEN_ACC_REGS:
case ACC_REGS:
case ACCG_REGS:
return TRUE;
}
return FALSE;
}
int
frv_adjust_field_align (tree field, int computed)
{
if (DECL_BIT_FIELD (field)
&& !DECL_ARTIFICIAL (field))
{
tree parent = DECL_CONTEXT (field);
tree prev = NULL_TREE;
tree cur;
for (cur = TYPE_FIELDS (parent); cur && cur != field; cur = TREE_CHAIN (cur))
{
if (TREE_CODE (cur) != FIELD_DECL)
continue;
prev = cur;
}
if (!cur)
abort ();
if (prev
&& ! DECL_PACKED (field)
&& ! integer_zerop (DECL_SIZE (field))
&& DECL_BIT_FIELD_TYPE (field) != DECL_BIT_FIELD_TYPE (prev))
{
int prev_align = TYPE_ALIGN (TREE_TYPE (prev));
int cur_align = TYPE_ALIGN (TREE_TYPE (field));
computed = (prev_align > cur_align) ? prev_align : cur_align;
}
}
return computed;
}
int
frv_hard_regno_mode_ok (int regno, enum machine_mode mode)
{
int base;
int mask;
switch (mode)
{
case CCmode:
case CC_UNSmode:
case CC_NZmode:
return ICC_P (regno) || GPR_P (regno);
case CC_CCRmode:
return CR_P (regno) || GPR_P (regno);
case CC_FPmode:
return FCC_P (regno) || GPR_P (regno);
default:
break;
}
if (INTEGRAL_MODE_P (mode) || FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode))
{
if (ACCG_P (regno))
{
base = ACCG_FIRST;
mask = GET_MODE_SIZE (mode) - 1;
}
else
{
if (GPR_P (regno) || regno == AP_FIRST)
base = GPR_FIRST;
else if (FPR_P (regno))
base = FPR_FIRST;
else if (ACC_P (regno))
base = ACC_FIRST;
else if (SPR_P (regno))
return mode == SImode;
else
return 0;
if (GET_MODE_SIZE (mode) < 4)
return 1;
mask = (GET_MODE_SIZE (mode) / 4) - 1;
}
return (((regno - base) & mask) == 0);
}
return 0;
}
int
frv_hard_regno_nregs (int regno, enum machine_mode mode)
{
if (ACCG_P (regno))
return GET_MODE_SIZE (mode);
else
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}
int
frv_class_max_nregs (enum reg_class class, enum machine_mode mode)
{
if (class == ACCG_REGS)
return GET_MODE_SIZE (mode);
else
return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}
int
frv_legitimate_constant_p (rtx x)
{
enum machine_mode mode = GET_MODE (x);
if (TARGET_FDPIC)
return LEGITIMATE_PIC_OPERAND_P (x);
if (GET_CODE (x) != CONST_DOUBLE)
return TRUE;
if (mode == VOIDmode || mode == DImode)
return TRUE;
if (x == CONST0_RTX (mode))
return TRUE;
if (!TARGET_HAS_FPRS)
return TRUE;
if (mode == DFmode && !TARGET_DOUBLE)
return TRUE;
return FALSE;
}
enum machine_mode
frv_select_cc_mode (enum rtx_code code, rtx x, rtx y)
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return CC_FPmode;
switch (code)
{
case EQ:
case NE:
case LT:
case GE:
return y == const0_rtx ? CC_NZmode : CCmode;
case GTU:
case GEU:
case LTU:
case LEU:
return y == const0_rtx ? CC_NZmode : CC_UNSmode;
default:
return CCmode;
}
}
#define HIGH_COST 40
#define MEDIUM_COST 3
#define LOW_COST 1
int
frv_register_move_cost (enum reg_class from, enum reg_class to)
{
switch (from)
{
default:
break;
case QUAD_REGS:
case EVEN_REGS:
case GPR_REGS:
switch (to)
{
default:
break;
case QUAD_REGS:
case EVEN_REGS:
case GPR_REGS:
return LOW_COST;
case FEVEN_REGS:
case FPR_REGS:
return LOW_COST;
case LCR_REG:
case LR_REG:
case SPR_REGS:
return LOW_COST;
}
case FEVEN_REGS:
case FPR_REGS:
switch (to)
{
default:
break;
case QUAD_REGS:
case EVEN_REGS:
case GPR_REGS:
case ACC_REGS:
case EVEN_ACC_REGS:
case QUAD_ACC_REGS:
case ACCG_REGS:
return MEDIUM_COST;
case FEVEN_REGS:
case FPR_REGS:
return LOW_COST;
}
case LCR_REG:
case LR_REG:
case SPR_REGS:
switch (to)
{
default:
break;
case QUAD_REGS:
case EVEN_REGS:
case GPR_REGS:
return MEDIUM_COST;
}
case ACC_REGS:
case EVEN_ACC_REGS:
case QUAD_ACC_REGS:
case ACCG_REGS:
switch (to)
{
default:
break;
case FEVEN_REGS:
case FPR_REGS:
return MEDIUM_COST;
}
}
return HIGH_COST;
}
static bool
frv_assemble_integer (rtx value, unsigned int size, int aligned_p)
{
if ((flag_pic || TARGET_FDPIC) && size == UNITS_PER_WORD)
{
if (GET_CODE (value) == CONST
|| GET_CODE (value) == SYMBOL_REF
|| GET_CODE (value) == LABEL_REF)
{
if (TARGET_FDPIC && GET_CODE (value) == SYMBOL_REF
&& SYMBOL_REF_FUNCTION_P (value))
{
fputs ("\t.picptr\tfuncdesc(", asm_out_file);
output_addr_const (asm_out_file, value);
fputs (")\n", asm_out_file);
return true;
}
else if (TARGET_FDPIC && GET_CODE (value) == CONST
&& frv_function_symbol_referenced_p (value))
return false;
if (aligned_p && !TARGET_FDPIC)
{
static int label_num = 0;
char buf[256];
const char *p;
ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", label_num++);
p = (* targetm.strip_name_encoding) (buf);
fprintf (asm_out_file, "%s:\n", p);
fprintf (asm_out_file, "%s\n", FIXUP_SECTION_ASM_OP);
fprintf (asm_out_file, "\t.picptr\t%s\n", p);
fprintf (asm_out_file, "\t.previous\n");
}
assemble_integer_with_op ("\t.picptr\t", value);
return true;
}
if (!aligned_p)
{
assemble_integer_with_op ("\t.4byte\t", value);
return true;
}
}
return default_assemble_integer (value, size, aligned_p);
}
static struct machine_function *
frv_init_machine_status (void)
{
return ggc_alloc_cleared (sizeof (struct machine_function));
}
int
frv_issue_rate (void)
{
if (!TARGET_PACK)
return 1;
switch (frv_cpu_type)
{
default:
case FRV_CPU_FR300:
case FRV_CPU_SIMPLE:
return 1;
case FRV_CPU_FR400:
case FRV_CPU_FR405:
case FRV_CPU_FR450:
return 2;
case FRV_CPU_GENERIC:
case FRV_CPU_FR500:
case FRV_CPU_TOMCAT:
return 4;
case FRV_CPU_FR550:
return 8;
}
}
static int
frv_acc_group_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
{
if (REG_P (*x))
{
if (ACC_P (REGNO (*x)))
return (REGNO (*x) - ACC_FIRST) & 4 ? ACC_GROUP_ODD : ACC_GROUP_EVEN;
if (ACCG_P (REGNO (*x)))
return (REGNO (*x) - ACCG_FIRST) & 4 ? ACC_GROUP_ODD : ACC_GROUP_EVEN;
}
return 0;
}
int
frv_acc_group (rtx insn)
{
if (frv_cpu_type != FRV_CPU_FR550)
return ACC_GROUP_NONE;
return for_each_rtx (&PATTERN (insn), frv_acc_group_1, 0);
}
static unsigned int
frv_insn_unit (rtx insn)
{
enum attr_type type;
type = get_attr_type (insn);
if (frv_type_to_unit[type] == ARRAY_SIZE (frv_unit_codes))
{
state_t state;
unsigned int unit;
state = alloca (state_size ());
state_reset (state);
state_transition (state, insn);
for (unit = 0; unit < ARRAY_SIZE (frv_unit_codes); unit++)
if (cpu_unit_reservation_p (state, frv_unit_codes[unit]))
break;
if (unit == ARRAY_SIZE (frv_unit_codes))
abort ();
frv_type_to_unit[type] = unit;
}
return frv_type_to_unit[type];
}
static bool
frv_issues_to_branch_unit_p (rtx insn)
{
return frv_unit_groups[frv_insn_unit (insn)] == GROUP_B;
}
static struct {
state_t dfa_state;
regstate_t regstate[FIRST_PSEUDO_REGISTER];
struct {
rtx mem;
regstate_t cond;
} mems[2];
unsigned int num_mems;
unsigned int issue_rate;
struct frv_packet_group {
unsigned int num_insns;
rtx insns[ARRAY_SIZE (frv_unit_codes)];
rtx sorted[ARRAY_SIZE (frv_unit_codes)];
rtx nop;
} groups[NUM_GROUPS];
rtx insns[ARRAY_SIZE (frv_unit_codes)];
unsigned int num_insns;
} frv_packet;
static int
frv_cond_flags (rtx cond)
{
if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
&& GET_CODE (XEXP (cond, 0)) == REG
&& CR_P (REGNO (XEXP (cond, 0)))
&& XEXP (cond, 1) == const0_rtx)
return ((REGNO (XEXP (cond, 0)) - CR_FIRST)
| (GET_CODE (cond) == NE
? REGSTATE_IF_TRUE
: REGSTATE_IF_FALSE));
abort ();
}
static bool
frv_regstate_conflict_p (regstate_t cond1, regstate_t cond2)
{
if ((cond1 & REGSTATE_IF_EITHER) == 0
|| (cond2 & REGSTATE_IF_EITHER) == 0)
return true;
if ((cond1 & REGSTATE_CC_MASK) != (cond2 & REGSTATE_CC_MASK))
return true;
if ((cond1 & cond2 & REGSTATE_IF_EITHER) != 0)
return true;
return false;
}
static int
frv_registers_conflict_p_1 (rtx *x, void *data)
{
unsigned int regno, i;
regstate_t cond;
cond = *(regstate_t *) data;
if (GET_CODE (*x) == REG)
FOR_EACH_REGNO (regno, *x)
if ((frv_packet.regstate[regno] & REGSTATE_MODIFIED) != 0)
if (frv_regstate_conflict_p (frv_packet.regstate[regno], cond))
return 1;
if (GET_CODE (*x) == MEM)
{
if (frv_packet.num_mems > ARRAY_SIZE (frv_packet.mems))
return 1;
for (i = 0; i < frv_packet.num_mems; i++)
if (frv_regstate_conflict_p (frv_packet.mems[i].cond, cond))
{
if (true_dependence (frv_packet.mems[i].mem, VOIDmode,
*x, rtx_varies_p))
return 1;
if (output_dependence (frv_packet.mems[i].mem, *x))
return 1;
}
}
if (GET_CODE (*x) == SET && GET_CODE (SET_SRC (*x)) == CALL)
{
if (for_each_rtx (&SET_SRC (*x), frv_registers_conflict_p_1, data))
return 1;
return -1;
}
return 0;
}
static bool
frv_registers_conflict_p (rtx x)
{
regstate_t flags;
flags = 0;
if (GET_CODE (x) == COND_EXEC)
{
if (for_each_rtx (&XEXP (x, 0), frv_registers_conflict_p_1, &flags))
return true;
flags |= frv_cond_flags (XEXP (x, 0));
x = XEXP (x, 1);
}
return for_each_rtx (&x, frv_registers_conflict_p_1, &flags);
}
static void
frv_registers_update_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
{
unsigned int regno;
if (GET_CODE (x) == REG)
FOR_EACH_REGNO (regno, x)
frv_packet.regstate[regno] |= *(regstate_t *) data;
if (GET_CODE (x) == MEM)
{
if (frv_packet.num_mems < ARRAY_SIZE (frv_packet.mems))
{
frv_packet.mems[frv_packet.num_mems].mem = x;
frv_packet.mems[frv_packet.num_mems].cond = *(regstate_t *) data;
}
frv_packet.num_mems++;
}
}
static void
frv_registers_update (rtx x)
{
regstate_t flags;
flags = REGSTATE_MODIFIED;
if (GET_CODE (x) == COND_EXEC)
{
flags |= frv_cond_flags (XEXP (x, 0));
x = XEXP (x, 1);
}
note_stores (x, frv_registers_update_1, &flags);
}
static void
frv_start_packet (void)
{
enum frv_insn_group group;
memset (frv_packet.regstate, 0, sizeof (frv_packet.regstate));
frv_packet.num_mems = 0;
frv_packet.num_insns = 0;
for (group = 0; group < NUM_GROUPS; group++)
frv_packet.groups[group].num_insns = 0;
}
static void
frv_start_packet_block (void)
{
state_reset (frv_packet.dfa_state);
frv_start_packet ();
}
static void
frv_finish_packet (void (*handle_packet) (void))
{
if (frv_packet.num_insns > 0)
{
handle_packet ();
state_transition (frv_packet.dfa_state, 0);
frv_start_packet ();
}
}
static bool
frv_pack_insn_p (rtx insn)
{
if (frv_packet.num_insns == frv_packet.issue_rate)
return false;
if (frv_packet.num_insns > 0
&& GET_CODE (insn) == INSN
&& GET_MODE (insn) == TImode
&& GET_CODE (PATTERN (insn)) != COND_EXEC)
return false;
if (get_attr_type (insn) != TYPE_SETLO)
if (frv_registers_conflict_p (PATTERN (insn)))
return false;
return state_transition (frv_packet.dfa_state, insn) < 0;
}
static void
frv_add_insn_to_packet (rtx insn)
{
struct frv_packet_group *packet_group;
packet_group = &frv_packet.groups[frv_unit_groups[frv_insn_unit (insn)]];
packet_group->insns[packet_group->num_insns++] = insn;
frv_packet.insns[frv_packet.num_insns++] = insn;
frv_registers_update (PATTERN (insn));
}
static void
frv_insert_nop_in_packet (rtx insn)
{
struct frv_packet_group *packet_group;
rtx last;
packet_group = &frv_packet.groups[frv_unit_groups[frv_insn_unit (insn)]];
last = frv_packet.insns[frv_packet.num_insns - 1];
if (GET_CODE (last) != INSN)
{
insn = emit_insn_before (PATTERN (insn), last);
frv_packet.insns[frv_packet.num_insns - 1] = insn;
frv_packet.insns[frv_packet.num_insns++] = last;
}
else
{
insn = emit_insn_after (PATTERN (insn), last);
frv_packet.insns[frv_packet.num_insns++] = insn;
}
packet_group->insns[packet_group->num_insns++] = insn;
}
static bool
frv_for_each_packet (void (*handle_packet) (void))
{
rtx insn, next_insn;
frv_packet.issue_rate = frv_issue_rate ();
if (!optimize
|| !flag_schedule_insns_after_reload
|| TARGET_NO_VLIW_BRANCH
|| frv_packet.issue_rate == 1)
return false;
dfa_start ();
frv_packet.dfa_state = alloca (state_size ());
frv_start_packet_block ();
for (insn = get_insns (); insn != 0; insn = next_insn)
{
enum rtx_code code;
bool eh_insn_p;
code = GET_CODE (insn);
next_insn = NEXT_INSN (insn);
if (code == CODE_LABEL)
{
frv_finish_packet (handle_packet);
frv_start_packet_block ();
}
if (INSN_P (insn))
switch (GET_CODE (PATTERN (insn)))
{
case USE:
case CLOBBER:
case ADDR_VEC:
case ADDR_DIFF_VEC:
break;
default:
if (GET_CODE (insn) == CALL_INSN && frv_cpu_type == FRV_CPU_TOMCAT)
frv_finish_packet (handle_packet);
eh_insn_p = (find_reg_note (insn, REG_EH_REGION, NULL) != NULL);
if (eh_insn_p && !frv_issues_to_branch_unit_p (insn))
frv_finish_packet (handle_packet);
if (!frv_pack_insn_p (insn))
{
frv_finish_packet (handle_packet);
while (!frv_pack_insn_p (insn))
state_transition (frv_packet.dfa_state, 0);
}
frv_add_insn_to_packet (insn);
if (code == CALL_INSN || code == JUMP_INSN || eh_insn_p)
frv_finish_packet (handle_packet);
break;
}
}
frv_finish_packet (handle_packet);
dfa_finish ();
return true;
}
static bool
frv_sort_insn_group_1 (enum frv_insn_group group,
unsigned int lower_slot, unsigned int upper_slot,
unsigned int issued, unsigned int num_insns,
state_t state)
{
struct frv_packet_group *packet_group;
unsigned int i;
state_t test_state;
size_t dfa_size;
rtx insn;
if (lower_slot == upper_slot)
return true;
packet_group = &frv_packet.groups[group];
dfa_size = state_size ();
test_state = alloca (dfa_size);
for (i = num_insns - 1; i + 1 != 0; i--)
if (~issued & (1 << i))
{
insn = packet_group->sorted[i];
memcpy (test_state, state, dfa_size);
if (state_transition (test_state, insn) < 0
&& cpu_unit_reservation_p (test_state,
NTH_UNIT (group, upper_slot - 1))
&& frv_sort_insn_group_1 (group, lower_slot, upper_slot - 1,
issued | (1 << i), num_insns,
test_state))
{
packet_group->sorted[upper_slot - 1] = insn;
return true;
}
}
return false;
}
static int
frv_compare_insns (const void *first, const void *second)
{
const rtx *insn1 = first, *insn2 = second;
return frv_insn_unit (*insn1) - frv_insn_unit (*insn2);
}
static void
frv_sort_insn_group (enum frv_insn_group group)
{
struct frv_packet_group *packet_group;
unsigned int first, i, nop, max_unit, num_slots;
state_t state, test_state;
size_t dfa_size;
packet_group = &frv_packet.groups[group];
packet_group->nop = 0;
if (packet_group->num_insns == 0)
return;
memcpy (packet_group->sorted, packet_group->insns,
sizeof (rtx) * packet_group->num_insns);
if (packet_group->num_insns > 1)
qsort (packet_group->sorted, packet_group->num_insns,
sizeof (rtx), frv_compare_insns);
if (group == GROUP_B || group == GROUP_C)
return;
dfa_size = state_size ();
state = alloca (dfa_size);
test_state = alloca (dfa_size);
state_reset (test_state);
for (first = 0; first < packet_group->num_insns; first++)
{
memcpy (state, test_state, dfa_size);
if (state_transition (test_state, packet_group->sorted[first]) >= 0
|| !cpu_unit_reservation_p (test_state, NTH_UNIT (group, first)))
break;
}
if (first == packet_group->num_insns)
return;
for (nop = 0; nop < frv_num_nops; nop++)
{
max_unit = frv_insn_unit (frv_nops[nop]);
if (frv_unit_groups[max_unit] == group)
{
packet_group->nop = frv_nops[nop];
num_slots = UNIT_NUMBER (max_unit) + 1;
for (i = packet_group->num_insns; i < num_slots; i++)
packet_group->sorted[i] = frv_nops[nop];
if (frv_sort_insn_group_1 (group, first, num_slots,
(1 << first) - 1, num_slots, state))
return;
}
}
abort ();
}
static void
frv_reorder_packet (void)
{
unsigned int cursor[NUM_GROUPS];
rtx insns[ARRAY_SIZE (frv_unit_groups)];
unsigned int unit, to, from;
enum frv_insn_group group;
struct frv_packet_group *packet_group;
for (group = 0; group < NUM_GROUPS; group++)
{
cursor[group] = 0;
frv_sort_insn_group (group);
}
to = 0;
for (unit = 0; unit < ARRAY_SIZE (frv_unit_groups); unit++)
{
group = frv_unit_groups[unit];
packet_group = &frv_packet.groups[group];
if (cursor[group] < packet_group->num_insns)
{
if (packet_group->sorted[cursor[group]] == packet_group->nop)
abort ();
insns[to++] = packet_group->sorted[cursor[group]++];
}
}
if (to != frv_packet.num_insns)
abort ();
CLEAR_PACKING_FLAG (insns[to - 1]);
for (from = 0; from < to - 1; from++)
{
remove_insn (insns[from]);
add_insn_before (insns[from], insns[to - 1]);
SET_PACKING_FLAG (insns[from]);
}
}
static void
frv_pack_insns (void)
{
if (frv_for_each_packet (frv_reorder_packet))
frv_insn_packing_flag = 0;
else
frv_insn_packing_flag = -1;
}
static void
frv_fill_unused_units (enum frv_insn_group group)
{
unsigned int non_nops, nops, i;
struct frv_packet_group *packet_group;
packet_group = &frv_packet.groups[group];
frv_sort_insn_group (group);
i = nops = 0;
for (non_nops = 0; non_nops < packet_group->num_insns; non_nops++)
while (packet_group->sorted[i++] == packet_group->nop)
nops++;
while (nops-- > 0)
frv_insert_nop_in_packet (packet_group->nop);
}
static unsigned int frv_packet_address;
static void
frv_align_label (void)
{
unsigned int alignment, target, nop;
rtx x, last, barrier, label;
last = frv_packet.insns[frv_packet.num_insns - 1];
label = barrier = 0;
alignment = 4;
for (x = NEXT_INSN (last); x != 0 && !INSN_P (x); x = NEXT_INSN (x))
{
if (LABEL_P (x))
{
unsigned int subalign = 1 << label_to_alignment (x);
alignment = MAX (alignment, subalign);
label = x;
}
if (BARRIER_P (x))
barrier = x;
}
if (TARGET_ALIGN_LABELS
&& label != 0
&& barrier == 0
&& frv_packet.num_insns < frv_packet.issue_rate)
alignment = MAX (alignment, 8);
frv_packet_address += frv_packet.num_insns * 4;
target = (frv_packet_address + alignment - 1) & -alignment;
if (barrier == 0)
{
for (nop = 0; nop < frv_num_nops; nop++)
while (frv_packet_address < target && frv_pack_insn_p (frv_nops[nop]))
{
frv_insert_nop_in_packet (frv_nops[nop]);
frv_packet_address += 4;
}
last = frv_packet.insns[frv_packet.num_insns - 1];
nop = 0;
while (frv_packet_address < target)
{
last = emit_insn_after (PATTERN (frv_nops[nop]), last);
frv_packet_address += 4;
if (frv_num_nops > 1)
nop ^= 1;
}
}
frv_packet_address = target;
}
static void
frv_reorg_packet (void)
{
frv_fill_unused_units (GROUP_I);
frv_fill_unused_units (GROUP_FM);
frv_align_label ();
}
static void
frv_register_nop (rtx nop)
{
nop = make_insn_raw (nop);
NEXT_INSN (nop) = 0;
PREV_INSN (nop) = 0;
frv_nops[frv_num_nops++] = nop;
}
static void
frv_reorg (void)
{
frv_num_nops = 0;
frv_register_nop (gen_nop ());
if (TARGET_MEDIA)
frv_register_nop (gen_mnop ());
if (TARGET_HARD_FLOAT)
frv_register_nop (gen_fnop ());
shorten_branches (get_insns ());
frv_packet_address = 0;
frv_for_each_packet (frv_reorg_packet);
}
#define def_builtin(name, type, code) \
lang_hooks.builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
struct builtin_description
{
enum insn_code icode;
const char *name;
enum frv_builtins code;
enum rtx_code comparison;
unsigned int flag;
};
static struct builtin_description bdesc_set[] =
{
{ CODE_FOR_mhdsets, "__MHDSETS", FRV_BUILTIN_MHDSETS, 0, 0 }
};
static struct builtin_description bdesc_1arg[] =
{
{ CODE_FOR_mnot, "__MNOT", FRV_BUILTIN_MNOT, 0, 0 },
{ CODE_FOR_munpackh, "__MUNPACKH", FRV_BUILTIN_MUNPACKH, 0, 0 },
{ CODE_FOR_mbtoh, "__MBTOH", FRV_BUILTIN_MBTOH, 0, 0 },
{ CODE_FOR_mhtob, "__MHTOB", FRV_BUILTIN_MHTOB, 0, 0 },
{ CODE_FOR_mabshs, "__MABSHS", FRV_BUILTIN_MABSHS, 0, 0 },
{ CODE_FOR_scutss, "__SCUTSS", FRV_BUILTIN_SCUTSS, 0, 0 }
};
static struct builtin_description bdesc_2arg[] =
{
{ CODE_FOR_mand, "__MAND", FRV_BUILTIN_MAND, 0, 0 },
{ CODE_FOR_mor, "__MOR", FRV_BUILTIN_MOR, 0, 0 },
{ CODE_FOR_mxor, "__MXOR", FRV_BUILTIN_MXOR, 0, 0 },
{ CODE_FOR_maveh, "__MAVEH", FRV_BUILTIN_MAVEH, 0, 0 },
{ CODE_FOR_msaths, "__MSATHS", FRV_BUILTIN_MSATHS, 0, 0 },
{ CODE_FOR_msathu, "__MSATHU", FRV_BUILTIN_MSATHU, 0, 0 },
{ CODE_FOR_maddhss, "__MADDHSS", FRV_BUILTIN_MADDHSS, 0, 0 },
{ CODE_FOR_maddhus, "__MADDHUS", FRV_BUILTIN_MADDHUS, 0, 0 },
{ CODE_FOR_msubhss, "__MSUBHSS", FRV_BUILTIN_MSUBHSS, 0, 0 },
{ CODE_FOR_msubhus, "__MSUBHUS", FRV_BUILTIN_MSUBHUS, 0, 0 },
{ CODE_FOR_mqaddhss, "__MQADDHSS", FRV_BUILTIN_MQADDHSS, 0, 0 },
{ CODE_FOR_mqaddhus, "__MQADDHUS", FRV_BUILTIN_MQADDHUS, 0, 0 },
{ CODE_FOR_mqsubhss, "__MQSUBHSS", FRV_BUILTIN_MQSUBHSS, 0, 0 },
{ CODE_FOR_mqsubhus, "__MQSUBHUS", FRV_BUILTIN_MQSUBHUS, 0, 0 },
{ CODE_FOR_mpackh, "__MPACKH", FRV_BUILTIN_MPACKH, 0, 0 },
{ CODE_FOR_mcop1, "__Mcop1", FRV_BUILTIN_MCOP1, 0, 0 },
{ CODE_FOR_mcop2, "__Mcop2", FRV_BUILTIN_MCOP2, 0, 0 },
{ CODE_FOR_mwcut, "__MWCUT", FRV_BUILTIN_MWCUT, 0, 0 },
{ CODE_FOR_mqsaths, "__MQSATHS", FRV_BUILTIN_MQSATHS, 0, 0 },
{ CODE_FOR_mqlclrhs, "__MQLCLRHS", FRV_BUILTIN_MQLCLRHS, 0, 0 },
{ CODE_FOR_mqlmths, "__MQLMTHS", FRV_BUILTIN_MQLMTHS, 0, 0 },
{ CODE_FOR_smul, "__SMUL", FRV_BUILTIN_SMUL, 0, 0 },
{ CODE_FOR_umul, "__UMUL", FRV_BUILTIN_UMUL, 0, 0 },
{ CODE_FOR_addss, "__ADDSS", FRV_BUILTIN_ADDSS, 0, 0 },
{ CODE_FOR_subss, "__SUBSS", FRV_BUILTIN_SUBSS, 0, 0 },
{ CODE_FOR_slass, "__SLASS", FRV_BUILTIN_SLASS, 0, 0 },
{ CODE_FOR_scan, "__SCAN", FRV_BUILTIN_SCAN, 0, 0 }
};
static struct builtin_description bdesc_int_void2arg[] =
{
{ CODE_FOR_smass, "__SMASS", FRV_BUILTIN_SMASS, 0, 0 },
{ CODE_FOR_smsss, "__SMSSS", FRV_BUILTIN_SMSSS, 0, 0 },
{ CODE_FOR_smu, "__SMU", FRV_BUILTIN_SMU, 0, 0 }
};
static struct builtin_description bdesc_prefetches[] =
{
{ CODE_FOR_frv_prefetch0, "__data_prefetch0", FRV_BUILTIN_PREFETCH0, 0, 0 },
{ CODE_FOR_frv_prefetch, "__data_prefetch", FRV_BUILTIN_PREFETCH, 0, 0 }
};
static struct builtin_description bdesc_cut[] =
{
{ CODE_FOR_mcut, "__MCUT", FRV_BUILTIN_MCUT, 0, 0 },
{ CODE_FOR_mcutss, "__MCUTSS", FRV_BUILTIN_MCUTSS, 0, 0 },
{ CODE_FOR_mdcutssi, "__MDCUTSSI", FRV_BUILTIN_MDCUTSSI, 0, 0 }
};
static struct builtin_description bdesc_2argimm[] =
{
{ CODE_FOR_mrotli, "__MROTLI", FRV_BUILTIN_MROTLI, 0, 0 },
{ CODE_FOR_mrotri, "__MROTRI", FRV_BUILTIN_MROTRI, 0, 0 },
{ CODE_FOR_msllhi, "__MSLLHI", FRV_BUILTIN_MSLLHI, 0, 0 },
{ CODE_FOR_msrlhi, "__MSRLHI", FRV_BUILTIN_MSRLHI, 0, 0 },
{ CODE_FOR_msrahi, "__MSRAHI", FRV_BUILTIN_MSRAHI, 0, 0 },
{ CODE_FOR_mexpdhw, "__MEXPDHW", FRV_BUILTIN_MEXPDHW, 0, 0 },
{ CODE_FOR_mexpdhd, "__MEXPDHD", FRV_BUILTIN_MEXPDHD, 0, 0 },
{ CODE_FOR_mdrotli, "__MDROTLI", FRV_BUILTIN_MDROTLI, 0, 0 },
{ CODE_FOR_mcplhi, "__MCPLHI", FRV_BUILTIN_MCPLHI, 0, 0 },
{ CODE_FOR_mcpli, "__MCPLI", FRV_BUILTIN_MCPLI, 0, 0 },
{ CODE_FOR_mhsetlos, "__MHSETLOS", FRV_BUILTIN_MHSETLOS, 0, 0 },
{ CODE_FOR_mhsetloh, "__MHSETLOH", FRV_BUILTIN_MHSETLOH, 0, 0 },
{ CODE_FOR_mhsethis, "__MHSETHIS", FRV_BUILTIN_MHSETHIS, 0, 0 },
{ CODE_FOR_mhsethih, "__MHSETHIH", FRV_BUILTIN_MHSETHIH, 0, 0 },
{ CODE_FOR_mhdseth, "__MHDSETH", FRV_BUILTIN_MHDSETH, 0, 0 },
{ CODE_FOR_mqsllhi, "__MQSLLHI", FRV_BUILTIN_MQSLLHI, 0, 0 },
{ CODE_FOR_mqsrahi, "__MQSRAHI", FRV_BUILTIN_MQSRAHI, 0, 0 }
};
static struct builtin_description bdesc_void2arg[] =
{
{ CODE_FOR_mdunpackh, "__MDUNPACKH", FRV_BUILTIN_MDUNPACKH, 0, 0 },
{ CODE_FOR_mbtohe, "__MBTOHE", FRV_BUILTIN_MBTOHE, 0, 0 },
};
static struct builtin_description bdesc_void3arg[] =
{
{ CODE_FOR_mcpxrs, "__MCPXRS", FRV_BUILTIN_MCPXRS, 0, 0 },
{ CODE_FOR_mcpxru, "__MCPXRU", FRV_BUILTIN_MCPXRU, 0, 0 },
{ CODE_FOR_mcpxis, "__MCPXIS", FRV_BUILTIN_MCPXIS, 0, 0 },
{ CODE_FOR_mcpxiu, "__MCPXIU", FRV_BUILTIN_MCPXIU, 0, 0 },
{ CODE_FOR_mmulhs, "__MMULHS", FRV_BUILTIN_MMULHS, 0, 0 },
{ CODE_FOR_mmulhu, "__MMULHU", FRV_BUILTIN_MMULHU, 0, 0 },
{ CODE_FOR_mmulxhs, "__MMULXHS", FRV_BUILTIN_MMULXHS, 0, 0 },
{ CODE_FOR_mmulxhu, "__MMULXHU", FRV_BUILTIN_MMULXHU, 0, 0 },
{ CODE_FOR_mmachs, "__MMACHS", FRV_BUILTIN_MMACHS, 0, 0 },
{ CODE_FOR_mmachu, "__MMACHU", FRV_BUILTIN_MMACHU, 0, 0 },
{ CODE_FOR_mmrdhs, "__MMRDHS", FRV_BUILTIN_MMRDHS, 0, 0 },
{ CODE_FOR_mmrdhu, "__MMRDHU", FRV_BUILTIN_MMRDHU, 0, 0 },
{ CODE_FOR_mqcpxrs, "__MQCPXRS", FRV_BUILTIN_MQCPXRS, 0, 0 },
{ CODE_FOR_mqcpxru, "__MQCPXRU", FRV_BUILTIN_MQCPXRU, 0, 0 },
{ CODE_FOR_mqcpxis, "__MQCPXIS", FRV_BUILTIN_MQCPXIS, 0, 0 },
{ CODE_FOR_mqcpxiu, "__MQCPXIU", FRV_BUILTIN_MQCPXIU, 0, 0 },
{ CODE_FOR_mqmulhs, "__MQMULHS", FRV_BUILTIN_MQMULHS, 0, 0 },
{ CODE_FOR_mqmulhu, "__MQMULHU", FRV_BUILTIN_MQMULHU, 0, 0 },
{ CODE_FOR_mqmulxhs, "__MQMULXHS", FRV_BUILTIN_MQMULXHS, 0, 0 },
{ CODE_FOR_mqmulxhu, "__MQMULXHU", FRV_BUILTIN_MQMULXHU, 0, 0 },
{ CODE_FOR_mqmachs, "__MQMACHS", FRV_BUILTIN_MQMACHS, 0, 0 },
{ CODE_FOR_mqmachu, "__MQMACHU", FRV_BUILTIN_MQMACHU, 0, 0 },
{ CODE_FOR_mqxmachs, "__MQXMACHS", FRV_BUILTIN_MQXMACHS, 0, 0 },
{ CODE_FOR_mqxmacxhs, "__MQXMACXHS", FRV_BUILTIN_MQXMACXHS, 0, 0 },
{ CODE_FOR_mqmacxhs, "__MQMACXHS", FRV_BUILTIN_MQMACXHS, 0, 0 }
};
static struct builtin_description bdesc_voidacc[] =
{
{ CODE_FOR_maddaccs, "__MADDACCS", FRV_BUILTIN_MADDACCS, 0, 0 },
{ CODE_FOR_msubaccs, "__MSUBACCS", FRV_BUILTIN_MSUBACCS, 0, 0 },
{ CODE_FOR_masaccs, "__MASACCS", FRV_BUILTIN_MASACCS, 0, 0 },
{ CODE_FOR_mdaddaccs, "__MDADDACCS", FRV_BUILTIN_MDADDACCS, 0, 0 },
{ CODE_FOR_mdsubaccs, "__MDSUBACCS", FRV_BUILTIN_MDSUBACCS, 0, 0 },
{ CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
};
static void
frv_init_builtins (void)
{
tree endlink = void_list_node;
tree accumulator = integer_type_node;
tree integer = integer_type_node;
tree voidt = void_type_node;
tree uhalf = short_unsigned_type_node;
tree sword1 = long_integer_type_node;
tree uword1 = long_unsigned_type_node;
tree sword2 = long_long_integer_type_node;
tree uword2 = long_long_unsigned_type_node;
tree uword4 = build_pointer_type (uword1);
tree iacc = integer_type_node;
#define UNARY(RET, T1) \
build_function_type (RET, tree_cons (NULL_TREE, T1, endlink))
#define BINARY(RET, T1, T2) \
build_function_type (RET, tree_cons (NULL_TREE, T1, \
tree_cons (NULL_TREE, T2, endlink)))
#define TRINARY(RET, T1, T2, T3) \
build_function_type (RET, tree_cons (NULL_TREE, T1, \
tree_cons (NULL_TREE, T2, \
tree_cons (NULL_TREE, T3, endlink))))
#define QUAD(RET, T1, T2, T3, T4) \
build_function_type (RET, tree_cons (NULL_TREE, T1, \
tree_cons (NULL_TREE, T2, \
tree_cons (NULL_TREE, T3, \
tree_cons (NULL_TREE, T4, endlink)))))
tree void_ftype_void = build_function_type (voidt, endlink);
tree void_ftype_acc = UNARY (voidt, accumulator);
tree void_ftype_uw4_uw1 = BINARY (voidt, uword4, uword1);
tree void_ftype_uw4_uw2 = BINARY (voidt, uword4, uword2);
tree void_ftype_acc_uw1 = BINARY (voidt, accumulator, uword1);
tree void_ftype_acc_acc = BINARY (voidt, accumulator, accumulator);
tree void_ftype_acc_uw1_uw1 = TRINARY (voidt, accumulator, uword1, uword1);
tree void_ftype_acc_sw1_sw1 = TRINARY (voidt, accumulator, sword1, sword1);
tree void_ftype_acc_uw2_uw2 = TRINARY (voidt, accumulator, uword2, uword2);
tree void_ftype_acc_sw2_sw2 = TRINARY (voidt, accumulator, sword2, sword2);
tree uw1_ftype_uw1 = UNARY (uword1, uword1);
tree uw1_ftype_sw1 = UNARY (uword1, sword1);
tree uw1_ftype_uw2 = UNARY (uword1, uword2);
tree uw1_ftype_acc = UNARY (uword1, accumulator);
tree uw1_ftype_uh_uh = BINARY (uword1, uhalf, uhalf);
tree uw1_ftype_uw1_uw1 = BINARY (uword1, uword1, uword1);
tree uw1_ftype_uw1_int = BINARY (uword1, uword1, integer);
tree uw1_ftype_acc_uw1 = BINARY (uword1, accumulator, uword1);
tree uw1_ftype_acc_sw1 = BINARY (uword1, accumulator, sword1);
tree uw1_ftype_uw2_uw1 = BINARY (uword1, uword2, uword1);
tree uw1_ftype_uw2_int = BINARY (uword1, uword2, integer);
tree sw1_ftype_int = UNARY (sword1, integer);
tree sw1_ftype_sw1_sw1 = BINARY (sword1, sword1, sword1);
tree sw1_ftype_sw1_int = BINARY (sword1, sword1, integer);
tree uw2_ftype_uw1 = UNARY (uword2, uword1);
tree uw2_ftype_uw1_int = BINARY (uword2, uword1, integer);
tree uw2_ftype_uw2_uw2 = BINARY (uword2, uword2, uword2);
tree uw2_ftype_uw2_int = BINARY (uword2, uword2, integer);
tree uw2_ftype_acc_int = BINARY (uword2, accumulator, integer);
tree uw2_ftype_uh_uh_uh_uh = QUAD (uword2, uhalf, uhalf, uhalf, uhalf);
tree sw2_ftype_sw2_sw2 = BINARY (sword2, sword2, sword2);
tree sw2_ftype_sw2_int = BINARY (sword2, sword2, integer);
tree uw2_ftype_uw1_uw1 = BINARY (uword2, uword1, uword1);
tree sw2_ftype_sw1_sw1 = BINARY (sword2, sword1, sword1);
tree void_ftype_sw1_sw1 = BINARY (voidt, sword1, sword1);
tree void_ftype_iacc_sw2 = BINARY (voidt, iacc, sword2);
tree void_ftype_iacc_sw1 = BINARY (voidt, iacc, sword1);
tree sw1_ftype_sw1 = UNARY (sword1, sword1);
tree sw2_ftype_iacc = UNARY (sword2, iacc);
tree sw1_ftype_iacc = UNARY (sword1, iacc);
tree void_ftype_ptr = UNARY (voidt, const_ptr_type_node);
def_builtin ("__MAND", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAND);
def_builtin ("__MOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MOR);
def_builtin ("__MXOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MXOR);
def_builtin ("__MNOT", uw1_ftype_uw1, FRV_BUILTIN_MNOT);
def_builtin ("__MROTLI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTLI);
def_builtin ("__MROTRI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTRI);
def_builtin ("__MWCUT", uw1_ftype_uw2_uw1, FRV_BUILTIN_MWCUT);
def_builtin ("__MAVEH", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAVEH);
def_builtin ("__MSLLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSLLHI);
def_builtin ("__MSRLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSRLHI);
def_builtin ("__MSRAHI", sw1_ftype_sw1_int, FRV_BUILTIN_MSRAHI);
def_builtin ("__MSATHS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSATHS);
def_builtin ("__MSATHU", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSATHU);
def_builtin ("__MADDHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MADDHSS);
def_builtin ("__MADDHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MADDHUS);
def_builtin ("__MSUBHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSUBHSS);
def_builtin ("__MSUBHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSUBHUS);
def_builtin ("__MMULHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULHS);
def_builtin ("__MMULHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULHU);
def_builtin ("__MMULXHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULXHS);
def_builtin ("__MMULXHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULXHU);
def_builtin ("__MMACHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMACHS);
def_builtin ("__MMACHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMACHU);
def_builtin ("__MMRDHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMRDHS);
def_builtin ("__MMRDHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMRDHU);
def_builtin ("__MQADDHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQADDHSS);
def_builtin ("__MQADDHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQADDHUS);
def_builtin ("__MQSUBHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSUBHSS);
def_builtin ("__MQSUBHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQSUBHUS);
def_builtin ("__MQMULHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULHS);
def_builtin ("__MQMULHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULHU);
def_builtin ("__MQMULXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULXHS);
def_builtin ("__MQMULXHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULXHU);
def_builtin ("__MQMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACHS);
def_builtin ("__MQMACHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMACHU);
def_builtin ("__MCPXRS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXRS);
def_builtin ("__MCPXRU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXRU);
def_builtin ("__MCPXIS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXIS);
def_builtin ("__MCPXIU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXIU);
def_builtin ("__MQCPXRS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXRS);
def_builtin ("__MQCPXRU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXRU);
def_builtin ("__MQCPXIS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXIS);
def_builtin ("__MQCPXIU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXIU);
def_builtin ("__MCUT", uw1_ftype_acc_uw1, FRV_BUILTIN_MCUT);
def_builtin ("__MCUTSS", uw1_ftype_acc_sw1, FRV_BUILTIN_MCUTSS);
def_builtin ("__MEXPDHW", uw1_ftype_uw1_int, FRV_BUILTIN_MEXPDHW);
def_builtin ("__MEXPDHD", uw2_ftype_uw1_int, FRV_BUILTIN_MEXPDHD);
def_builtin ("__MPACKH", uw1_ftype_uh_uh, FRV_BUILTIN_MPACKH);
def_builtin ("__MUNPACKH", uw2_ftype_uw1, FRV_BUILTIN_MUNPACKH);
def_builtin ("__MDPACKH", uw2_ftype_uh_uh_uh_uh, FRV_BUILTIN_MDPACKH);
def_builtin ("__MDUNPACKH", void_ftype_uw4_uw2, FRV_BUILTIN_MDUNPACKH);
def_builtin ("__MBTOH", uw2_ftype_uw1, FRV_BUILTIN_MBTOH);
def_builtin ("__MHTOB", uw1_ftype_uw2, FRV_BUILTIN_MHTOB);
def_builtin ("__MBTOHE", void_ftype_uw4_uw1, FRV_BUILTIN_MBTOHE);
def_builtin ("__MCLRACC", void_ftype_acc, FRV_BUILTIN_MCLRACC);
def_builtin ("__MCLRACCA", void_ftype_void, FRV_BUILTIN_MCLRACCA);
def_builtin ("__MRDACC", uw1_ftype_acc, FRV_BUILTIN_MRDACC);
def_builtin ("__MRDACCG", uw1_ftype_acc, FRV_BUILTIN_MRDACCG);
def_builtin ("__MWTACC", void_ftype_acc_uw1, FRV_BUILTIN_MWTACC);
def_builtin ("__MWTACCG", void_ftype_acc_uw1, FRV_BUILTIN_MWTACCG);
def_builtin ("__Mcop1", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP1);
def_builtin ("__Mcop2", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP2);
def_builtin ("__MTRAP", void_ftype_void, FRV_BUILTIN_MTRAP);
def_builtin ("__MQXMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACHS);
def_builtin ("__MQXMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACXHS);
def_builtin ("__MQMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACXHS);
def_builtin ("__MADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MADDACCS);
def_builtin ("__MSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MSUBACCS);
def_builtin ("__MASACCS", void_ftype_acc_acc, FRV_BUILTIN_MASACCS);
def_builtin ("__MDADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MDADDACCS);
def_builtin ("__MDSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MDSUBACCS);
def_builtin ("__MDASACCS", void_ftype_acc_acc, FRV_BUILTIN_MDASACCS);
def_builtin ("__MABSHS", uw1_ftype_sw1, FRV_BUILTIN_MABSHS);
def_builtin ("__MDROTLI", uw2_ftype_uw2_int, FRV_BUILTIN_MDROTLI);
def_builtin ("__MCPLHI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLHI);
def_builtin ("__MCPLI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLI);
def_builtin ("__MDCUTSSI", uw2_ftype_acc_int, FRV_BUILTIN_MDCUTSSI);
def_builtin ("__MQSATHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSATHS);
def_builtin ("__MHSETLOS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETLOS);
def_builtin ("__MHSETHIS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETHIS);
def_builtin ("__MHDSETS", sw1_ftype_int, FRV_BUILTIN_MHDSETS);
def_builtin ("__MHSETLOH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETLOH);
def_builtin ("__MHSETHIH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETHIH);
def_builtin ("__MHDSETH", uw1_ftype_uw1_int, FRV_BUILTIN_MHDSETH);
def_builtin ("__MQLCLRHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQLCLRHS);
def_builtin ("__MQLMTHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQLMTHS);
def_builtin ("__MQSLLHI", uw2_ftype_uw2_int, FRV_BUILTIN_MQSLLHI);
def_builtin ("__MQSRAHI", sw2_ftype_sw2_int, FRV_BUILTIN_MQSRAHI);
def_builtin ("__SMUL", sw2_ftype_sw1_sw1, FRV_BUILTIN_SMUL);
def_builtin ("__UMUL", uw2_ftype_uw1_uw1, FRV_BUILTIN_UMUL);
def_builtin ("__SMASS", void_ftype_sw1_sw1, FRV_BUILTIN_SMASS);
def_builtin ("__SMSSS", void_ftype_sw1_sw1, FRV_BUILTIN_SMSSS);
def_builtin ("__SMU", void_ftype_sw1_sw1, FRV_BUILTIN_SMU);
def_builtin ("__ADDSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_ADDSS);
def_builtin ("__SUBSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_SUBSS);
def_builtin ("__SLASS", sw1_ftype_sw1_sw1, FRV_BUILTIN_SLASS);
def_builtin ("__SCAN", sw1_ftype_sw1_sw1, FRV_BUILTIN_SCAN);
def_builtin ("__SCUTSS", sw1_ftype_sw1, FRV_BUILTIN_SCUTSS);
def_builtin ("__IACCreadll", sw2_ftype_iacc, FRV_BUILTIN_IACCreadll);
def_builtin ("__IACCreadl", sw1_ftype_iacc, FRV_BUILTIN_IACCreadl);
def_builtin ("__IACCsetll", void_ftype_iacc_sw2, FRV_BUILTIN_IACCsetll);
def_builtin ("__IACCsetl", void_ftype_iacc_sw1, FRV_BUILTIN_IACCsetl);
def_builtin ("__data_prefetch0", void_ftype_ptr, FRV_BUILTIN_PREFETCH0);
def_builtin ("__data_prefetch", void_ftype_ptr, FRV_BUILTIN_PREFETCH);
#undef UNARY
#undef BINARY
#undef TRINARY
#undef QUAD
}
static void
frv_init_libfuncs (void)
{
set_optab_libfunc (smod_optab, SImode, "__modi");
set_optab_libfunc (umod_optab, SImode, "__umodi");
set_optab_libfunc (add_optab, DImode, "__addll");
set_optab_libfunc (sub_optab, DImode, "__subll");
set_optab_libfunc (smul_optab, DImode, "__mulll");
set_optab_libfunc (sdiv_optab, DImode, "__divll");
set_optab_libfunc (smod_optab, DImode, "__modll");
set_optab_libfunc (umod_optab, DImode, "__umodll");
set_optab_libfunc (and_optab, DImode, "__andll");
set_optab_libfunc (ior_optab, DImode, "__orll");
set_optab_libfunc (xor_optab, DImode, "__xorll");
set_optab_libfunc (one_cmpl_optab, DImode, "__notll");
set_optab_libfunc (add_optab, SFmode, "__addf");
set_optab_libfunc (sub_optab, SFmode, "__subf");
set_optab_libfunc (smul_optab, SFmode, "__mulf");
set_optab_libfunc (sdiv_optab, SFmode, "__divf");
set_optab_libfunc (add_optab, DFmode, "__addd");
set_optab_libfunc (sub_optab, DFmode, "__subd");
set_optab_libfunc (smul_optab, DFmode, "__muld");
set_optab_libfunc (sdiv_optab, DFmode, "__divd");
set_conv_libfunc (sext_optab, DFmode, SFmode, "__ftod");
set_conv_libfunc (trunc_optab, SFmode, DFmode, "__dtof");
set_conv_libfunc (sfix_optab, SImode, SFmode, "__ftoi");
set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftoll");
set_conv_libfunc (sfix_optab, SImode, DFmode, "__dtoi");
set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtoll");
set_conv_libfunc (ufix_optab, SImode, SFmode, "__ftoui");
set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoull");
set_conv_libfunc (ufix_optab, SImode, DFmode, "__dtoui");
set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoull");
set_conv_libfunc (sfloat_optab, SFmode, SImode, "__itof");
set_conv_libfunc (sfloat_optab, SFmode, DImode, "__lltof");
set_conv_libfunc (sfloat_optab, DFmode, SImode, "__itod");
set_conv_libfunc (sfloat_optab, DFmode, DImode, "__lltod");
}
static rtx
frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
{
rtx reg;
int i;
for (i = 0; i <= ACC_MASK; i++)
if ((i & ACC_MASK) == i)
global_regs[i + ACC_FIRST] = global_regs[i + ACCG_FIRST] = 1;
if (GET_CODE (opval) != CONST_INT)
{
error ("accumulator is not a constant integer");
return NULL_RTX;
}
if ((INTVAL (opval) & ~ACC_MASK) != 0)
{
error ("accumulator number is out of bounds");
return NULL_RTX;
}
reg = gen_rtx_REG (insn_data[icode].operand[opnum].mode,
ACC_FIRST + INTVAL (opval));
if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
REGNO (reg) = ACCG_FIRST + INTVAL (opval);
if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
{
error ("inappropriate accumulator for %qs", insn_data[icode].name);
return NULL_RTX;
}
return reg;
}
static enum machine_mode
frv_matching_accg_mode (enum machine_mode mode)
{
switch (mode)
{
case V4SImode:
return V4QImode;
case DImode:
return HImode;
case SImode:
return QImode;
default:
abort ();
}
}
rtx
frv_matching_accg_for_acc (rtx acc)
{
return gen_rtx_REG (frv_matching_accg_mode (GET_MODE (acc)),
REGNO (acc) - ACC_FIRST + ACCG_FIRST);
}
static rtx
frv_read_argument (tree *arglistptr)
{
tree next = TREE_VALUE (*arglistptr);
*arglistptr = TREE_CHAIN (*arglistptr);
return expand_expr (next, NULL_RTX, VOIDmode, 0);
}
static rtx
frv_read_iacc_argument (enum machine_mode mode, tree *arglistptr)
{
int i, regno;
rtx op;
op = frv_read_argument (arglistptr);
if (GET_CODE (op) != CONST_INT
|| INTVAL (op) < 0
|| INTVAL (op) > IACC_LAST - IACC_FIRST
|| ((INTVAL (op) * 4) & (GET_MODE_SIZE (mode) - 1)) != 0)
{
error ("invalid IACC argument");
op = const0_rtx;
}
regno = INTVAL (op) + IACC_FIRST;
for (i = 0; i < HARD_REGNO_NREGS (regno, mode); i++)
global_regs[regno + i] = 1;
return gen_rtx_REG (mode, regno);
}
static int
frv_check_constant_argument (enum insn_code icode, int opnum, rtx opval)
{
if (GET_CODE (opval) != CONST_INT)
{
error ("%qs expects a constant argument", insn_data[icode].name);
return FALSE;
}
if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
{
error ("constant argument out of range for %qs", insn_data[icode].name);
return FALSE;
}
return TRUE;
}
static rtx
frv_legitimize_target (enum insn_code icode, rtx target)
{
enum machine_mode mode = insn_data[icode].operand[0].mode;
if (! target
|| GET_MODE (target) != mode
|| ! (*insn_data[icode].operand[0].predicate) (target, mode))
return gen_reg_rtx (mode);
else
return target;
}
static rtx
frv_legitimize_argument (enum insn_code icode, int opnum, rtx arg)
{
enum machine_mode mode = insn_data[icode].operand[opnum].mode;
if ((*insn_data[icode].operand[opnum].predicate) (arg, mode))
return arg;
else
return copy_to_mode_reg (mode, arg);
}
static rtx
frv_expand_set_builtin (enum insn_code icode, tree arglist, rtx target)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
if (! frv_check_constant_argument (icode, 1, op0))
return NULL_RTX;
target = frv_legitimize_target (icode, target);
pat = GEN_FCN (icode) (target, op0);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
target = frv_legitimize_target (icode, target);
op0 = frv_legitimize_argument (icode, 1, op0);
pat = GEN_FCN (icode) (target, op0);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
target = frv_legitimize_target (icode, target);
op0 = frv_legitimize_argument (icode, 1, op0);
op1 = frv_legitimize_argument (icode, 2, op1);
pat = GEN_FCN (icode) (target, op0, op1);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_cut_builtin (enum insn_code icode, tree arglist, rtx target)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
rtx op2;
target = frv_legitimize_target (icode, target);
op0 = frv_int_to_acc (icode, 1, op0);
if (! op0)
return NULL_RTX;
if (icode == CODE_FOR_mdcutssi || GET_CODE (op1) == CONST_INT)
{
if (! frv_check_constant_argument (icode, 2, op1))
return NULL_RTX;
}
else
op1 = frv_legitimize_argument (icode, 2, op1);
op2 = frv_matching_accg_for_acc (op0);
pat = GEN_FCN (icode) (target, op0, op1, op2);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_binopimm_builtin (enum insn_code icode, tree arglist, rtx target)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
if (! frv_check_constant_argument (icode, 2, op1))
return NULL_RTX;
target = frv_legitimize_target (icode, target);
op0 = frv_legitimize_argument (icode, 1, op0);
pat = GEN_FCN (icode) (target, op0, op1);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_voidbinop_builtin (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
enum machine_mode mode0 = insn_data[icode].operand[0].mode;
rtx addr;
if (GET_CODE (op0) != MEM)
{
rtx reg = op0;
if (! offsettable_address_p (0, mode0, op0))
{
reg = gen_reg_rtx (Pmode);
emit_insn (gen_rtx_SET (VOIDmode, reg, op0));
}
op0 = gen_rtx_MEM (SImode, reg);
}
addr = XEXP (op0, 0);
if (! offsettable_address_p (0, mode0, addr))
addr = copy_to_mode_reg (Pmode, op0);
op0 = change_address (op0, V4SImode, addr);
op1 = frv_legitimize_argument (icode, 1, op1);
pat = GEN_FCN (icode) (op0, op1);
if (! pat)
return 0;
emit_insn (pat);
return 0;
}
static rtx
frv_expand_int_void2arg (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
op0 = frv_legitimize_argument (icode, 1, op0);
op1 = frv_legitimize_argument (icode, 1, op1);
pat = GEN_FCN (icode) (op0, op1);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return NULL_RTX;
}
static rtx
frv_expand_prefetches (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
pat = GEN_FCN (icode) (force_reg (Pmode, op0));
if (! pat)
return 0;
emit_insn (pat);
return 0;
}
static rtx
frv_expand_voidtriop_builtin (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
rtx op2 = frv_read_argument (&arglist);
rtx op3;
op0 = frv_int_to_acc (icode, 0, op0);
if (! op0)
return NULL_RTX;
op1 = frv_legitimize_argument (icode, 1, op1);
op2 = frv_legitimize_argument (icode, 2, op2);
op3 = frv_matching_accg_for_acc (op0);
pat = GEN_FCN (icode) (op0, op1, op2, op3);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return NULL_RTX;
}
static rtx
frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
rtx op2;
rtx op3;
op0 = frv_int_to_acc (icode, 0, op0);
if (! op0)
return NULL_RTX;
op1 = frv_int_to_acc (icode, 1, op1);
if (! op1)
return NULL_RTX;
op2 = frv_matching_accg_for_acc (op0);
op3 = frv_matching_accg_for_acc (op1);
pat = GEN_FCN (icode) (op0, op1, op2, op3);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return NULL_RTX;
}
static rtx
frv_expand_mdpackh_builtin (tree arglist, rtx target)
{
enum insn_code icode = CODE_FOR_mdpackh;
rtx pat, op0, op1;
rtx arg1 = frv_read_argument (&arglist);
rtx arg2 = frv_read_argument (&arglist);
rtx arg3 = frv_read_argument (&arglist);
rtx arg4 = frv_read_argument (&arglist);
target = frv_legitimize_target (icode, target);
op0 = gen_reg_rtx (DImode);
op1 = gen_reg_rtx (DImode);
emit_insn (gen_rtx_CLOBBER (DImode, op0));
emit_insn (gen_rtx_CLOBBER (DImode, op1));
emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 2), arg1);
emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 6), arg2);
emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 2), arg3);
emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 6), arg4);
pat = GEN_FCN (icode) (target, op0, op1);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_mclracc_builtin (tree arglist)
{
enum insn_code icode = CODE_FOR_mclracc;
rtx pat;
rtx op0 = frv_read_argument (&arglist);
op0 = frv_int_to_acc (icode, 0, op0);
if (! op0)
return NULL_RTX;
pat = GEN_FCN (icode) (op0);
if (pat)
emit_insn (pat);
return NULL_RTX;
}
static rtx
frv_expand_noargs_builtin (enum insn_code icode)
{
rtx pat = GEN_FCN (icode) (const0_rtx);
if (pat)
emit_insn (pat);
return NULL_RTX;
}
static rtx
frv_expand_mrdacc_builtin (enum insn_code icode, tree arglist)
{
rtx pat;
rtx target = gen_reg_rtx (SImode);
rtx op0 = frv_read_argument (&arglist);
op0 = frv_int_to_acc (icode, 1, op0);
if (! op0)
return NULL_RTX;
pat = GEN_FCN (icode) (target, op0);
if (! pat)
return NULL_RTX;
emit_insn (pat);
return target;
}
static rtx
frv_expand_mwtacc_builtin (enum insn_code icode, tree arglist)
{
rtx pat;
rtx op0 = frv_read_argument (&arglist);
rtx op1 = frv_read_argument (&arglist);
op0 = frv_int_to_acc (icode, 0, op0);
if (! op0)
return NULL_RTX;
op1 = frv_legitimize_argument (icode, 1, op1);
pat = GEN_FCN (icode) (op0, op1);
if (pat)
emit_insn (pat);
return NULL_RTX;
}
static void
frv_split_iacc_move (rtx dest, rtx src)
{
enum machine_mode inner;
int i;
inner = GET_MODE (dest);
for (i = 0; i < GET_MODE_SIZE (inner); i += GET_MODE_SIZE (SImode))
emit_move_insn (simplify_gen_subreg (SImode, dest, inner, i),
simplify_gen_subreg (SImode, src, inner, i));
}
static rtx
frv_expand_builtin (tree exp,
rtx target,
rtx subtarget ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED,
int ignore ATTRIBUTE_UNUSED)
{
tree arglist = TREE_OPERAND (exp, 1);
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
unsigned fcode = (unsigned)DECL_FUNCTION_CODE (fndecl);
unsigned i;
struct builtin_description *d;
if (fcode < FRV_BUILTIN_FIRST_NONMEDIA && !TARGET_MEDIA)
{
error ("media functions are not available unless -mmedia is used");
return NULL_RTX;
}
switch (fcode)
{
case FRV_BUILTIN_MCOP1:
case FRV_BUILTIN_MCOP2:
case FRV_BUILTIN_MDUNPACKH:
case FRV_BUILTIN_MBTOHE:
if (! TARGET_MEDIA_REV1)
{
error ("this media function is only available on the fr500");
return NULL_RTX;
}
break;
case FRV_BUILTIN_MQXMACHS:
case FRV_BUILTIN_MQXMACXHS:
case FRV_BUILTIN_MQMACXHS:
case FRV_BUILTIN_MADDACCS:
case FRV_BUILTIN_MSUBACCS:
case FRV_BUILTIN_MASACCS:
case FRV_BUILTIN_MDADDACCS:
case FRV_BUILTIN_MDSUBACCS:
case FRV_BUILTIN_MDASACCS:
case FRV_BUILTIN_MABSHS:
case FRV_BUILTIN_MDROTLI:
case FRV_BUILTIN_MCPLHI:
case FRV_BUILTIN_MCPLI:
case FRV_BUILTIN_MDCUTSSI:
case FRV_BUILTIN_MQSATHS:
case FRV_BUILTIN_MHSETLOS:
case FRV_BUILTIN_MHSETLOH:
case FRV_BUILTIN_MHSETHIS:
case FRV_BUILTIN_MHSETHIH:
case FRV_BUILTIN_MHDSETS:
case FRV_BUILTIN_MHDSETH:
if (! TARGET_MEDIA_REV2)
{
error ("this media function is only available on the fr400"
" and fr550");
return NULL_RTX;
}
break;
case FRV_BUILTIN_SMASS:
case FRV_BUILTIN_SMSSS:
case FRV_BUILTIN_SMU:
case FRV_BUILTIN_ADDSS:
case FRV_BUILTIN_SUBSS:
case FRV_BUILTIN_SLASS:
case FRV_BUILTIN_SCUTSS:
case FRV_BUILTIN_IACCreadll:
case FRV_BUILTIN_IACCreadl:
case FRV_BUILTIN_IACCsetll:
case FRV_BUILTIN_IACCsetl:
if (!TARGET_FR405_BUILTINS)
{
error ("this builtin function is only available"
" on the fr405 and fr450");
return NULL_RTX;
}
break;
case FRV_BUILTIN_PREFETCH:
if (!TARGET_FR500_FR550_BUILTINS)
{
error ("this builtin function is only available on the fr500"
" and fr550");
return NULL_RTX;
}
break;
case FRV_BUILTIN_MQLCLRHS:
case FRV_BUILTIN_MQLMTHS:
case FRV_BUILTIN_MQSLLHI:
case FRV_BUILTIN_MQSRAHI:
if (!TARGET_MEDIA_FR450)
{
error ("this builtin function is only available on the fr450");
return NULL_RTX;
}
break;
default:
break;
}
switch (fcode)
{
case FRV_BUILTIN_MTRAP:
return frv_expand_noargs_builtin (CODE_FOR_mtrap);
case FRV_BUILTIN_MCLRACC:
return frv_expand_mclracc_builtin (arglist);
case FRV_BUILTIN_MCLRACCA:
if (TARGET_ACC_8)
return frv_expand_noargs_builtin (CODE_FOR_mclracca8);
else
return frv_expand_noargs_builtin (CODE_FOR_mclracca4);
case FRV_BUILTIN_MRDACC:
return frv_expand_mrdacc_builtin (CODE_FOR_mrdacc, arglist);
case FRV_BUILTIN_MRDACCG:
return frv_expand_mrdacc_builtin (CODE_FOR_mrdaccg, arglist);
case FRV_BUILTIN_MWTACC:
return frv_expand_mwtacc_builtin (CODE_FOR_mwtacc, arglist);
case FRV_BUILTIN_MWTACCG:
return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
case FRV_BUILTIN_MDPACKH:
return frv_expand_mdpackh_builtin (arglist, target);
case FRV_BUILTIN_IACCreadll:
{
rtx src = frv_read_iacc_argument (DImode, &arglist);
if (target == 0 || !REG_P (target))
target = gen_reg_rtx (DImode);
frv_split_iacc_move (target, src);
return target;
}
case FRV_BUILTIN_IACCreadl:
return frv_read_iacc_argument (SImode, &arglist);
case FRV_BUILTIN_IACCsetll:
{
rtx dest = frv_read_iacc_argument (DImode, &arglist);
rtx src = frv_read_argument (&arglist);
frv_split_iacc_move (dest, force_reg (DImode, src));
return 0;
}
case FRV_BUILTIN_IACCsetl:
{
rtx dest = frv_read_iacc_argument (SImode, &arglist);
rtx src = frv_read_argument (&arglist);
emit_move_insn (dest, force_reg (SImode, src));
return 0;
}
default:
break;
}
for (i = 0, d = bdesc_set; i < ARRAY_SIZE (bdesc_set); i++, d++)
if (d->code == fcode)
return frv_expand_set_builtin (d->icode, arglist, target);
for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
if (d->code == fcode)
return frv_expand_unop_builtin (d->icode, arglist, target);
for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
if (d->code == fcode)
return frv_expand_binop_builtin (d->icode, arglist, target);
for (i = 0, d = bdesc_cut; i < ARRAY_SIZE (bdesc_cut); i++, d++)
if (d->code == fcode)
return frv_expand_cut_builtin (d->icode, arglist, target);
for (i = 0, d = bdesc_2argimm; i < ARRAY_SIZE (bdesc_2argimm); i++, d++)
if (d->code == fcode)
return frv_expand_binopimm_builtin (d->icode, arglist, target);
for (i = 0, d = bdesc_void2arg; i < ARRAY_SIZE (bdesc_void2arg); i++, d++)
if (d->code == fcode)
return frv_expand_voidbinop_builtin (d->icode, arglist);
for (i = 0, d = bdesc_void3arg; i < ARRAY_SIZE (bdesc_void3arg); i++, d++)
if (d->code == fcode)
return frv_expand_voidtriop_builtin (d->icode, arglist);
for (i = 0, d = bdesc_voidacc; i < ARRAY_SIZE (bdesc_voidacc); i++, d++)
if (d->code == fcode)
return frv_expand_voidaccop_builtin (d->icode, arglist);
for (i = 0, d = bdesc_int_void2arg;
i < ARRAY_SIZE (bdesc_int_void2arg); i++, d++)
if (d->code == fcode)
return frv_expand_int_void2arg (d->icode, arglist);
for (i = 0, d = bdesc_prefetches;
i < ARRAY_SIZE (bdesc_prefetches); i++, d++)
if (d->code == fcode)
return frv_expand_prefetches (d->icode, arglist);
return 0;
}
static bool
frv_in_small_data_p (tree decl)
{
HOST_WIDE_INT size;
tree section_name;
if (TREE_CODE (decl) != VAR_DECL || DECL_ARTIFICIAL (decl))
return false;
section_name = DECL_SECTION_NAME (decl);
if (section_name)
{
if (TREE_CODE (section_name) != STRING_CST)
abort ();
if (frv_string_begins_with (section_name, ".sdata"))
return true;
if (frv_string_begins_with (section_name, ".sbss"))
return true;
return false;
}
size = int_size_in_bytes (TREE_TYPE (decl));
if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
return true;
return false;
}
static bool
frv_rtx_costs (rtx x,
int code ATTRIBUTE_UNUSED,
int outer_code ATTRIBUTE_UNUSED,
int *total)
{
if (outer_code == MEM)
{
*total = COSTS_N_INSNS (0);
return true;
}
switch (code)
{
case CONST_INT:
if (IN_RANGE_P (INTVAL (x), -2048, 2047))
{
*total = 0;
return true;
}
case CONST:
case LABEL_REF:
case SYMBOL_REF:
case CONST_DOUBLE:
*total = COSTS_N_INSNS (2);
return true;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
case NOT:
case NEG:
case COMPARE:
if (GET_MODE (x) == SImode)
*total = COSTS_N_INSNS (1);
else if (GET_MODE (x) == DImode)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (3);
return true;
case MULT:
if (GET_MODE (x) == SImode)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (6);
return true;
case DIV:
case UDIV:
case MOD:
case UMOD:
*total = COSTS_N_INSNS (18);
return true;
case MEM:
*total = COSTS_N_INSNS (3);
return true;
default:
return false;
}
}
static void
frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
ctors_section ();
assemble_align (POINTER_SIZE);
if (TARGET_FDPIC)
{
if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
abort ();
return;
}
assemble_integer_with_op ("\t.picptr\t", symbol);
}
static void
frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
dtors_section ();
assemble_align (POINTER_SIZE);
if (TARGET_FDPIC)
{
if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
abort ();
return;
}
assemble_integer_with_op ("\t.picptr\t", symbol);
}
static rtx
frv_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
int incoming ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (Pmode, FRV_STRUCT_VALUE_REGNUM);
}
#define TLS_BIAS (2048 - 16)
void
frv_output_dwarf_dtprel (FILE *file, int size, rtx x)
{
if (size != 4)
abort ();
fputs ("\t.picptr\ttlsmoff(", file);
output_addr_const (file, plus_constant (x, TLS_BIAS));
fputs (")", file);
}
#include "gt-frv.h"