(FRV_CPU_FR405): New processor enums.
(frv_issue_rate, frv_acc_group): Declare.
* config/frv/frv.h (CPP_SPEC, CPP_FRV_SPEC, CPP_FR500_SPEC): Delete.
(CPP_FR400_SPEC, CPP_SIMPLE_SPEC): Delete.
(MASK_DEFAULT_FR550, MASK_DEFAULT_FR450): New macros.
(SUBTARGET_EXTRA_SPECS, EXTRA_SPECS, CPP_CPU_DEFAULT_SPEC): Delete.
(TARGET_CPU_CPP_BUILTINS): Define the macros that were previously
handled by CPP_SPEC.
(MASK_LONG_CALLS, TARGET_LONG_CALLS): New macros.
(MASK_ALIGN_LABELS, TARGET_ALIGN_LABELS): New macros.
(ACC_MASK): New macro.
(TARGET_MEDIA_REV2): Include FRV_CPU_{FR405,FR450,FR550}.
(TARGET_MEDIA_FR450): New macro.
(TARGET_FR500_FR550_BUILTINS, TARGET_FR405_BUILTINS): New macros.
(TARGET_SWITCHES): Add -m{no-,}align-labels and -m{no-,}long-calls.
(LABEL_ALIGN_AFTER_BARRIER): Define.
(ACC_LAST, ACCG_LAST): Add four new accumulator registers.
(IACC_FIRST, IACC_LAST): New pair of SPRs.
(ACCG_FIRST, AP_FIRST, SPR_FIRST, SPR_LAST): Adjust accordingly.
(FIXED_REGISTERS, CALL_USED_REGISTERS, REG_ALLOC_ORDER)
(REGISTER_NAMES): Add entries for new registers.
(REG_CLASS_CONTENTS): Update for new register ranges.
(EXTRA_CONSTRAINT_FOR_S): Redefine in terms of call_operand.
(ISSUE_RATE, CLEAR_VLIW_START, SET_VLIW_START): Delete.
(PACKING_FLAG_USED_P): Delete.
(FRV_BUILTIN_MQLCLRHS, FRV_BUILTIN_MQLMTHS, FRV_BUILTIN_MQSLLHI)
(FRV_BUILTIN_MQSRAHI, FRV_BUILTIN_SMUL, FRV_BUILTIN_UMUL)
(FRV_BUILTIN_PREFETCH0, FRV_BUILTIN_PREFETCH, FRV_BUILTIN_SMASS)
(FRV_BUILTIN_SMSSS, FRV_BUILTIN_SMU, FRV_BUILTIN_SCUTSS)
(FRV_BUILTIN_ADDSS, FRV_BUILTIN_SUBSS, FRV_BUILTIN_SLASS)
(FRV_BUILTIN_IACCread{l,ll}, FRV_BUILTIN_IACCset{ll,l})
(FRV_BUILTIN_SCAN): New members of frv_builtin_enum.
(FRV_BUILTIN_FIRST_NONMEDIA): New macro.
(CPU_UNITS_QUERY): Define to 1.
* config/frv/frv.c: Include gt-frv.h
(NUM_NOP_PATTERNS, NTH_UNIT, UNIT_NUMBER, PACKING_FLAG_P): New macros.
(SET_PACKING_FLAG, CLEAR_PACKING_FLAG, FOR_EACH_REGNO): New macros.
(frv_insn_group): New enumeration.
(frv_unit_names, frv_unit_groups, frv_unit_codes): New variables.
(frv_type_to_unit, frv_nops, frv_num_nops): New variables.
(REGSTATE_DEAD, REGSTATE_LIVE, REGSTATE_UNUSED, REGSTATE_MASK)
(REGSTATE_CONDJUMP): Delete. Shuffle other numbers to cover the
gap left by REGSTATE_LIVE.
(regstate_t): New typedef.
(TARGET_MACHINE_DEPENDENT_REORG): Define.
(frv_default_flags_for_cpu): Handle FRV_CPU_{FR550,FR450,FR405}.
(frv_override_options): Check for -mcpu={fr550,fr450,fr405}.
Initialize frv_unit_codes[] and frv_type_to_unit[].
(frv_conditional_register_usage): Remove redundant fixing of
accumulator registers.
(frv_insn_packing_flag): Update specification.
(frv_function_prologue): Don't set frv_insn_packing_flag here.
Zero out frv_nops[].
(frv_expand_epilogue): Remove comments about the no-longer-present
SIBCALL_P argument.
(frv_asm_output_mi_thunk): Check frv_issue_rate() rather than
PACKING_FLAG_USED_P() when deciding whether to pack instructions.
(frv_asm_output_opcode, frv_final_prescan_insn): Simplify in light
of the new meaning of frv_insn_packing_flag. Emit an mnop.p if
packing is disabled and if INSN can only issue to M1.
(call_operand): Check TARGET_LONG_CALLS.
(acc_operand, even_acc_operand, quad_acc_operand)
(accg_operand): Simplify. Don't accept pseudo registers.
(output_move_single): Handle SPR<-zero moves.
(frv_issue_rate): Make non-static. Handle FRV_CPU_{FR550,FR450,FR405}.
(frv_registers_update, frv_registers_used_p): Delete.
(frv_registers_set_p): Delete.
(frv_acc_group_1, frv_acc_group, frv_insn_unit): New functions.
(frv_issues_to_branch_unit_p): New function.
(frv_packet): New structure.
(frv_cond_flags, frv_regstate_conflict_p): New functions.
(frv_registers_conflict_p_1, frv_registers_conflict_p): New functions.
(frv_registers_update_1, frv_registers_update): New functions.
(frv_start_packet, frv_start_packet_block, frv_finish_packet)
(frv_pack_insn_p, frv_add_insn_to_packet, frv_insert_nop_in_packet)
(frv_for_each_packet, frv_sort_insn_group_1, frv_compare_insns)
(frv_sort_insn_group, frv_reorder_packet): New functions.
(frv_pack_insns): Use frv_reorder_packet.
(frv_packet_address): New variable.
(frv_fill_unused_units, frv_align_label, frv_reorg_packet)
(frv_register_nop, frv_reorg): New functions.
(bdesc_1arg): Add __SCUTSS.
(bdesc_2arg): Add __MQLCLRHS, __MQLMTHS, __SMUL, __UMUL, __ADDSS,
__SUBSS, __SLASS and __SCAN.
(bdesc_2argimm): Add __MQSLLHI and __MQSRAHI.
(bdesc_int_void2arg, bdesc_prefetches): New arrays.
(frv_init_builtins): Register the above builtins.
(frv_int_to_acc): Use ACC_MASK to check for valid accumulator
registers. Turn the referenced accumulators into global registers.
(frv_read_iacc_argument): New function.
(frv_expand_int_void2arg, frv_expand_prefetches): New functions.
(frv_split_iacc_move): New function.
(frv_expand_builtin): Handle the new builtins.
* config/frv/frv.md: Replace old schedulers with new order-independent
ones. Add schedulers for the FR405, FR450 and FR550. Describe new
packing algorithm.
(cpu): Add fr550, fr450 and fr405.
(type): Add macc, scan, cut, fnop, fscmp, fdcmp, mnop, mqlimh and
mqshift. Replace fmas with fsmadd and fmad with fdmadd. Delete m7.
(*muladd[sd]f4, *mulsub[sd]f4): Fix types.
(*cmp[sd]f_cc_fp): Use new f[sd]cmp types.
(fnop, mnop): New patterns.
(UNSPEC_MQLCLRHS, UNSPEC_MQLMTHS, UNSPEC_MQSLLHI, UNSPEC_MQSRAHI):
New constants.
(mexpdhw, *cond_exec_mexpdhw): Fix destination operands.
(mclracca8): Use ACC_MASK to determine the upper set of accumulator
registers.
(mqlclrhs, mqlmths, mqsllhi, mqsrahi): New patterns.
(UNSPEC_SMUL, UNSPEC_UMUL, UNSPEC_SMU, UNSPEC_ADDSS, UNSPEC_SUBSS)
(UNSPEC_SLASS, UNSPEC_SCAN, UNSPEC_INTSS, UNSPEC_SCUTSS)
(UNSPEC_PREFETCH0, UNSPEC_PREFETCH, UNSPEC_IACCreadll)
(UNSPEC_IACCreadl, UNSPEC_IACCsetll, UNSPEC_IACCsetl, UNSPEC_SMASS)
(UNSPEC_SMSSS, UNSPEC_IMUL, IACC0_REG): New constants.
(smul, umul, smass, smsss, smu, addss, subss, slass, scan, scutss)
(frv_prefetch0, frv_prefetch): New patterns.
* config/frv/t-frv (MULTILIB_OPTIONS): Remove -mcpu=frv and
-mcpu=simple. Add -mcpu=fr550.
(MULTILIB_DIRNAMES): Update accordingly.
(MULTILIB_MATCHES): Use the fr400 multilibs for -mcpu=fr405 and
-mcpu=fr450.
* doc/invoke.texi: Document the new -mcpu={fr550,fr450,fr405},
-mlong-calls and -malign-labels options for FR-V.
Co-Authored-By: Catherine Moore <clm@redhat.com>
From-SVN: r87222
+2004-09-09 Richard Sandiford <rsandifo@redhat.com>
+ Catherine Moore <clm@redhat.com>
+
+ * config/frv/frv-protos.h (FRV_CPU_FR550, FRV_CPU_FR450)
+ (FRV_CPU_FR405): New processor enums.
+ (frv_issue_rate, frv_acc_group): Declare.
+ * config/frv/frv.h (CPP_SPEC, CPP_FRV_SPEC, CPP_FR500_SPEC): Delete.
+ (CPP_FR400_SPEC, CPP_SIMPLE_SPEC): Delete.
+ (MASK_DEFAULT_FR550, MASK_DEFAULT_FR450): New macros.
+ (SUBTARGET_EXTRA_SPECS, EXTRA_SPECS, CPP_CPU_DEFAULT_SPEC): Delete.
+ (TARGET_CPU_CPP_BUILTINS): Define the macros that were previously
+ handled by CPP_SPEC.
+ (MASK_LONG_CALLS, TARGET_LONG_CALLS): New macros.
+ (MASK_ALIGN_LABELS, TARGET_ALIGN_LABELS): New macros.
+ (ACC_MASK): New macro.
+ (TARGET_MEDIA_REV2): Include FRV_CPU_{FR405,FR450,FR550}.
+ (TARGET_MEDIA_FR450): New macro.
+ (TARGET_FR500_FR550_BUILTINS, TARGET_FR405_BUILTINS): New macros.
+ (TARGET_SWITCHES): Add -m{no-,}align-labels and -m{no-,}long-calls.
+ (LABEL_ALIGN_AFTER_BARRIER): Define.
+ (ACC_LAST, ACCG_LAST): Add four new accumulator registers.
+ (IACC_FIRST, IACC_LAST): New pair of SPRs.
+ (ACCG_FIRST, AP_FIRST, SPR_FIRST, SPR_LAST): Adjust accordingly.
+ (FIXED_REGISTERS, CALL_USED_REGISTERS, REG_ALLOC_ORDER)
+ (REGISTER_NAMES): Add entries for new registers.
+ (REG_CLASS_CONTENTS): Update for new register ranges.
+ (EXTRA_CONSTRAINT_FOR_S): Redefine in terms of call_operand.
+ (ISSUE_RATE, CLEAR_VLIW_START, SET_VLIW_START): Delete.
+ (PACKING_FLAG_USED_P): Delete.
+ (FRV_BUILTIN_MQLCLRHS, FRV_BUILTIN_MQLMTHS, FRV_BUILTIN_MQSLLHI)
+ (FRV_BUILTIN_MQSRAHI, FRV_BUILTIN_SMUL, FRV_BUILTIN_UMUL)
+ (FRV_BUILTIN_PREFETCH0, FRV_BUILTIN_PREFETCH, FRV_BUILTIN_SMASS)
+ (FRV_BUILTIN_SMSSS, FRV_BUILTIN_SMU, FRV_BUILTIN_SCUTSS)
+ (FRV_BUILTIN_ADDSS, FRV_BUILTIN_SUBSS, FRV_BUILTIN_SLASS)
+ (FRV_BUILTIN_IACCread{l,ll}, FRV_BUILTIN_IACCset{ll,l})
+ (FRV_BUILTIN_SCAN): New members of frv_builtin_enum.
+ (FRV_BUILTIN_FIRST_NONMEDIA): New macro.
+ (CPU_UNITS_QUERY): Define to 1.
+ * config/frv/frv.c: Include gt-frv.h
+ (NUM_NOP_PATTERNS, NTH_UNIT, UNIT_NUMBER, PACKING_FLAG_P): New macros.
+ (SET_PACKING_FLAG, CLEAR_PACKING_FLAG, FOR_EACH_REGNO): New macros.
+ (frv_insn_group): New enumeration.
+ (frv_unit_names, frv_unit_groups, frv_unit_codes): New variables.
+ (frv_type_to_unit, frv_nops, frv_num_nops): New variables.
+ (REGSTATE_DEAD, REGSTATE_LIVE, REGSTATE_UNUSED, REGSTATE_MASK)
+ (REGSTATE_CONDJUMP): Delete. Shuffle other numbers to cover the
+ gap left by REGSTATE_LIVE.
+ (regstate_t): New typedef.
+ (TARGET_MACHINE_DEPENDENT_REORG): Define.
+ (frv_default_flags_for_cpu): Handle FRV_CPU_{FR550,FR450,FR405}.
+ (frv_override_options): Check for -mcpu={fr550,fr450,fr405}.
+ Initialize frv_unit_codes[] and frv_type_to_unit[].
+ (frv_conditional_register_usage): Remove redundant fixing of
+ accumulator registers.
+ (frv_insn_packing_flag): Update specification.
+ (frv_function_prologue): Don't set frv_insn_packing_flag here.
+ Zero out frv_nops[].
+ (frv_expand_epilogue): Remove comments about the no-longer-present
+ SIBCALL_P argument.
+ (frv_asm_output_mi_thunk): Check frv_issue_rate() rather than
+ PACKING_FLAG_USED_P() when deciding whether to pack instructions.
+ (frv_asm_output_opcode, frv_final_prescan_insn): Simplify in light
+ of the new meaning of frv_insn_packing_flag. Emit an mnop.p if
+ packing is disabled and if INSN can only issue to M1.
+ (call_operand): Check TARGET_LONG_CALLS.
+ (acc_operand, even_acc_operand, quad_acc_operand)
+ (accg_operand): Simplify. Don't accept pseudo registers.
+ (output_move_single): Handle SPR<-zero moves.
+ (frv_issue_rate): Make non-static. Handle FRV_CPU_{FR550,FR450,FR405}.
+ (frv_registers_update, frv_registers_used_p): Delete.
+ (frv_registers_set_p): Delete.
+ (frv_acc_group_1, frv_acc_group, frv_insn_unit): New functions.
+ (frv_issues_to_branch_unit_p): New function.
+ (frv_packet): New structure.
+ (frv_cond_flags, frv_regstate_conflict_p): New functions.
+ (frv_registers_conflict_p_1, frv_registers_conflict_p): New functions.
+ (frv_registers_update_1, frv_registers_update): New functions.
+ (frv_start_packet, frv_start_packet_block, frv_finish_packet)
+ (frv_pack_insn_p, frv_add_insn_to_packet, frv_insert_nop_in_packet)
+ (frv_for_each_packet, frv_sort_insn_group_1, frv_compare_insns)
+ (frv_sort_insn_group, frv_reorder_packet): New functions.
+ (frv_pack_insns): Use frv_reorder_packet.
+ (frv_packet_address): New variable.
+ (frv_fill_unused_units, frv_align_label, frv_reorg_packet)
+ (frv_register_nop, frv_reorg): New functions.
+ (bdesc_1arg): Add __SCUTSS.
+ (bdesc_2arg): Add __MQLCLRHS, __MQLMTHS, __SMUL, __UMUL, __ADDSS,
+ __SUBSS, __SLASS and __SCAN.
+ (bdesc_2argimm): Add __MQSLLHI and __MQSRAHI.
+ (bdesc_int_void2arg, bdesc_prefetches): New arrays.
+ (frv_init_builtins): Register the above builtins.
+ (frv_int_to_acc): Use ACC_MASK to check for valid accumulator
+ registers. Turn the referenced accumulators into global registers.
+ (frv_read_iacc_argument): New function.
+ (frv_expand_int_void2arg, frv_expand_prefetches): New functions.
+ (frv_split_iacc_move): New function.
+ (frv_expand_builtin): Handle the new builtins.
+ * config/frv/frv.md: Replace old schedulers with new order-independent
+ ones. Add schedulers for the FR405, FR450 and FR550. Describe new
+ packing algorithm.
+ (cpu): Add fr550, fr450 and fr405.
+ (type): Add macc, scan, cut, fnop, fscmp, fdcmp, mnop, mqlimh and
+ mqshift. Replace fmas with fsmadd and fmad with fdmadd. Delete m7.
+ (*muladd[sd]f4, *mulsub[sd]f4): Fix types.
+ (*cmp[sd]f_cc_fp): Use new f[sd]cmp types.
+ (fnop, mnop): New patterns.
+ (UNSPEC_MQLCLRHS, UNSPEC_MQLMTHS, UNSPEC_MQSLLHI, UNSPEC_MQSRAHI):
+ New constants.
+ (mexpdhw, *cond_exec_mexpdhw): Fix destination operands.
+ (mclracca8): Use ACC_MASK to determine the upper set of accumulator
+ registers.
+ (mqlclrhs, mqlmths, mqsllhi, mqsrahi): New patterns.
+ (UNSPEC_SMUL, UNSPEC_UMUL, UNSPEC_SMU, UNSPEC_ADDSS, UNSPEC_SUBSS)
+ (UNSPEC_SLASS, UNSPEC_SCAN, UNSPEC_INTSS, UNSPEC_SCUTSS)
+ (UNSPEC_PREFETCH0, UNSPEC_PREFETCH, UNSPEC_IACCreadll)
+ (UNSPEC_IACCreadl, UNSPEC_IACCsetll, UNSPEC_IACCsetl, UNSPEC_SMASS)
+ (UNSPEC_SMSSS, UNSPEC_IMUL, IACC0_REG): New constants.
+ (smul, umul, smass, smsss, smu, addss, subss, slass, scan, scutss)
+ (frv_prefetch0, frv_prefetch): New patterns.
+ * config/frv/t-frv (MULTILIB_OPTIONS): Remove -mcpu=frv and
+ -mcpu=simple. Add -mcpu=fr550.
+ (MULTILIB_DIRNAMES): Update accordingly.
+ (MULTILIB_MATCHES): Use the fr400 multilibs for -mcpu=fr405 and
+ -mcpu=fr450.
+ * doc/invoke.texi: Document the new -mcpu={fr550,fr450,fr405},
+ -mlong-calls and -malign-labels options for FR-V.
+
2004-09-09 Joseph S. Myers <jsm@polyomino.org.uk>
PR c/8420
typedef enum frv_cpu
{
FRV_CPU_GENERIC,
+ FRV_CPU_FR550,
FRV_CPU_FR500,
+ FRV_CPU_FR450,
+ FRV_CPU_FR405,
FRV_CPU_FR400,
FRV_CPU_FR300,
FRV_CPU_SIMPLE,
extern int direct_return_p (void);
extern int frv_register_move_cost (enum reg_class, enum reg_class);
+extern int frv_issue_rate (void);
+extern int frv_acc_group (rtx);
#ifdef TREE_CODE
extern int frv_adjust_field_align (tree, int);
#define FRV_INLINE inline
#endif
+/* The maximum number of distinct NOP patterns. There are three:
+ nop, fnop and mnop. */
+#define NUM_NOP_PATTERNS 3
+
+/* Classification of instructions and units: integer, floating-point/media,
+ branch and control. */
+enum frv_insn_group { GROUP_I, GROUP_FM, GROUP_B, GROUP_C, NUM_GROUPS };
+
+/* The DFA names of the units, in packet order. */
+static const char *const frv_unit_names[] =
+{
+ "c",
+ "i0", "f0",
+ "i1", "f1",
+ "i2", "f2",
+ "i3", "f3",
+ "b0", "b1"
+};
+
+/* The classification of each unit in frv_unit_names[]. */
+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
+};
+
+/* Return the DFA unit code associated with the Nth unit of integer
+ or floating-point group GROUP, */
+#define NTH_UNIT(GROUP, N) frv_unit_codes[(GROUP) + (N) * 2 + 1]
+
+/* Return the number of integer or floating-point unit UNIT
+ (1 for I1, 2 for F2, etc.). */
+#define UNIT_NUMBER(UNIT) (((UNIT) - 1) / 2)
+
+/* The DFA unit number for each unit in frv_unit_names[]. */
+static int frv_unit_codes[ARRAY_SIZE (frv_unit_names)];
+
+/* FRV_TYPE_TO_UNIT[T] is the last unit in frv_unit_names[] that can issue
+ an instruction of type T. The value is ARRAY_SIZE (frv_unit_names) if
+ no instruction of type T has been seen. */
+static unsigned int frv_type_to_unit[TYPE_UNKNOWN + 1];
+
+/* An array of dummy nop INSNs, one for each type of nop that the
+ target supports. */
+static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
+
+/* The number of nop instructions in frv_nops[]. */
+static unsigned int frv_num_nops;
+
+/* Return true if instruction INSN should be packed with the following
+ instruction. */
+#define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
+
+/* Set the value of PACKING_FLAG_P(INSN). */
+#define SET_PACKING_FLAG(INSN) PUT_MODE (INSN, TImode)
+#define CLEAR_PACKING_FLAG(INSN) PUT_MODE (INSN, VOIDmode)
+
+/* Loop with REG set to each hard register in rtx X. */
+#define FOR_EACH_REGNO(REG, X) \
+ for (REG = REGNO (X); \
+ REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \
+ REG++)
+
/* Information about a relocation unspec. SYMBOL is the relocation symbol
(a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
is the constant addend. */
}
frv_tmp_reg_t;
-/* Register state information for VLIW re-packing phase. These values must fit
- within an unsigned char. */
-#define REGSTATE_DEAD 0x00 /* register is currently dead */
+/* Register state information for VLIW re-packing phase. */
#define REGSTATE_CC_MASK 0x07 /* Mask to isolate CCn for cond exec */
-#define REGSTATE_LIVE 0x08 /* register is live */
-#define REGSTATE_MODIFIED 0x10 /* reg modified in current VLIW insn */
-#define REGSTATE_IF_TRUE 0x20 /* reg modified in cond exec true */
-#define REGSTATE_IF_FALSE 0x40 /* reg modified in cond exec false */
-#define REGSTATE_UNUSED 0x80 /* bit for hire */
-#define REGSTATE_MASK 0xff /* mask for the bits to set */
-
- /* conditional expression used */
+#define REGSTATE_MODIFIED 0x08 /* reg modified in current VLIW insn */
+#define REGSTATE_IF_TRUE 0x10 /* reg modified in cond exec true */
+#define REGSTATE_IF_FALSE 0x20 /* reg modified in cond exec false */
+
#define REGSTATE_IF_EITHER (REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
-/* The following is not sure in the reg_state bytes, so can have a larger value
- than 0xff. */
-#define REGSTATE_CONDJUMP 0x100 /* conditional jump done in VLIW insn */
+typedef unsigned char regstate_t;
/* Used in frv_frame_accessor_t to indicate the direction of a register-to-
memory move. */
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_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 void frv_registers_update (rtx, unsigned char [],
- int [], int *, int);
-static int frv_registers_used_p (rtx, unsigned char [], int);
-static int frv_registers_set_p (rtx, unsigned char [], int);
-static int frv_issue_rate (void);
+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);
#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;
\f
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;
void
frv_override_options (void)
{
- int regno, i;
+ int regno;
+ unsigned int i;
/* Set the cpu type. */
if (frv_cpu_string)
else
{
const char *p = frv_cpu_string + sizeof ("fr") - 1;
- if (strcmp (p, "500") == 0)
+ 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;
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;
}
for (i = FPR_FIRST + NUM_FPRS; i <= FPR_LAST; i++)
fixed_regs[i] = call_used_regs[i] = 1;
- for (i = ACC_FIRST + NUM_ACCS; i <= ACC_LAST; i++)
- fixed_regs[i] = call_used_regs[i] = 1;
-
- for (i = ACCG_FIRST + NUM_ACCS; i <= ACCG_LAST; i++)
- fixed_regs[i] = call_used_regs[i] = 1;
-
/* Reserve the registers used for conditional execution. At present, we need
1 ICC and 1 ICR register. */
fixed_regs[ICC_TEMP] = call_used_regs[ICC_TEMP] = 1;
\f
-/* The following variable value is TRUE if the next output insn should
- finish cpu cycle. In order words the insn will have packing bit
- (which means absence of asm code suffix `.p' on assembler. */
+/* Used during final to control the packing of insns. The value is
+ 1 if the current instruction should be packed with the next one,
+ 0 if it shouldn't or -1 if packing is disabled altogether. */
static int frv_insn_packing_flag;
}
frv_pack_insns ();
- frv_insn_packing_flag = TRUE;
+
+ /* Allow the garbage collector to free the nops created by frv_reorg. */
+ memset (frv_nops, 0, sizeof (frv_nops));
}
\f
it allows the scheduler to intermix instructions with the saves of
the caller saved registers. In some cases, it might be necessary
to emit a barrier instruction as the last insn to prevent such
- scheduling.
-
- If SIBCALL_P is true, the final branch back to the calling function is
- omitted, and is used for sibling call (aka tail call) sites. For sibcalls,
- we must not clobber any arguments used for parameter passing or any stack
- slots for arguments passed to the current function. */
+ scheduling. */
void
frv_expand_epilogue (bool emit_return)
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 = ((PACKING_FLAG_USED_P ()) ? ".p" : "");
+ const char *parallel = (frv_issue_rate () > 1 ? ".p" : "");
/* Do the add using an addi if possible. */
if (IN_RANGE_P (delta, -2048, 2047))
{
int c;
- if (! PACKING_FLAG_USED_P())
+ if (frv_insn_packing_flag <= 0)
return ptr;
for (; *ptr && *ptr != ' ' && *ptr != '\t';)
fputc (c, f);
}
- if (!frv_insn_packing_flag)
- fprintf (f, ".p");
+ fprintf (f, ".p");
return ptr;
}
-/* The following function sets up the packing bit for the current
- output insn. Remember that the function is not called for asm
- insns. */
+/* Set up the packing bit for the current output insn. Note that this
+ function is not called for asm insns. */
void
-frv_final_prescan_insn (rtx insn, rtx *opvec, int noperands ATTRIBUTE_UNUSED)
+frv_final_prescan_insn (rtx insn, rtx *opvec,
+ int noperands ATTRIBUTE_UNUSED)
{
- if (! PACKING_FLAG_USED_P())
- return;
-
- if (!INSN_P (insn))
- return;
-
- frv_insn_operands = opvec;
-
- /* Look for the next printable instruction. frv_pack_insns () has set
- things up so that any printable instruction will have TImode if it
- starts a new packet and VOIDmode if it should be packed with the
- previous instruction.
-
- Printable instructions will be asm_operands or match one of the .md
- patterns. Since asm instructions cannot be packed -- and will
- therefore have TImode -- this loop terminates on any recognizable
- instruction, and on any unrecognizable instruction with TImode. */
- for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
{
- if (NOTE_P (insn))
- continue;
- else if (!INSN_P (insn))
- break;
- else if (GET_MODE (insn) == TImode || INSN_CODE (insn) != -1)
- break;
+ 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)
+ /* Packing optimizations have been disabled, but INSN can only
+ be issued in M1. Insert an mnop in M0. */
+ fprintf (asm_out_file, "\tmnop.p\n");
}
-
- /* Set frv_insn_packing_flag to FALSE if the next instruction should
- be packed with this one. Set it to TRUE otherwise. If the next
- instruction is an asm instruction, this statement will set the
- flag to TRUE, and that value will still hold when the asm operands
- themselves are printed. */
- frv_insn_packing_flag = ! (insn && INSN_P (insn)
- && GET_MODE (insn) != TImode);
}
return FALSE;
if (GET_CODE (op) == SYMBOL_REF)
- return TRUE;
+ return !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);
/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
never occur anyway), but prevents reload from not handling the case
int
acc_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);
- return ACC_OR_PSEUDO_P (regno);
+ return ((mode == VOIDmode || mode == GET_MODE (op))
+ && REG_P (op) && ACC_P (REGNO (op))
+ && ((INTVAL (op) - ACC_FIRST) & ~ACC_MASK) == 0);
}
/* Return 1 if operand is a valid even ACC register number. */
int
even_acc_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);
- return (ACC_OR_PSEUDO_P (regno) && ((regno - ACC_FIRST) & 1) == 0);
+ return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0;
}
/* Return 1 if operand is zero or four. */
int
quad_acc_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);
- return (ACC_OR_PSEUDO_P (regno) && ((regno - ACC_FIRST) & 3) == 0);
+ return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
}
/* Return 1 if operand is a valid ACCG register number. */
int
accg_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 ACCG_OR_PSEUDO_P (REGNO (op));
+ return ((mode == VOIDmode || mode == GET_MODE (op))
+ && REG_P (op) && ACCG_P (REGNO (op))
+ && ((INTVAL (op) - ACCG_FIRST) & ~ACC_MASK) == 0);
}
\f
if (GPR_P (src_regno))
return "movgs %1, %0";
}
+ else if (ZERO_P (src))
+ return "movgs %., %0";
}
}
\f
/* Implement TARGET_SCHED_ISSUE_RATE. */
-static int
+int
frv_issue_rate (void)
{
if (!TARGET_PACK)
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;
}
}
\f
-/* Update the register state information, to know about which registers are set
- or clobbered. */
+/* A for_each_rtx callback. If X refers to an accumulator, return
+ ACC_GROUP_ODD if the bit 2 of the register number is set and
+ ACC_GROUP_EVEN if it is clear. Return 0 (ACC_GROUP_NONE)
+ otherwise. */
-static void
-frv_registers_update (rtx x,
- unsigned char reg_state[],
- int modified[],
- int *p_num_mod,
- int flag)
+static int
+frv_acc_group_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
{
- int regno, reg_max;
- rtx reg;
- rtx cond;
- const char *format;
- int length;
- int j;
-
- switch (GET_CODE (x))
+ if (REG_P (*x))
{
- default:
- break;
-
- /* Clobber just modifies a register, it doesn't make it live. */
- case CLOBBER:
- frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
- flag | REGSTATE_MODIFIED);
- return;
+ 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;
+}
- /* Pre modify updates the first argument, just references the second. */
- case PRE_MODIFY:
- case SET:
- frv_registers_update (XEXP (x, 0), reg_state, modified, p_num_mod,
- flag | REGSTATE_MODIFIED | REGSTATE_LIVE);
- frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod, flag);
- return;
+/* Return the value of INSN's acc_group attribute. */
- /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
- statement, but just to be sure, make sure it is the type of cond_exec
- we expect. */
- case COND_EXEC:
- cond = XEXP (x, 0);
- if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
- && GET_CODE (XEXP (cond, 0)) == REG
- && CR_P (REGNO (XEXP (cond, 0)))
- && GET_CODE (XEXP (cond, 1)) == CONST_INT
- && INTVAL (XEXP (cond, 1)) == 0
- && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
- {
- frv_registers_update (cond, reg_state, modified, p_num_mod, flag);
- flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
- | ((GET_CODE (cond) == NE)
- ? REGSTATE_IF_TRUE
- : REGSTATE_IF_FALSE));
-
- frv_registers_update (XEXP (x, 1), reg_state, modified, p_num_mod,
- flag);
- return;
- }
- else
- fatal_insn ("frv_registers_update", x);
+int
+frv_acc_group (rtx insn)
+{
+ /* This distinction only applies to the FR550 packing constraints. */
+ if (frv_cpu_type != FRV_CPU_FR550)
+ return ACC_GROUP_NONE;
+ return for_each_rtx (&PATTERN (insn), frv_acc_group_1, 0);
+}
- /* MEM resets the modification bits. */
- case MEM:
- flag &= ~REGSTATE_MODIFIED;
- break;
+/* Return the index of the DFA unit in FRV_UNIT_NAMES[] that instruction
+ INSN will try to claim first. Since this value depends only on the
+ type attribute, we can cache the results in FRV_TYPE_TO_UNIT[]. */
- /* See if we need to set the modified flag. */
- case SUBREG:
- reg = SUBREG_REG (x);
- if (GET_CODE (reg) == REG)
- {
- regno = subreg_regno (x);
- reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
- goto reg_common;
- }
- break;
+static unsigned int
+frv_insn_unit (rtx insn)
+{
+ enum attr_type type;
- case REG:
- regno = REGNO (x);
- reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- /* Fall through. */
+ type = get_attr_type (insn);
+ if (frv_type_to_unit[type] == ARRAY_SIZE (frv_unit_codes))
+ {
+ /* We haven't seen this type of instruction before. */
+ state_t state;
+ unsigned int unit;
- reg_common:
- if (flag & REGSTATE_MODIFIED)
- {
- flag &= REGSTATE_MASK;
- while (regno < reg_max)
- {
- int rs = reg_state[regno];
+ /* Issue the instruction on its own to see which unit it prefers. */
+ state = alloca (state_size ());
+ state_reset (state);
+ state_transition (state, insn);
- if (flag != rs)
- {
- if ((rs & REGSTATE_MODIFIED) == 0)
- {
- modified[ *p_num_mod ] = regno;
- (*p_num_mod)++;
- }
+ /* Find out which unit was taken. */
+ for (unit = 0; unit < ARRAY_SIZE (frv_unit_codes); unit++)
+ if (cpu_unit_reservation_p (state, frv_unit_codes[unit]))
+ break;
- /* If the previous register state had the register as
- modified, possibly in some conditional execution context,
- and the current insn modifies in some other context, or
- outside of conditional execution, just mark the variable
- as modified. */
- else
- flag &= ~(REGSTATE_IF_EITHER | REGSTATE_CC_MASK);
+ if (unit == ARRAY_SIZE (frv_unit_codes))
+ abort ();
- reg_state[regno] = (rs | flag);
- }
- regno++;
- }
- }
- return;
+ frv_type_to_unit[type] = unit;
}
+ return frv_type_to_unit[type];
+}
+/* Return true if INSN issues to a branch unit. */
- length = GET_RTX_LENGTH (GET_CODE (x));
- format = GET_RTX_FORMAT (GET_CODE (x));
+static bool
+frv_issues_to_branch_unit_p (rtx insn)
+{
+ return frv_unit_groups[frv_insn_unit (insn)] == GROUP_B;
+}
+\f
+/* The current state of the packing pass, implemented by frv_pack_insns. */
+static struct {
+ /* The state of the pipeline DFA. */
+ state_t dfa_state;
+
+ /* Which hardware registers are set within the current packet,
+ and the conditions under which they are set. */
+ regstate_t regstate[FIRST_PSEUDO_REGISTER];
+
+ /* The memory locations that have been modified so far in this
+ packet. MEM is the memref and COND is the regstate_t condition
+ under which it is set. */
+ struct {
+ rtx mem;
+ regstate_t cond;
+ } mems[2];
+
+ /* The number of valid entries in MEMS. The value is larger than
+ ARRAY_SIZE (mems) if there were too many mems to record. */
+ unsigned int num_mems;
+
+ /* The maximum number of instructions that can be packed together. */
+ unsigned int issue_rate;
+
+ /* The instructions in the packet, partitioned into groups. */
+ struct frv_packet_group {
+ /* How many instructions in the packet belong to this group. */
+ unsigned int num_insns;
+
+ /* A list of the instructions that belong to this group, in the order
+ they appear in the rtl stream. */
+ rtx insns[ARRAY_SIZE (frv_unit_codes)];
+
+ /* The contents of INSNS after they have been sorted into the correct
+ assembly-language order. Element X issues to unit X. The list may
+ contain extra nops. */
+ rtx sorted[ARRAY_SIZE (frv_unit_codes)];
+
+ /* The member of frv_nops[] to use in sorted[]. */
+ rtx nop;
+ } groups[NUM_GROUPS];
+
+ /* The instructions that make up the current packet. */
+ rtx insns[ARRAY_SIZE (frv_unit_codes)];
+ unsigned int num_insns;
+} frv_packet;
+
+/* Return the regstate_t flags for the given COND_EXEC condition.
+ Abort if the condition isn't in the right form. */
- for (j = 0; j < length; ++j)
- {
- switch (format[j])
- {
- case 'e':
- frv_registers_update (XEXP (x, j), reg_state, modified, p_num_mod,
- flag);
- break;
+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 ();
+}
- case 'V':
- case 'E':
- if (XVEC (x, j) != 0)
- {
- int k;
- for (k = 0; k < XVECLEN (x, j); ++k)
- frv_registers_update (XVECEXP (x, j, k), reg_state, modified,
- p_num_mod, flag);
- }
- break;
- default:
- /* Nothing to do. */
- break;
- }
- }
+/* Return true if something accessed under condition COND2 can
+ conflict with something written under condition COND1. */
- return;
+static bool
+frv_regstate_conflict_p (regstate_t cond1, regstate_t cond2)
+{
+ /* If either reference was unconditional, we have a conflict. */
+ if ((cond1 & REGSTATE_IF_EITHER) == 0
+ || (cond2 & REGSTATE_IF_EITHER) == 0)
+ return true;
+
+ /* The references might conflict if they were controlled by
+ different CRs. */
+ if ((cond1 & REGSTATE_CC_MASK) != (cond2 & REGSTATE_CC_MASK))
+ return true;
+
+ /* They definitely conflict if they are controlled by the
+ same condition. */
+ if ((cond1 & cond2 & REGSTATE_IF_EITHER) != 0)
+ return true;
+
+ return false;
}
-\f
-/* Return if any registers in a hard register set were used an insn. */
+
+/* A for_each_rtx callback. Return 1 if *X depends on an instruction in
+ the current packet. DATA points to a regstate_t that describes the
+ condition under which *X might be set or used. */
static int
-frv_registers_used_p (rtx x, unsigned char reg_state[], int flag)
+frv_registers_conflict_p_1 (rtx *x, void *data)
{
- int regno, reg_max;
- rtx reg;
- rtx cond;
- rtx dest;
- const char *format;
- int result;
- int length;
- int j;
+ unsigned int regno, i;
+ regstate_t cond;
- switch (GET_CODE (x))
- {
- default:
- break;
+ cond = *(regstate_t *) data;
- /* Skip clobber, that doesn't use the previous value. */
- case CLOBBER:
- return FALSE;
+ 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;
- /* For SET, if a conditional jump has occurred in the same insn, only
- allow a set of a CR register if that register is not currently live.
- This is because on the FR-V, B0/B1 instructions are always last.
- Otherwise, don't look at the result, except within a MEM, but do look
- at the source. */
- case SET:
- dest = SET_DEST (x);
- if (flag & REGSTATE_CONDJUMP
- && GET_CODE (dest) == REG && CR_P (REGNO (dest))
- && (reg_state[ REGNO (dest) ] & REGSTATE_LIVE) != 0)
- return TRUE;
+ if (GET_CODE (*x) == MEM)
+ {
+ /* If we ran out of memory slots, assume a conflict. */
+ if (frv_packet.num_mems > ARRAY_SIZE (frv_packet.mems))
+ return 1;
- if (GET_CODE (dest) == MEM)
- {
- result = frv_registers_used_p (XEXP (dest, 0), reg_state, flag);
- if (result)
- return result;
- }
+ /* Check for output or true dependencies with earlier MEMs. */
+ 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;
- return frv_registers_used_p (SET_SRC (x), reg_state, flag);
-
- /* For COND_EXEC, pass the appropriate flag to evaluate the conditional
- statement, but just to be sure, make sure it is the type of cond_exec
- we expect. */
- case COND_EXEC:
- cond = XEXP (x, 0);
- if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
- && GET_CODE (XEXP (cond, 0)) == REG
- && CR_P (REGNO (XEXP (cond, 0)))
- && GET_CODE (XEXP (cond, 1)) == CONST_INT
- && INTVAL (XEXP (cond, 1)) == 0
- && (flag & (REGSTATE_MODIFIED | REGSTATE_IF_EITHER)) == 0)
- {
- result = frv_registers_used_p (cond, reg_state, flag);
- if (result)
- return result;
+ if (output_dependence (frv_packet.mems[i].mem, *x))
+ return 1;
+ }
+ }
- flag |= ((REGNO (XEXP (cond, 0)) - CR_FIRST)
- | ((GET_CODE (cond) == NE)
- ? REGSTATE_IF_TRUE
- : REGSTATE_IF_FALSE));
+ /* The return values of calls aren't significant: they describe
+ the effect of the call as a whole, not of the insn itself. */
+ 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 frv_registers_used_p (XEXP (x, 1), reg_state, flag);
- }
- else
- fatal_insn ("frv_registers_used_p", x);
+ /* Check subexpressions. */
+ return 0;
+}
- /* See if a register or subreg was modified in the same VLIW insn. */
- case SUBREG:
- reg = SUBREG_REG (x);
- if (GET_CODE (reg) == REG)
- {
- regno = subreg_regno (x);
- reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
- goto reg_common;
- }
- break;
- case REG:
- regno = REGNO (x);
- reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- /* Fall through. */
+/* Return true if something in X might depend on an instruction
+ in the current packet. */
- reg_common:
- while (regno < reg_max)
- {
- int rs = reg_state[regno];
+static bool
+frv_registers_conflict_p (rtx x)
+{
+ regstate_t flags;
- if (rs & REGSTATE_MODIFIED)
- {
- int rs_if = rs & REGSTATE_IF_EITHER;
- int flag_if = flag & REGSTATE_IF_EITHER;
-
- /* Simple modification, no conditional execution */
- if ((rs & REGSTATE_IF_EITHER) == 0)
- return TRUE;
-
- /* See if the variable is only modified in a conditional
- execution expression opposite to the conditional execution
- expression that governs this expression (ie, true vs. false
- for the same CC register). If this isn't two halves of the
- same conditional expression, consider the register
- modified. */
- if (((rs_if == REGSTATE_IF_TRUE && flag_if == REGSTATE_IF_FALSE)
- || (rs_if == REGSTATE_IF_FALSE && flag_if == REGSTATE_IF_TRUE))
- && ((rs & REGSTATE_CC_MASK) == (flag & REGSTATE_CC_MASK)))
- ;
- else
- return TRUE;
- }
+ flags = 0;
+ if (GET_CODE (x) == COND_EXEC)
+ {
+ if (for_each_rtx (&XEXP (x, 0), frv_registers_conflict_p_1, &flags))
+ return true;
- regno++;
- }
- return FALSE;
+ flags |= frv_cond_flags (XEXP (x, 0));
+ x = XEXP (x, 1);
}
+ return for_each_rtx (&x, frv_registers_conflict_p_1, &flags);
+}
- length = GET_RTX_LENGTH (GET_CODE (x));
- format = GET_RTX_FORMAT (GET_CODE (x));
+/* A note_stores callback. DATA points to the regstate_t condition
+ under which X is modified. Update FRV_PACKET accordingly. */
- for (j = 0; j < length; ++j)
+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)
{
- switch (format[j])
+ if (frv_packet.num_mems < ARRAY_SIZE (frv_packet.mems))
{
- case 'e':
- result = frv_registers_used_p (XEXP (x, j), reg_state, flag);
- if (result != 0)
- return result;
- break;
+ frv_packet.mems[frv_packet.num_mems].mem = x;
+ frv_packet.mems[frv_packet.num_mems].cond = *(regstate_t *) data;
+ }
+ frv_packet.num_mems++;
+ }
+}
- case 'V':
- case 'E':
- if (XVEC (x, j) != 0)
- {
- int k;
- for (k = 0; k < XVECLEN (x, j); ++k)
- {
- result = frv_registers_used_p (XVECEXP (x, j, k), reg_state,
- flag);
- if (result != 0)
- return result;
- }
- }
- break;
- default:
- /* Nothing to do. */
- break;
- }
+/* Update the register state information for an instruction whose
+ body is X. */
+
+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);
+}
- return 0;
+
+/* Initialize frv_packet for the start of a new packet. */
+
+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;
}
-/* Return if any registers in a hard register set were set in an insn. */
-static int
-frv_registers_set_p (rtx x, unsigned char reg_state[], int modify_p)
+/* Likewise for the start of a new basic block. */
+
+static void
+frv_start_packet_block (void)
{
- int regno, reg_max;
- rtx reg;
- rtx cond;
- const char *format;
- int length;
- int j;
+ state_reset (frv_packet.dfa_state);
+ frv_start_packet ();
+}
- switch (GET_CODE (x))
+
+/* Finish the current packet, if any, and start a new one. Call
+ HANDLE_PACKET with FRV_PACKET describing the completed packet. */
+
+static void
+frv_finish_packet (void (*handle_packet) (void))
+{
+ if (frv_packet.num_insns > 0)
{
- default:
- break;
+ handle_packet ();
+ state_transition (frv_packet.dfa_state, 0);
+ frv_start_packet ();
+ }
+}
- case CLOBBER:
- return frv_registers_set_p (XEXP (x, 0), reg_state, TRUE);
- case PRE_MODIFY:
- case SET:
- return (frv_registers_set_p (XEXP (x, 0), reg_state, TRUE)
- || frv_registers_set_p (XEXP (x, 1), reg_state, FALSE));
-
- case COND_EXEC:
- cond = XEXP (x, 0);
- /* Just to be sure, make sure it is the type of cond_exec we
- expect. */
- if ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
- && GET_CODE (XEXP (cond, 0)) == REG
- && CR_P (REGNO (XEXP (cond, 0)))
- && GET_CODE (XEXP (cond, 1)) == CONST_INT
- && INTVAL (XEXP (cond, 1)) == 0
- && !modify_p)
- return frv_registers_set_p (XEXP (x, 1), reg_state, modify_p);
- else
- fatal_insn ("frv_registers_set_p", x);
+/* Return true if INSN can be added to the current packet. Update
+ the DFA state on success. */
- /* MEM resets the modification bits. */
- case MEM:
- modify_p = FALSE;
- break;
+static bool
+frv_pack_insn_p (rtx insn)
+{
+ /* See if the packet is already as long as it can be. */
+ if (frv_packet.num_insns == frv_packet.issue_rate)
+ return false;
- /* See if we need to set the modified modify_p. */
- case SUBREG:
- reg = SUBREG_REG (x);
- if (GET_CODE (reg) == REG)
- {
- regno = subreg_regno (x);
- reg_max = REGNO (reg) + HARD_REGNO_NREGS (regno, GET_MODE (reg));
- goto reg_common;
- }
- break;
+ /* If the scheduler thought that an instruction should start a packet,
+ it's usually a good idea to believe it. It knows much more about
+ the latencies than we do.
- case REG:
- regno = REGNO (x);
- reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- /* Fall through. */
+ There are some exceptions though:
- reg_common:
- if (modify_p)
- while (regno < reg_max)
- {
- int rs = reg_state[regno];
+ - Conditional instructions are scheduled on the assumption that
+ they will be executed. This is usually a good thing, since it
+ tends to avoid unncessary stalls in the conditional code.
+ But we want to pack conditional instructions as tightly as
+ possible, in order to optimize the case where they aren't
+ executed.
- if (rs & REGSTATE_MODIFIED)
- return TRUE;
- regno++;
- }
- return FALSE;
- }
+ - The scheduler will always put branches on their own, even
+ if there's no real dependency.
+ - There's no point putting a call in its own packet unless
+ we have to. */
+ if (frv_packet.num_insns > 0
+ && GET_CODE (insn) == INSN
+ && GET_MODE (insn) == TImode
+ && GET_CODE (PATTERN (insn)) != COND_EXEC)
+ return false;
- length = GET_RTX_LENGTH (GET_CODE (x));
- format = GET_RTX_FORMAT (GET_CODE (x));
+ /* Check for register conflicts. Don't do this for setlo since any
+ conflict will be with the partnering sethi, with which it can
+ be packed. */
+ if (get_attr_type (insn) != TYPE_SETLO)
+ if (frv_registers_conflict_p (PATTERN (insn)))
+ return false;
- for (j = 0; j < length; ++j)
- {
- switch (format[j])
- {
- case 'e':
- if (frv_registers_set_p (XEXP (x, j), reg_state, modify_p))
- return TRUE;
- break;
+ return state_transition (frv_packet.dfa_state, insn) < 0;
+}
- case 'V':
- case 'E':
- if (XVEC (x, j) != 0)
- {
- int k;
- for (k = 0; k < XVECLEN (x, j); ++k)
- if (frv_registers_set_p (XVECEXP (x, j, k), reg_state,
- modify_p))
- return TRUE;
- }
- break;
- default:
- /* Nothing to do. */
- break;
- }
- }
+/* Add instruction INSN to the current packet. */
- return FALSE;
+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));
}
-\f
-/* On the FR-V, this pass is used to rescan the insn chain, and pack
- conditional branches/calls/jumps, etc. with previous insns where it can. It
- does not reorder the instructions. We assume the scheduler left the flow
- information in a reasonable state. */
+
+/* Insert INSN (a member of frv_nops[]) into the current packet. If the
+ packet ends in a branch or call, insert the nop before it, otherwise
+ add to the end. */
static void
-frv_pack_insns (void)
+frv_insert_nop_in_packet (rtx insn)
{
- state_t frv_state; /* frv state machine */
- int cur_start_vliw_p; /* current insn starts a VLIW insn */
- int next_start_vliw_p; /* next insn starts a VLIW insn */
- int cur_condjump_p; /* flag if current insn is a cond jump*/
- int next_condjump_p; /* flag if next insn is a cond jump */
- rtx insn;
- rtx link;
- int j;
- int num_mod = 0; /* # of modified registers */
- int modified[FIRST_PSEUDO_REGISTER]; /* registers modified in current VLIW */
- /* register state information */
- unsigned char reg_state[FIRST_PSEUDO_REGISTER];
+ 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;
+}
+
- /* If we weren't going to pack the insns, don't bother with this pass. */
+/* If packing is enabled, divide the instructions into packets and
+ return true. Call HANDLE_PACKET for each complete packet. */
+
+static bool
+frv_for_each_packet (void (*handle_packet) (void))
+{
+ rtx insn, next_insn;
+
+ frv_packet.issue_rate = frv_issue_rate ();
+
+ /* Early exit if we don't want to pack insns. */
if (!optimize
|| !flag_schedule_insns_after_reload
|| TARGET_NO_VLIW_BRANCH
- || frv_issue_rate () == 1)
- return;
+ || frv_packet.issue_rate == 1)
+ return false;
- /* Set up the instruction and register states. */
+ /* Set up the initial packing state. */
dfa_start ();
- frv_state = (state_t) xmalloc (state_size ());
- memset (reg_state, REGSTATE_DEAD, sizeof (reg_state));
-
- /* Go through the insns, and repack the insns. */
- state_reset (frv_state);
- cur_start_vliw_p = FALSE;
- next_start_vliw_p = TRUE;
- cur_condjump_p = 0;
- next_condjump_p = 0;
+ frv_packet.dfa_state = alloca (state_size ());
- for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
+ frv_start_packet_block ();
+ for (insn = get_insns (); insn != 0; insn = next_insn)
{
- enum rtx_code code = GET_CODE (insn);
- enum rtx_code pattern_code;
+ enum rtx_code code;
+ bool eh_insn_p;
- /* For basic block begin notes redo the live information, and skip other
- notes. */
- if (code == NOTE)
+ code = GET_CODE (insn);
+ next_insn = NEXT_INSN (insn);
+
+ if (code == CODE_LABEL)
{
- if (NOTE_LINE_NUMBER (insn) == (int)NOTE_INSN_BASIC_BLOCK)
- {
- regset live;
+ frv_finish_packet (handle_packet);
+ frv_start_packet_block ();
+ }
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- reg_state[j] &= ~ REGSTATE_LIVE;
+ if (INSN_P (insn))
+ switch (GET_CODE (PATTERN (insn)))
+ {
+ case USE:
+ case CLOBBER:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ break;
- live = NOTE_BASIC_BLOCK (insn)->global_live_at_start;
- EXECUTE_IF_SET_IN_REG_SET(live, 0, j,
- {
- reg_state[j] |= REGSTATE_LIVE;
- });
- }
+ default:
+ /* Calls mustn't be packed on a TOMCAT. */
+ if (GET_CODE (insn) == CALL_INSN && frv_cpu_type == FRV_CPU_TOMCAT)
+ frv_finish_packet (handle_packet);
+
+ /* Since the last instruction in a packet determines the EH
+ region, any exception-throwing instruction must come at
+ the end of reordered packet. Insns that issue to a
+ branch unit are bound to come last; for others it's
+ too hard to predict. */
+ 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);
+
+ /* Finish the current packet if we can't add INSN to it.
+ Simulate cycles until INSN is ready to issue. */
+ if (!frv_pack_insn_p (insn))
+ {
+ frv_finish_packet (handle_packet);
+ while (!frv_pack_insn_p (insn))
+ state_transition (frv_packet.dfa_state, 0);
+ }
- continue;
- }
+ /* Add the instruction to the packet. */
+ frv_add_insn_to_packet (insn);
+
+ /* Calls and jumps end a packet, as do insns that throw
+ an exception. */
+ 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;
+}
+\f
+/* Subroutine of frv_sort_insn_group. We are trying to sort
+ frv_packet.groups[GROUP].sorted[0...NUM_INSNS-1] into assembly
+ language order. We have already picked a new position for
+ frv_packet.groups[GROUP].sorted[X] if bit X of ISSUED is set.
+ These instructions will occupy elements [0, LOWER_SLOT) and
+ [UPPER_SLOT, NUM_INSNS) of the final (sorted) array. STATE is
+ the DFA state after issuing these instructions.
+
+ Try filling elements [LOWER_SLOT, UPPER_SLOT) with every permutation
+ of the unused instructions. Return true if one such permutation gives
+ a valid ordering, leaving the successful permutation in sorted[].
+ Do not modify sorted[] until a valid permutation is found. */
+
+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;
+
+ /* Early success if we've filled all the slots. */
+ if (lower_slot == upper_slot)
+ return true;
+
+ packet_group = &frv_packet.groups[group];
+ dfa_size = state_size ();
+ test_state = alloca (dfa_size);
+
+ /* Try issuing each unused instruction. */
+ 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;
+}
+
+/* Compare two instructions by their frv_insn_unit. */
+
+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);
+}
+
+/* Copy frv_packet.groups[GROUP].insns[] to frv_packet.groups[GROUP].sorted[]
+ and sort it into assembly language order. See frv.md for a description of
+ the algorithm. */
+
+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];
+ if (packet_group->num_insns == 0)
+ return;
+
+ /* Copy insns[] to sorted[]. */
+ memcpy (packet_group->sorted, packet_group->insns,
+ sizeof (rtx) * packet_group->num_insns);
+
+ /* Sort sorted[] by the unit that each insn tries to take first. */
+ if (packet_group->num_insns > 1)
+ qsort (packet_group->sorted, packet_group->num_insns,
+ sizeof (rtx), frv_compare_insns);
+
+ /* That's always enough for branch and control insns. */
+ if (group == GROUP_B || group == GROUP_C)
+ return;
+
+ dfa_size = state_size ();
+ state = alloca (dfa_size);
+ test_state = alloca (dfa_size);
+
+ /* Find the highest FIRST such that sorted[0...FIRST-1] can issue
+ consecutively and such that the DFA takes unit X when sorted[X]
+ is added. Set STATE to the new DFA state. */
+ 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 all the instructions issued in ascending order, we're done. */
+ if (first == packet_group->num_insns)
+ return;
- /* Things like labels reset everything. */
- if (!INSN_P (insn))
+ /* Add nops to the end of sorted[] and try each permutation until
+ we find one that works. */
+ for (nop = 0; nop < frv_num_nops; nop++)
+ {
+ max_unit = frv_insn_unit (frv_nops[nop]);
+ if (frv_unit_groups[max_unit] == group)
{
- next_start_vliw_p = TRUE;
- continue;
+ 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 ();
+}
+\f
+/* Sort the current packet into assembly-language order. Set packing
+ flags as appropriate. */
- /* Clear the VLIW start flag on random USE and CLOBBER insns, which is
- set on the USE insn that precedes the return, and potentially on
- CLOBBERs for setting multiword variables. Also skip the ADDR_VEC
- holding the case table labels. */
- pattern_code = GET_CODE (PATTERN (insn));
- if (pattern_code == USE || pattern_code == CLOBBER
- || pattern_code == ADDR_VEC || pattern_code == ADDR_DIFF_VEC)
+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;
+
+ /* First sort each group individually. */
+ for (group = 0; group < NUM_GROUPS; group++)
+ {
+ cursor[group] = 0;
+ frv_sort_insn_group (group);
+ }
+
+ /* Go through the unit template and try add an instruction from
+ that unit's 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)
{
- CLEAR_VLIW_START (insn);
- continue;
+ /* frv_reorg should have added nops for us. */
+ if (packet_group->sorted[cursor[group]] == packet_group->nop)
+ abort ();
+ insns[to++] = packet_group->sorted[cursor[group]++];
}
+ }
- cur_start_vliw_p = next_start_vliw_p;
- next_start_vliw_p = FALSE;
+ if (to != frv_packet.num_insns)
+ abort ();
- cur_condjump_p |= next_condjump_p;
- next_condjump_p = 0;
+ /* Clear the last instruction's packing flag, thus marking the end of
+ a packet. Reorder the other instructions relative to it. */
+ 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]);
+ }
+}
- /* Unconditional branches and calls end the current VLIW insn. */
- if (code == CALL_INSN)
- {
- next_start_vliw_p = TRUE;
- /* On a TOMCAT, calls must be alone in the VLIW insns. */
- if (frv_cpu_type == FRV_CPU_TOMCAT)
- cur_start_vliw_p = TRUE;
- }
- else if (code == JUMP_INSN)
- {
- if (any_condjump_p (insn))
- next_condjump_p = REGSTATE_CONDJUMP;
- else
- next_start_vliw_p = TRUE;
- }
+/* Divide instructions into packets. Reorder the contents of each
+ packet so that they are in the correct assembly-language order.
+
+ Since this pass can change the raw meaning of the rtl stream, it must
+ only be called at the last minute, just before the instructions are
+ written out. */
+
+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;
+}
+\f
+/* See whether we need to add nops to group GROUP in order to
+ make a valid packet. */
+
+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];
+
+ /* Sort the instructions into assembly-language order.
+ Use nops to fill slots that are otherwise unused. */
+ frv_sort_insn_group (group);
+
+ /* See how many nops are needed before the final useful instruction. */
+ i = nops = 0;
+ for (non_nops = 0; non_nops < packet_group->num_insns; non_nops++)
+ while (packet_group->sorted[i++] == packet_group->nop)
+ nops++;
+
+ /* Insert that many nops into the instruction stream. */
+ while (nops-- > 0)
+ frv_insert_nop_in_packet (packet_group->nop);
+}
+
+/* Used by frv_reorg to keep track of the current packet's address. */
+static unsigned int frv_packet_address;
- /* Only allow setting a CCR register after a conditional branch. */
- else if (((cur_condjump_p & REGSTATE_CONDJUMP) != 0)
- && get_attr_type (insn) != TYPE_CCR)
- cur_start_vliw_p = TRUE;
-
- /* Determine if we need to start a new VLIW instruction. */
- if (cur_start_vliw_p
- /* Do not check for register conflicts in a setlo instruction
- because any output or true dependencies will be with the
- partnering sethi instruction, with which it can be packed.
-
- Although output dependencies are rare they are still
- possible. So check output dependencies in VLIW insn. */
- || (get_attr_type (insn) != TYPE_SETLO
- && (frv_registers_used_p (PATTERN (insn),
- reg_state,
- cur_condjump_p)
- || frv_registers_set_p (PATTERN (insn), reg_state, FALSE)))
- || state_transition (frv_state, insn) >= 0)
+/* If the current packet falls through to a label, try to pad the packet
+ with nops in order to fit the label's alignment requirements. */
+
+static void
+frv_align_label (void)
+{
+ unsigned int alignment, target, nop;
+ rtx x, last, barrier, label;
+
+ /* Walk forward to the start of the next packet. Set ALIGNMENT to the
+ maximum alignment of that packet, LABEL to the last label between
+ the packets, and BARRIER to the last barrier. */
+ 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))
{
- SET_VLIW_START (insn);
- state_reset (frv_state);
- state_transition (frv_state, insn);
- cur_condjump_p = 0;
-
- /* Update the modified registers. */
- for (j = 0; j < num_mod; j++)
- reg_state[ modified[j] ] &= ~(REGSTATE_CC_MASK
- | REGSTATE_IF_EITHER
- | REGSTATE_MODIFIED);
-
- num_mod = 0;
+ unsigned int subalign = 1 << label_to_alignment (x);
+ alignment = MAX (alignment, subalign);
+ label = x;
}
- else
- CLEAR_VLIW_START (insn);
+ if (BARRIER_P (x))
+ barrier = x;
+ }
- /* Record which registers are modified. */
- frv_registers_update (PATTERN (insn), reg_state, modified, &num_mod, 0);
+ /* If -malign-labels, and the packet falls through to an unaligned
+ label, try introducing a nop to align that label to 8 bytes. */
+ if (TARGET_ALIGN_LABELS
+ && label != 0
+ && barrier == 0
+ && frv_packet.num_insns < frv_packet.issue_rate)
+ alignment = MAX (alignment, 8);
- /* Process the death notices. */
- for (link = REG_NOTES (insn);
- link != NULL_RTX;
- link = XEXP (link, 1))
- {
- rtx reg = XEXP (link, 0);
+ /* Advance the address to the end of the current packet. */
+ frv_packet_address += frv_packet.num_insns * 4;
- if (REG_NOTE_KIND (link) == REG_DEAD && GET_CODE (reg) == REG)
- {
- int regno = REGNO (reg);
- int n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
- for (; regno < n; regno++)
- reg_state[regno] &= ~REGSTATE_LIVE;
- }
+ /* Work out the target address, after alignment. */
+ target = (frv_packet_address + alignment - 1) & -alignment;
+
+ /* If the packet falls through to the label, try to find an efficient
+ padding sequence. */
+ if (barrier == 0)
+ {
+ /* First try adding nops to the current packet. */
+ 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;
+ }
+
+ /* If we still haven't reached the target, add some new packets that
+ contain only nops. If there are two types of nop, insert an
+ alternating sequence of frv_nops[0] and frv_nops[1], which will
+ lead to packets like:
+
+ nop.p
+ mnop.p/fnop.p
+ nop.p
+ mnop/fnop
+
+ etc. Just emit frv_nops[0] if that's the only nop we have. */
+ 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;
}
}
- free (frv_state);
- dfa_finish ();
- return;
+ frv_packet_address = target;
}
+/* Subroutine of frv_reorg, called after each packet has been constructed
+ in frv_packet. */
+
+static void
+frv_reorg_packet (void)
+{
+ frv_fill_unused_units (GROUP_I);
+ frv_fill_unused_units (GROUP_FM);
+ frv_align_label ();
+}
+
+/* Add an instruction with pattern NOP to frv_nops[]. */
+
+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;
+}
+
+/* Implement TARGET_MACHINE_DEPENDENT_REORG. Divide the instructions
+ into packets and check whether we need to insert nops in order to
+ fulfill the processor's issue requirements. Also, if the user has
+ requested a certain alignment for a label, try to meet that alignment
+ by inserting nops in the previous packet. */
+
+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 ());
+
+ /* Estimate the length of each branch. Although this may change after
+ we've inserted nops, it will only do so in big functions. */
+ shorten_branches (get_insns ());
+
+ frv_packet_address = 0;
+ frv_for_each_packet (frv_reorg_packet);
+}
\f
#define def_builtin(name, type, code) \
lang_hooks.builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
{ 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_mabshs, "__MABSHS", FRV_BUILTIN_MABSHS, 0, 0 },
+ { CODE_FOR_scutss, "__SCUTSS", FRV_BUILTIN_SCUTSS, 0, 0 }
};
/* Media intrinsics that take two arguments. */
{ 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_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 }
+};
+
+/* Integer intrinsics that take two arguments and have no return value. */
+
+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 }
};
/* Media intrinsics that take two arguments, the first being an ACC number. */
{ 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_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 }
};
/* Media intrinsics that take two arguments and return void, the first argument
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))
tree uw2_ftype_acc_int = BINARY (uword2, accumulator, integer);
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 ("__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
frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
{
rtx reg;
+ int i;
+
+ /* ACCs and ACCGs are implicity global registers if media instrinsics
+ are being used. We set up this lazily to avoid creating lots of
+ unncessary call_insn rtl in non-media code. */
+ 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 (! IN_RANGE_P (INTVAL (opval), 0, NUM_ACCS - 1))
+ if ((INTVAL (opval) & ~ACC_MASK) != 0)
{
error ("accumulator number is out of bounds");
return NULL_RTX;
return expand_expr (next, NULL_RTX, VOIDmode, 0);
}
+/* Like frv_read_argument, but interpret the argument as the number
+ of an IACC register and return a (reg:MODE ...) rtx for it. */
+
+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;
+ }
+
+ /* IACCs are implicity global registers. We set up this lazily to
+ avoid creating lots of unncessary call_insn rtl when IACCs aren't
+ being used. */
+ 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);
+}
+
/* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
The instruction should require a constant operand of some sort. The
function prints an error if OPVAL is not valid. */
return 0;
}
+/* Expand builtins that take two long operands and return void. */
+
+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;
+}
+
+/* Expand prefetch builtins. These take a single address as argument. */
+
+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;
+}
+
/* Expand builtins that take three operands and return void. The first
argument must be a constant that describes a pair or quad accumulators. A
fourth argument is created that is the accumulator guard register that
return NULL_RTX;
}
+/* Emit a move from SRC to DEST in SImode chunks. This can be used
+ to move DImode values into and out of IACC0. */
+
+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));
+}
+
/* Expand builtins. */
static rtx
unsigned i;
struct builtin_description *d;
- if (! TARGET_MEDIA)
+ if (fcode < FRV_BUILTIN_FIRST_NONMEDIA && !TARGET_MEDIA)
{
error ("media functions are not available unless -mmedia is used");
return NULL_RTX;
case FRV_BUILTIN_MHDSETH:
if (! TARGET_MEDIA_REV2)
{
- error ("this media function is only available on the fr400");
+ 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;
case FRV_BUILTIN_MWTACCG:
return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
+ 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;
}
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;
}
{
return gen_rtx_REG (Pmode, FRV_STRUCT_VALUE_REGNUM);
}
+
+#include "gt-frv.h"
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "frvend%O%s"
-/* A C string constant that tells the GCC driver program options to pass to
- CPP. It can also specify how to translate options you give to GCC into
- options for GCC to pass to the CPP.
-
- Do not define this macro if it does not need to do anything. */
-
-/* The idea here is to use the -mcpu option to define macros based on the
- processor's features, using the features of the default processor if
- no -mcpu option is given. These macros can then be overridden by
- other -m options. */
-#define CPP_SPEC "\
-%{mcpu=frv: %(cpp_frv)} \
-%{mcpu=fr500: %(cpp_fr500)} \
-%{mcpu=fr400: %(cpp_fr400)} \
-%{mcpu=fr300: %(cpp_simple)} \
-%{mcpu=tomcat: %(cpp_fr500)} \
-%{mcpu=simple: %(cpp_simple)} \
-%{!mcpu*: %(cpp_cpu_default)} \
-%{mno-media: -U__FRV_ACC__ -D__FRV_ACC__=0 %{msoft-float: -U__FRV_FPR__ -D__FRV_FPR__=0}} \
-%{mhard-float: -D__FRV_HARD_FLOAT__} \
-%{msoft-float: -U__FRV_HARD_FLOAT__} \
-%{mgpr-32: -U__FRV_GPR__ -D__FRV_GPR__=32} \
-%{mgpr-64: -U__FRV_GPR__ -D__FRV_GPR__=64} \
-%{mfpr-32: -U__FRV_FPR__ -D__FRV_FPR__=32} \
-%{mfpr-64: -U__FRV_FPR__ -D__FRV_FPR__=64} \
-%{macc-4: -U__FRV_ACC__ -D__FRV_ACC__=4} \
-%{macc-8: -U__FRV_ACC__ -D__FRV_ACC__=8} \
-%{mdword: -D__FRV_DWORD__} \
-%{mno-dword: -U__FRV_DWORD__} \
-%{mno-pack: -U__FRV_VLIW__} \
-%{fleading-underscore: -D__FRV_UNDERSCORE__}"
-
-/* CPU defaults. Each CPU has its own CPP spec that defines the default
- macros for that CPU. Each CPU also has its own default target mask.
-
- CPU GPRs FPRs ACCs FPU MulAdd ldd/std Issue rate
- --- ---- ---- ---- --- ------ ------- ----------
- FRV 64 64 8 double yes yes 4
- FR500 64 64 8 single no yes 4
- FR400 32 32 4 none no yes 2
- Simple 32 0 0 none no no 1 */
-
-
-#define CPP_FRV_SPEC "\
--D__FRV_GPR__=64 \
--D__FRV_FPR__=64 \
--D__FRV_ACC__=8 \
--D__FRV_HARD_FLOAT__ \
--D__FRV_DWORD__ \
--D__FRV_VLIW__=4"
-
-#define CPP_FR500_SPEC "\
--D__FRV_GPR__=64 \
--D__FRV_FPR__=64 \
--D__FRV_ACC__=8 \
--D__FRV_HARD_FLOAT__ \
--D__FRV_DWORD__ \
--D__FRV_VLIW__=4"
-
-#define CPP_FR400_SPEC "\
--D__FRV_GPR__=32 \
--D__FRV_FPR__=32 \
--D__FRV_ACC__=4 \
--D__FRV_DWORD__ \
--D__FRV_VLIW__=2"
-
-#define CPP_SIMPLE_SPEC "\
--D__FRV_GPR__=32 \
--D__FRV_FPR__=0 \
--D__FRV_ACC__=0 \
-%{mmedia: -U__FRV_ACC__ -D__FRV_ACC__=8} \
-%{mhard-float|mmedia: -D__FRV_FPR__=64}"
#define MASK_DEFAULT_FRV \
(MASK_MEDIA \
#define MASK_DEFAULT_FR500 \
(MASK_MEDIA | MASK_DWORD | MASK_PACK)
+#define MASK_DEFAULT_FR550 \
+ (MASK_MEDIA | MASK_DWORD | MASK_PACK)
+
+#define MASK_DEFAULT_FR450 \
+ (MASK_GPR_32 \
+ | MASK_FPR_32 \
+ | MASK_MEDIA \
+ | MASK_SOFT_FLOAT \
+ | MASK_DWORD \
+ | MASK_PACK)
+
#define MASK_DEFAULT_FR400 \
(MASK_GPR_32 \
| MASK_FPR_32 \
#undef LIB_SPEC
#define LIB_SPEC "--start-group -lc -lsim --end-group"
-/* This macro defines names of additional specifications to put in the specs
- that can be used in various specifications like CC1_SPEC. Its definition
- is an initializer with a subgrouping for each command option.
-
- Each subgrouping contains a string constant, that defines the
- specification name, and a string constant that used by the GCC driver
- program.
-
- Do not define this macro if it does not need to do anything. */
-
-#ifndef SUBTARGET_EXTRA_SPECS
-#define SUBTARGET_EXTRA_SPECS
-#endif
-
-#define EXTRA_SPECS \
- { "cpp_frv", CPP_FRV_SPEC }, \
- { "cpp_fr500", CPP_FR500_SPEC }, \
- { "cpp_fr400", CPP_FR400_SPEC }, \
- { "cpp_simple", CPP_SIMPLE_SPEC }, \
- { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
- SUBTARGET_EXTRA_SPECS
-
-#ifndef CPP_CPU_DEFAULT_SPEC
-#define CPP_CPU_DEFAULT_SPEC CPP_FR500_SPEC
+#ifndef CPU_TYPE
#define CPU_TYPE FRV_CPU_FR500
#endif
/* Run-time target specifications */
-#define TARGET_CPU_CPP_BUILTINS() \
- do \
- { \
- builtin_define ("__frv__"); \
- builtin_assert ("machine=frv"); \
- \
- if (TARGET_FDPIC) \
- builtin_define ("__FRV_FDPIC__"); \
- } \
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ int issue_rate; \
+ \
+ builtin_define ("__frv__"); \
+ builtin_assert ("machine=frv"); \
+ \
+ issue_rate = frv_issue_rate (); \
+ if (issue_rate > 1) \
+ builtin_define_with_int_value ("__FRV_VLIW__", issue_rate); \
+ builtin_define_with_int_value ("__FRV_GPR__", NUM_GPRS); \
+ builtin_define_with_int_value ("__FRV_FPR__", NUM_FPRS); \
+ builtin_define_with_int_value ("__FRV_ACC__", NUM_ACCS); \
+ \
+ switch (frv_cpu_type) \
+ { \
+ case FRV_CPU_GENERIC: \
+ builtin_define ("__CPU_GENERIC__"); \
+ break; \
+ case FRV_CPU_FR550: \
+ builtin_define ("__CPU_FR550__"); \
+ break; \
+ case FRV_CPU_FR500: \
+ case FRV_CPU_TOMCAT: \
+ builtin_define ("__CPU_FR500__"); \
+ break; \
+ case FRV_CPU_FR450: \
+ builtin_define ("__CPU_FR450__"); \
+ break; \
+ case FRV_CPU_FR405: \
+ builtin_define ("__CPU_FR405__"); \
+ break; \
+ case FRV_CPU_FR400: \
+ builtin_define ("__CPU_FR400__"); \
+ break; \
+ case FRV_CPU_FR300: \
+ case FRV_CPU_SIMPLE: \
+ builtin_define ("__CPU_FR300__"); \
+ break; \
+ } \
+ \
+ if (TARGET_HARD_FLOAT) \
+ builtin_define ("__FRV_HARD_FLOAT__"); \
+ if (TARGET_DWORD) \
+ builtin_define ("__FRV_DWORD__"); \
+ if (TARGET_FDPIC) \
+ builtin_define ("__FRV_FDPIC__"); \
+ if (flag_leading_underscore > 0) \
+ builtin_define ("__FRV_UNDERSCORE__"); \
+ } \
while (0)
\f
#define MASK_LIBPIC 0x00000100 /* -fpic that can be linked w/o pic */
#define MASK_ACC_4 0x00000200 /* Only use four media accumulators */
#define MASK_PACK 0x00000400 /* Set to enable packed output */
+#define MASK_LONG_CALLS 0x00000800 /* Use indirect calls */
+#define MASK_ALIGN_LABELS 0x00001000 /* Optimize label alignments */
#define MASK_LINKED_FP 0x00002000 /* Follow ABI linkage requirements. */
/* put debug masks up high */
#define TARGET_INLINE_PLT ((target_flags & MASK_INLINE_PLT) != 0)
#define TARGET_GPREL_RO ((target_flags & MASK_GPREL_RO) != 0)
#define TARGET_PACK ((target_flags & MASK_PACK) != 0)
+#define TARGET_LONG_CALLS ((target_flags & MASK_LONG_CALLS) != 0)
+#define TARGET_ALIGN_LABELS ((target_flags & MASK_ALIGN_LABELS) != 0)
#define TARGET_LINKED_FP ((target_flags & MASK_LINKED_FP) != 0)
#define TARGET_GPR_64 (! TARGET_GPR_32)
#define NUM_FPRS (!TARGET_HAS_FPRS? 0 : TARGET_FPR_32? 32 : 64)
#define NUM_ACCS (!TARGET_MEDIA? 0 : TARGET_ACC_4? 4 : 8)
+/* X is a valid accumulator number if (X & ACC_MASK) == X. */
+#define ACC_MASK \
+ (!TARGET_MEDIA ? 0 \
+ : TARGET_ACC_4 ? 3 \
+ : frv_cpu_type == FRV_CPU_FR450 ? 11 \
+ : 7)
+
/* Macros to identify the blend of media instructions available. Revision 1
is the one found on the FR500. Revision 2 includes the changes made for
the FR400.
|| frv_cpu_type == FRV_CPU_FR500))
#define TARGET_MEDIA_REV2 \
- (TARGET_MEDIA && frv_cpu_type == FRV_CPU_FR400)
+ (TARGET_MEDIA \
+ && (frv_cpu_type == FRV_CPU_FR400 \
+ || frv_cpu_type == FRV_CPU_FR405 \
+ || frv_cpu_type == FRV_CPU_FR450 \
+ || frv_cpu_type == FRV_CPU_FR550))
+
+#define TARGET_MEDIA_FR450 \
+ (frv_cpu_type == FRV_CPU_FR450)
+
+#define TARGET_FR500_FR550_BUILTINS \
+ (frv_cpu_type == FRV_CPU_FR500 \
+ || frv_cpu_type == FRV_CPU_FR550)
+
+#define TARGET_FR405_BUILTINS \
+ (frv_cpu_type == FRV_CPU_FR405 \
+ || frv_cpu_type == FRV_CPU_FR450)
/* This macro defines names of command options to set and clear bits in
`target_flags'. Its definition is an initializer with a subgrouping for
{ "debug", MASK_DEBUG, "Internal debug switch" }, \
{ "debug-cond-exec", MASK_DEBUG_COND_EXEC, "Internal debug switch" }, \
{ "debug-loc", MASK_DEBUG_LOC, "Internal debug switch" }, \
+ { "align-labels", MASK_ALIGN_LABELS, "Enable label alignment optimizations" }, \
+ { "no-align-labels", -MASK_ALIGN_LABELS, "Disable label alignment optimizations" }, \
{ "cond-move", -MASK_NO_COND_MOVE, "Enable conditional moves" }, \
{ "no-cond-move", MASK_NO_COND_MOVE, "Disable conditional moves" }, \
{ "scc", -MASK_NO_SCC, "Enable setting gprs to the result of comparisons" }, \
{ "no-multi-cond-exec", MASK_NO_MULTI_CE, "Enable optimizing &&/|| in conditional execution" }, \
{ "nested-cond-exec", -MASK_NO_NESTED_CE, "Enable nested conditional execution optimizations" }, \
{ "no-nested-cond-exec" ,MASK_NO_NESTED_CE, "Disable nested conditional execution optimizations" }, \
+ { "long-calls", MASK_LONG_CALLS, "Disallow direct calls to global functions" }, \
+ { "no-long-calls", -MASK_LONG_CALLS, "Allow direct calls to global functions" }, \
{ "linked-fp", MASK_LINKED_FP, "Follow the EABI linkage requirements" }, \
{ "no-linked-fp", -MASK_LINKED_FP, "Don't follow the EABI linkage requirements" }, \
{ "fdpic", MASK_FDPIC, "Enable file descriptor PIC mode" }, \
#define CAN_DEBUG_WITHOUT_FP
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (TARGET_ALIGN_LABELS ? 3 : 0)
\f
/* Small Data Area Support. */
/* Maximum size of variables that go in .sdata/.sbss.
#define CR_MASK 0x3
#define ACC_FIRST 144 /* First acc register */
-#define ACC_LAST 151 /* Last acc register */
+#define ACC_LAST 155 /* Last acc register */
-#define ACCG_FIRST 152 /* First accg register */
-#define ACCG_LAST 159 /* Last accg register */
+#define ACCG_FIRST 156 /* First accg register */
+#define ACCG_LAST 167 /* Last accg register */
-#define AP_FIRST 160 /* fake argument pointer */
+#define AP_FIRST 168 /* fake argument pointer */
-#define SPR_FIRST 161
-#define SPR_LAST 162
+#define SPR_FIRST 169
+#define SPR_LAST 172
#define LR_REGNO (SPR_FIRST)
#define LCR_REGNO (SPR_FIRST + 1)
+#define IACC_FIRST (SPR_FIRST + 2)
+#define IACC_LAST (SPR_FIRST + 3)
#define GPR_P(R) IN_RANGE_P (R, GPR_FIRST, GPR_LAST)
#define GPR_OR_AP_P(R) (GPR_P (R) || (R) == ARG_POINTER_REGNUM)
0, 0, 0, 0, 0, 0, 0, 1, /* 136-143, cr0 - cr7 */ \
/* Accumulators */ \
1, 1, 1, 1, 1, 1, 1, 1, /* 144-151, acc0 - acc7 */ \
- 1, 1, 1, 1, 1, 1, 1, 1, /* 152-159, accg0 - accg7 */ \
+ 1, 1, 1, 1, /* 152-155, acc8 - acc11 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, /* 156-163, accg0 - accg7 */ \
+ 1, 1, 1, 1, /* 164-167, accg8 - accg11 */ \
/* Other registers */ \
- 1, /* 160, AP - fake arg ptr */ \
- 0, /* 161, LR - Link register*/ \
- 0, /* 162, LCR - Loop count reg*/ \
+ 1, /* 168, AP - fake arg ptr */ \
+ 0, /* 169, LR - Link register*/ \
+ 0, /* 170, LCR - Loop count reg*/ \
+ 1, 1 /* 171-172, iacc0 */ \
}
/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
1, 1, 1, 1, 1, 1, 1, 1, /* 136-143, cr0 - cr7 */ \
/* Accumulators */ \
1, 1, 1, 1, 1, 1, 1, 1, /* 144-151, acc0 - acc7 */ \
- 1, 1, 1, 1, 1, 1, 1, 1, /* 152-159, accg0 - accg7 */ \
+ 1, 1, 1, 1, /* 152-155, acc8 - acc11 */ \
+ 1, 1, 1, 1, 1, 1, 1, 1, /* 156-163, accg0 - accg7 */ \
+ 1, 1, 1, 1, /* 164-167, accg8 - accg11 */ \
/* Other registers */ \
- 1, /* 160, AP - fake arg ptr */ \
- 1, /* 161, LR - Link register*/ \
- 1, /* 162, LCR - Loop count reg */ \
+ 1, /* 168, AP - fake arg ptr */ \
+ 1, /* 169, LR - Link register*/ \
+ 1, /* 170, LCR - Loop count reg */ \
+ 1, 1 /* 171-172, iacc0 */ \
}
/* Zero or more C statements that may conditionally modify two variables
GPR_FIRST + 28, GPR_FIRST + 29, GPR_FIRST + 30, GPR_FIRST + 31, \
ACC_FIRST + 0, ACC_FIRST + 1, ACC_FIRST + 2, ACC_FIRST + 3, \
ACC_FIRST + 4, ACC_FIRST + 5, ACC_FIRST + 6, ACC_FIRST + 7, \
+ ACC_FIRST + 8, ACC_FIRST + 9, ACC_FIRST + 10, ACC_FIRST + 11, \
ACCG_FIRST + 0, ACCG_FIRST + 1, ACCG_FIRST + 2, ACCG_FIRST + 3, \
ACCG_FIRST + 4, ACCG_FIRST + 5, ACCG_FIRST + 6, ACCG_FIRST + 7, \
- AP_FIRST, LR_REGNO, LCR_REGNO \
+ ACCG_FIRST + 8, ACCG_FIRST + 9, ACCG_FIRST + 10, ACCG_FIRST + 11, \
+ AP_FIRST, LR_REGNO, LCR_REGNO, \
+ IACC_FIRST + 0, IACC_FIRST + 1 \
}
\f
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x0000f000,0x0}, /* ICR_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00000f00,0x0}, /* FCR_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x0000ff00,0x0}, /* CR_REGS */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x4}, /* LCR_REGS */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x2}, /* LR_REGS */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x400}, /* LCR_REGS */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x200}, /* LR_REGS */\
{ 0x00008000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_REGS */\
{ 0x00004000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_FPTR_REGS */\
{ 0x0000c000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_CALL_REGS */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x6}, /* SPR_REGS */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* QUAD_ACC */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* EVEN_ACC */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* ACC_REGS */\
- { 0x00000000,0x00000000,0x00000000,0x00000000,0xff000000,0x0}, /* ACCG_REGS*/\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x1e00}, /* SPR_REGS */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x0fff0000,0x0}, /* QUAD_ACC */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x0fff0000,0x0}, /* EVEN_ACC */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0x0fff0000,0x0}, /* ACC_REGS */\
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0xf0000000,0xff}, /* ACCG_REGS*/\
{ 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* QUAD_FPR */\
{ 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* FEVEN_REG*/\
{ 0x00000000,0x00000000,0xffffffff,0xffffffff,0x00000000,0x0}, /* FPR_REGS */\
{ 0x0ffffffc,0xffffffff,0x00000000,0x00000000,0x00000000,0x0}, /* QUAD_REGS*/\
{ 0xfffffffc,0xffffffff,0x00000000,0x00000000,0x00000000,0x0}, /* EVEN_REGS*/\
- { 0xffffffff,0xffffffff,0x00000000,0x00000000,0x00000000,0x1}, /* GPR_REGS */\
- { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0x7}, /* ALL_REGS */\
+ { 0xffffffff,0xffffffff,0x00000000,0x00000000,0x00000000,0x100}, /* GPR_REGS */\
+ { 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0x1fff}, /* ALL_REGS */\
}
/* A C expression whose value is a register class containing hard register
(dbl_memory_one_insn_operand (VALUE, GET_MODE (VALUE)))
/* SYMBOL_REF */
-#define EXTRA_CONSTRAINT_FOR_S(VALUE) (GET_CODE (VALUE) == SYMBOL_REF)
+#define EXTRA_CONSTRAINT_FOR_S(VALUE) \
+ (CONSTANT_P (VALUE) && call_operand (VALUE, VOIDmode))
/* Double word memory ops that take two instructions. */
#define EXTRA_CONSTRAINT_FOR_T(VALUE) \
"fcc0", "fcc1", "fcc2", "fcc3", "icc0", "icc1", "icc2", "icc3", \
"cc0", "cc1", "cc2", "cc3", "cc4", "cc5", "cc6", "cc7", \
"acc0", "acc1", "acc2", "acc3", "acc4", "acc5", "acc6", "acc7", \
+ "acc8", "acc9", "acc10", "acc11", \
"accg0","accg1","accg2","accg3","accg4","accg5","accg6","accg7", \
- "ap", "lr", "lcr" \
+ "accg8", "accg9", "accg10", "accg11", \
+ "ap", "lr", "lcr", "iacc0h", "iacc0l" \
}
/* Define this macro if you are using an unusual assembler that
/* Initialize the extra fields provided by IFCVT_EXTRA_FIELDS. */
#define IFCVT_INIT_EXTRA_FIELDS(CE_INFO) frv_ifcvt_init_extra_fields (CE_INFO)
-/* Indicate how many instructions can be issued at the same time. */
-#define ISSUE_RATE \
-(! TARGET_PACK ? 1 \
- : (frv_cpu_type == FRV_CPU_GENERIC \
- || frv_cpu_type == FRV_CPU_FR500 \
- || frv_cpu_type == FRV_CPU_TOMCAT) ? 4 \
- : frv_cpu_type == FRV_CPU_FR400 ? 2 : 1)
-
-/* Set and clear whether this insn begins a VLIW insn. */
-#define CLEAR_VLIW_START(INSN) PUT_MODE (INSN, VOIDmode)
-#define SET_VLIW_START(INSN) PUT_MODE (INSN, TImode)
-
/* The definition of the following macro results in that the 2nd jump
optimization (after the 2nd insn scheduling) is minimal. It is
necessary to define when start cycle marks of insns (TImode is used
#define MINIMAL_SECOND_JUMP_OPTIMIZATION
-/* Return true if parallel operations are expected to be emitted via the
- packing flag. */
-#define PACKING_FLAG_USED_P() \
-(optimize && flag_schedule_insns_after_reload && ISSUE_RATE > 1)
/* If the following macro is defined and nonzero and deterministic
finite state automata are used for pipeline hazard recognition, the
FRV_BUILTIN_MCPLI,
FRV_BUILTIN_MDCUTSSI,
FRV_BUILTIN_MQSATHS,
+ FRV_BUILTIN_MQLCLRHS,
+ FRV_BUILTIN_MQLMTHS,
+ FRV_BUILTIN_MQSLLHI,
+ FRV_BUILTIN_MQSRAHI,
FRV_BUILTIN_MHSETLOS,
FRV_BUILTIN_MHSETLOH,
FRV_BUILTIN_MHSETHIS,
FRV_BUILTIN_MHSETHIH,
FRV_BUILTIN_MHDSETS,
- FRV_BUILTIN_MHDSETH
+ FRV_BUILTIN_MHDSETH,
+ FRV_BUILTIN_SMUL,
+ FRV_BUILTIN_UMUL,
+ FRV_BUILTIN_PREFETCH0,
+ FRV_BUILTIN_PREFETCH,
+ FRV_BUILTIN_SMASS,
+ FRV_BUILTIN_SMSSS,
+ FRV_BUILTIN_SMU,
+ FRV_BUILTIN_SCUTSS,
+ FRV_BUILTIN_ADDSS,
+ FRV_BUILTIN_SUBSS,
+ FRV_BUILTIN_SLASS,
+ FRV_BUILTIN_IACCreadll,
+ FRV_BUILTIN_IACCreadl,
+ FRV_BUILTIN_IACCsetll,
+ FRV_BUILTIN_IACCsetl,
+ FRV_BUILTIN_SCAN
};
+#define FRV_BUILTIN_FIRST_NONMEDIA FRV_BUILTIN_SMUL
/* Enable prototypes on the call rtl functions. */
#define MD_CALL_PROTOTYPES 1
extern GTY(()) rtx frv_compare_op0; /* operand save for */
extern GTY(()) rtx frv_compare_op1; /* comparison generation */
+#define CPU_UNITS_QUERY 1
+
#ifdef __FRV_FDPIC__
#define CRT_GET_RFIB_DATA(dbase) \
({ extern void *_GLOBAL_OFFSET_TABLE_; (dbase) = &_GLOBAL_OFFSET_TABLE_; })
;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in frv-protos.h.
-(define_attr "cpu" "generic,fr500,fr400,fr300,simple,tomcat"
+(define_attr "cpu" "generic,fr550,fr500,fr450,fr405,fr400,fr300,simple,tomcat"
(const (symbol_ref "frv_cpu_type")))
;; Attribute is "yes" for branches and jumps that span too great a distance
(define_attr "far_jump" "yes,no" (const_string "no"))
;; Instruction type
-
-;; The table below summarizes the types of media instruction and their
-;; scheduling classification. Headings are:
-
-;; Type: the name of the define_attr type
-;; Conditions: "yes" if conditional variants are available
-;; FR500: Fujitsu's categorization for the FR500
-;; FR400: Fujitsu's categorization for the FR400 (but see below).
-
-;; On the FR400, media instructions are divided into 2 broad categories.
-;; Category 1 instructions can execute in either the M0 or M1 unit and can
-;; execute in parallel with other category 1 instructions. Category 2
-;; instructions must use the M0 unit, and therefore cannot run in parallel
-;; with other media instructions.
-
-;; The FR400 documentation also divides media instructions into one of seven
-;; categories (m1 to m7). m1 to m4 contain both Category 1 and Category 2
-;; instructions, so we use a combination of the categories here.
-
-;; Type Conditional FR500 FR400
-;; ---- ---------- ----- -----
-;; mlogic yes m1 m1:1
-;; mrdacc no m2 m4:1
-;; mwtacc no m3 m5:1
-;; maveh no m1 m1:1
-;; msath no m1 m1:1
-;; maddh yes m1 m1:1
-;; mqaddh yes m1 m1:2
-;; mpackh no m2 m3:1
-;; munpackh no m2 m3:2
-;; mdpackh no m5 m3:2
-;; mbhconv yes m2 m3:2
-;; mrot no m2 m3:1
-;; mshift no m2 m3:1
-;; mexpdhw yes m2 m3:1
-;; mexpdhd yes m2 m3:2
-;; mwcut no m2 m3:2
-;; mmulh yes m4 m2:1
-;; mmulxh no m4 m2:1
-;; mmach yes m4 m2:1
-;; mmrdh no m4 m2:1
-;; mqmulh yes m4 m2:2
-;; mqmulxh no m4 m2:2
-;; mqmach yes m4 m2:2
-;; mcpx yes m4 m2:1
-;; mqcpx yes m4 m2:2
-;; mcut no m2 m4:1
-;; mclracc no m3 m4:1
-;; mclracca no m6 m4:2
-;; mdunpackh no m2 n/a
-;; mbhconve no m2 n/a
-;; maddacc no n/a m2:1
-;; mdaddacc no n/a m2:2
-;; mabsh no n/a m1:1
-;; mdrot no n/a m3:2
-;; mcpl no n/a m3:2
-;; mdcut no n/a m4:2
-;; mqsath no n/a m1:2
-;; mset no n/a m1:1
-
+;; "unknown" must come last.
(define_attr "type"
- "int,sethi,setlo,mul,div,gload,gstore,fload,fstore,movfg,movgf,branch,jump,jumpl,call,spr,trap,fsconv,fsadd,fsmul,fmas,fsdiv,sqrt_single,fdconv,fdadd,fdmul,fddiv,sqrt_double,mlogic,maveh,msath,maddh,mqaddh,mpackh,munpackh,mdpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx,mcut,mclracc,mclracca,mdunpackh,mbhconve,mrdacc,mwtacc,maddacc,mdaddacc,mabsh,mdrot,mcpl,mdcut,mqsath,mset,m7,ccr,multi,unknown"
+ "int,sethi,setlo,mul,div,gload,gstore,fload,fstore,movfg,movgf,macc,scan,cut,branch,jump,jumpl,call,spr,trap,fnop,fsconv,fsadd,fscmp,fsmul,fsmadd,fsdiv,sqrt_single,fdconv,fdadd,fdcmp,fdmul,fdmadd,fddiv,sqrt_double,mnop,mlogic,maveh,msath,maddh,mqaddh,mpackh,munpackh,mdpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx,mcut,mclracc,mclracca,mdunpackh,mbhconve,mrdacc,mwtacc,maddacc,mdaddacc,mabsh,mdrot,mcpl,mdcut,mqsath,mqlimh,mqshift,mset,ccr,multi,unknown"
(const_string "unknown"))
+(define_attr "acc_group" "none,even,odd"
+ (symbol_ref "frv_acc_group (insn)"))
\f
-
-/* This is description of pipeline hazards based on DFA. The
- following constructions can be used for this:
-
- o define_cpu_unit string [string]) describes a cpu functional unit
- (separated by comma).
-
- 1st operand: Names of cpu function units.
- 2nd operand: Name of automaton (see comments for
- DEFINE_AUTOMATON).
-
- All define_reservations and define_cpu_units should have unique
- names which cannot be "nothing".
-
- o (exclusion_set string string) means that each CPU function unit
- in the first string cannot be reserved simultaneously with each
- unit whose name is in the second string and vise versa. CPU
- units in the string are separated by commas. For example, it is
- useful for description CPU with fully pipelined floating point
- functional unit which can execute simultaneously only single
- floating point insns or only double floating point insns.
-
- o (presence_set string string) means that each CPU function unit in
- the first string cannot be reserved unless at least one of units
- whose names are in the second string is reserved. This is an
- asymmetric relation. CPU units in the string are separated by
- commas. For example, it is useful for description that slot1 is
- reserved after slot0 reservation for a VLIW processor.
-
- o (absence_set string string) means that each CPU function unit in
- the first string cannot be reserved only if each unit whose name
- is in the second string is not reserved. This is an asymmetric
- relation (actually exclusion set is analogous to this one but it
- is symmetric). CPU units in the string are separated by commas.
- For example, it is useful for description that slot0 cannot be
- reserved after slot1 or slot2 reservation for a VLIW processor.
-
- o (define_bypass number out_insn_names in_insn_names) names bypass with
- given latency (the first number) from insns given by the first
- string (see define_insn_reservation) into insns given by the
- second string. Insn names in the strings are separated by
- commas.
-
- o (define_automaton string) describes names of an automaton
- generated and used for pipeline hazards recognition. The names
- are separated by comma. Actually it is possibly to generate the
- single automaton but unfortunately it can be very large. If we
- use more one automata, the summary size of the automata usually
- is less than the single one. The automaton name is used in
- define_cpu_unit. All automata should have unique names.
-
- o (define_reservation string string) names reservation (the first
- string) of cpu functional units (the 2nd string). Sometimes unit
- reservations for different insns contain common parts. In such
- case, you describe common part and use one its name (the 1st
- parameter) in regular expression in define_insn_reservation. All
- define_reservations, define results and define_cpu_units should
- have unique names which cannot be "nothing".
-
- o (define_insn_reservation name default_latency condition regexpr)
- describes reservation of cpu functional units (the 3nd operand)
- for instruction which is selected by the condition (the 2nd
- parameter). The first parameter is used for output of debugging
- information. The reservations are described by a regular
- expression according the following syntax:
-
- regexp = regexp "," oneof
- | oneof
-
- oneof = oneof "|" allof
- | allof
-
- allof = allof "+" repeat
- | repeat
-
- repeat = element "*" number
- | element
-
- element = cpu_function_name
- | reservation_name
- | result_name
- | "nothing"
- | "(" regexp ")"
-
- 1. "," is used for describing start of the next cycle in
- reservation.
-
- 2. "|" is used for describing the reservation described by the
- first regular expression *or* the reservation described by
- the second regular expression *or* etc.
-
- 3. "+" is used for describing the reservation described by the
- first regular expression *and* the reservation described by
- the second regular expression *and* etc.
-
- 4. "*" is used for convenience and simply means sequence in
- which the regular expression are repeated NUMBER times with
- cycle advancing (see ",").
-
- 5. cpu function unit name which means reservation.
-
- 6. reservation name -- see define_reservation.
-
- 7. string "nothing" means no units reservation.
-
-*/
-
-(define_automaton "nodiv, idiv, div")
-
-;; An FR500 packet can contain a single control instruction or a sequence
-;; of up to four operations matching the regular expression:
-
-;; (I FM? I? FM? | FM? FM?) B? B?
-
-;; where I denotes an integer operation, FM a floating-point or media
-;; operation, and B a branch operation. There are two units for each type
-;; of instruction: I0 and I1, FM0 and FM1, and B0 and B1. Units are
-;; allocated left-to-right: the first integer instruction uses I0, the
-;; second uses I1, and so on.
-
-;; The FR400 is similar to the FR500 except that it allows only 2 operations
-;; per packet and has only one branch unit. We can use the FR500 conflict
-;; description for the FR400, but need to define different cpu_units
-;; later.
-
-;; Slot/unit combinations available on the FR400 and above:
-(define_cpu_unit "sl0_i0, sl0_fm0, sl0_b0, sl0_c" "nodiv")
-(define_cpu_unit "sl1_fm0, sl1_i1, sl1_fm1, sl1_b0" "nodiv")
-
-;; These are available on the FR500 and above:
-(define_cpu_unit "sl1_b1" "nodiv")
-(define_cpu_unit "sl2_i1, sl2_fm1, sl2_b0, sl2_b1" "nodiv")
-(define_cpu_unit "sl3_fm1, sl3_b0, sl3_b1" "nodiv")
-
-;; The following describes conflicts by slots
-;; slot0
-(exclusion_set "sl0_i0" "sl0_fm0,sl0_b0,sl0_c")
-(exclusion_set "sl0_fm0" "sl0_b0,sl0_c")
-(exclusion_set "sl0_b0" "sl0_c")
-
-;; slot1
-(exclusion_set "sl1_fm0" "sl1_i1,sl1_fm1,sl1_b0,sl1_b1")
-(exclusion_set "sl1_i1" "sl1_fm1,sl1_b0,sl1_b1")
-(exclusion_set "sl1_fm1" "sl1_b0,sl1_b1")
-(exclusion_set "sl1_b0" "sl1_b1")
-
-;; slot2
-(exclusion_set "sl2_i1" "sl2_fm1,sl2_b0,sl2_b1")
-(exclusion_set "sl2_fm1" "sl2_b0,sl2_b1")
-(exclusion_set "sl2_b0" "sl2_b1")
-
-;; slot3
-(exclusion_set "sl3_fm1" "sl3_b0,sl3_b1")
-(exclusion_set "sl3_b0" "sl3_b1")
-
-;; The following describes conflicts by units
-;; fm0
-(exclusion_set "sl0_fm0" "sl1_fm0")
-
-;; b0
-(exclusion_set "sl0_b0" "sl1_b0,sl2_b0,sl3_b0")
-(exclusion_set "sl1_b0" "sl2_b0,sl3_b0")
-(exclusion_set "sl2_b0" "sl3_b0")
-
-;; i1
-(exclusion_set "sl1_i1" "sl2_i1")
-
-;; fm1
-(exclusion_set "sl1_fm1" "sl2_fm1,sl3_fm1")
-(exclusion_set "sl2_fm1" "sl3_fm1")
-
-;; b1
-(exclusion_set "sl1_b1" "sl2_b1,sl3_b1")
-(exclusion_set "sl2_b1" "sl3_b1")
-
-;; The following describes remaining combinations of conflicts
-;; slot0
-(exclusion_set "sl0_i0" "sl1_fm1,sl1_b1")
-(exclusion_set "sl0_fm0" "sl1_i1,sl1_b1,sl2_i1,sl2_fm1,sl3_fm1,sl3_b0")
-(exclusion_set "sl0_b0" "sl1_fm0,sl1_i1,sl1_fm1,sl2_i1,sl2_fm1,sl2_b1,\
- sl3_fm1,sl3_b1")
-(exclusion_set "sl0_c" "sl1_fm0,sl1_i1,sl1_fm1,sl1_b0,sl1_b1,sl2_i1,sl2_fm1,\
- sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
-
-
-;; slot1
-(exclusion_set "sl1_fm0" "sl2_b1")
-(exclusion_set "sl1_i1" "sl2_fm1,sl2_b1,sl3_fm1,sl3_b0")
-(exclusion_set "sl1_fm1" "sl2_i1,sl2_b1,sl3_b0")
-(exclusion_set "sl1_b0" "sl2_i1,sl2_fm1,sl3_fm1,sl3_b1")
-(exclusion_set "sl1_b1" "sl2_i1,sl2_fm1,sl2_b0,sl3_fm1,sl3_b0")
-
-;; slot2
-(exclusion_set "sl2_i1" "sl3_b1")
-(exclusion_set "sl2_fm1" "sl3_b1")
-(exclusion_set "sl2_b0" "sl3_fm1")
-(exclusion_set "sl2_b1" "sl3_fm1,sl3_b0")
-
-;; slot3
-(exclusion_set "sl1_fm0" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_fm1,sl3_b0,sl3_b1")
-(exclusion_set "sl3_fm1" "sl2_i1,sl2_fm1,sl2_b0,sl2_b1,sl3_b0,sl3_b1")
+;; Scheduling and Packing Overview
+;; -------------------------------
+;;
+;; FR-V instructions are divided into five groups: integer, floating-point,
+;; media, branch and control. Each group is associated with a separate set
+;; of processing units, the number and behavior of which depend on the target
+;; target processor. Integer units have names like I0 and I1, floating-point
+;; units have names like F0 and F1, and so on.
+;;
+;; Each member of the FR-V family has its own restrictions on which
+;; instructions can issue to which units. For example, some processors
+;; allow loads to issue to I0 or I1 while others only allow them to issue
+;; to I0. As well as these processor-specific restrictions, there is a
+;; general rule that an instruction can only issue to unit X + 1 if an
+;; instruction in the same packet issued to unit X.
+;;
+;; Sometimes the only way to honor these restrictions is by adding nops
+;; to a packet. For example, on the fr550, media instructions that access
+;; ACC4-7 can only issue to M1 or M3. It is therefore only possible to
+;; execute these instructions by packing them with something that issues
+;; to M0. When no useful M0 instruction exists, an "mnop" can be used
+;; instead.
+;;
+;; Having decided which instructions should issue to which units, the packet
+;; should be ordered according to the following template:
+;;
+;; I0 F0/M0 I1 F1/M1 .... B0 B1 ...
+;;
+;; Note that VLIW packets execute strictly in parallel. Every instruction
+;; in the packet will stall until all input operands are ready. These
+;; operands are then read simultaneously before any registers are modified.
+;; This means that it's OK to have write-after-read hazards between
+;; instructions in the same packet, even if the write is listed earlier
+;; than the read.
+;;
+;; Three gcc passes are involved in generating VLIW packets:
+;;
+;; (1) The scheduler. This pass uses the standard scheduling code and
+;; behaves in much the same way as it would for a superscalar RISC
+;; architecture.
+;;
+;; (2) frv_reorg. This pass inserts nops into packets in order to meet
+;; the processor's issue requirements. It also has code to optimize
+;; the type of padding used to align labels.
+;;
+;; (3) frv_pack_insns. The final packing phase, which puts the
+;; instructions into assembly language order according to the
+;; "I0 F0/M0 ..." template above.
+;;
+;; In the ideal case, these three passes will agree on which instructions
+;; should be packed together, but this won't always happen. In particular:
+;;
+;; (a) (2) might not pack predicated instructions in the same way as (1).
+;; The scheduler tries to schedule predicated instructions for the
+;; worst case, assuming the predicate is true. However, if we have
+;; something like a predicated load, it isn't always possible to
+;; fill the load delay with useful instructions. (2) should then
+;; pack the user of the loaded value as aggressively as possible,
+;; in order to optimize the case when the predicate is false.
+;; See frv_pack_insn_p for more details.
+;;
+;; (b) The final shorten_branches pass runs between (2) and (3).
+;; Since (2) inserts nops, it is possible that some branches
+;; that were thought to be in range during (2) turned out to
+;; out-of-range in (3).
+;;
+;; All three passes use DFAs to model issue restrictions. The main
+;; question that the DFAs are supposed to answer is simply: can these
+;; instructions be packed together? The DFAs are not responsible for
+;; assigning instructions to execution units; that's the job of
+;; frv_sort_insn_group, see below for details.
+;;
+;; To get the best results, the DFAs should try to allow packets to
+;; be built in every possible order. This gives the scheduler more
+;; flexibility, removing the need for things like multipass lookahead.
+;; It also means we can take more advantage of inter-packet dependencies.
+;;
+;; For example, suppose we're compiling for the fr400 and we have:
+;;
+;; addi gr4,#1,gr5
+;; ldi @(gr6,gr0),gr4
+;;
+;; We can pack these instructions together by assigning the load to I0 and
+;; the addition to I1. However, because of the anti dependence between the
+;; two instructions, the scheduler must schedule the addition first.
+;; We should generally get better schedules if the DFA allows both
+;; (ldi, addi) and (addi, ldi), leaving the final packing pass to
+;; reorder the packet where appropriate.
+;;
+;; Almost all integer instructions can issue to any unit in the range I0
+;; to Ix, where the value of "x" depends on the type of instruction and
+;; on the target processor. The rules for other instruction groups are
+;; usually similar.
+;;
+;; When the restrictions are as regular as this, we can get the desired
+;; behavior by claiming the DFA unit associated with the highest unused
+;; execution unit. For example, if an instruction can issue to I0 or I1,
+;; the DFA first tries to take the DFA unit associated with I1, and will
+;; only take I0's unit if I1 isn't free. (Note that, as mentioned above,
+;; the DFA does not assign instructions to units. An instruction that
+;; claims DFA unit I1 will not necessarily issue to I1 in the final packet.)
+;;
+;; There are some cases, such as the fr550 media restriction mentioned
+;; above, where the rule is not as simple as "any unit between 0 and X".
+;; Even so, allocating higher units first brings us close to the ideal.
+;;
+;; Having divided instructions into packets, passes (2) and (3) must
+;; assign instructions to specific execution units. They do this using
+;; the following algorithm:
+;;
+;; 1. Partition the instructions into groups (integer, float/media, etc.)
+;;
+;; 2. For each group of instructions:
+;;
+;; (a) Issue each instruction in the reset DFA state and use the
+;; DFA cpu_unit_query interface to find out which unit it picks
+;; first.
+;;
+;; (b) Sort the instructions into ascending order of picked units.
+;; Instructions that pick I1 first come after those that pick
+;; I0 first, and so on. Let S be the sorted sequence and S[i]
+;; be the ith element of it (counting from zero).
+;;
+;; (c) If this is the control or branch group, goto (i)
+;;
+;; (d) Find the largest L such that S[0]...S[L-1] can be issued
+;; consecutively from the reset state and such that the DFA
+;; claims unit X when S[X] is added. Let D be the DFA state
+;; after instructions S[0]...S[L-1] have been issued.
+;;
+;; (e) If L is the length of S, goto (i)
+;;
+;; (f) Let U be the number of units belonging to this group and #S be
+;; the length of S. Create a new sequence S' by concatenating
+;; S[L]...S[#S-1] and (U - #S) nops.
+;;
+;; (g) For each permutation S'' of S', try issuing S'' from last to
+;; first, starting with state D. See if the DFA claims unit
+;; X + L when each S''[X] is added. If so, set S to the
+;; concatenation of S[0]...S[L-1] and S'', then goto (i).
+;;
+;; (h) If (g) found no permuation, abort.
+;;
+;; (i) S is now the sorted sequence for this group, meaning that S[X]
+;; issues to unit X. Trim any unwanted nops from the end of S.
+;;
+;; The sequence calculated by (b) is trivially correct for control
+;; instructions since they can't be packed. It is also correct for branch
+;; instructions due to their simple issue requirements. For integer and
+;; floating-point/media instructions, the sequence calculated by (b) is
+;; often the correct answer; the rest of the algorithm is optimized for
+;; the case in which it is correct.
+;;
+;; If there were no irregularities in the issue restrictions then step
+;; (d) would not be needed. It is mainly there to cope with the fr550
+;; integer restrictions, where a store can issue to I1, but only if a store
+;; also issues to I0. (Note that if a packet has two stores, they will be
+;; at the beginning of the sequence calculated by (b).) It also copes
+;; with fr400 M-2 instructions, which must issue to M0, and which cannot
+;; be issued together with an mnop in M1.
+;;
+;; Step (g) is the main one for integer and float/media instructions.
+;; The first permutation it tries is S' itself (because, as noted above,
+;; the sequence calculated by (b) is often correct). If S' doesn't work,
+;; the implementation tries varying the beginning of the sequence first.
+;; Thus the nops towards the end of the sequence will only move to lower
+;; positions if absolutely necessary.
+;;
+;; The algorithm is theoretically exponential in the number of instructions
+;; in a group, although it's only O(n log(n)) if the sequence calculated by
+;; (b) is acceptable. In practice, the algorithm completes quickly even
+;; in the rare cases where (g) needs to try other permutations.
+(define_automaton "integer, float_media, branch, control, idiv, div")
+
+;; The main issue units. Note that not all units are available on
+;; all processors.
+(define_query_cpu_unit "i0,i1,i2,i3" "integer")
+(define_query_cpu_unit "f0,f1,f2,f3" "float_media")
+(define_query_cpu_unit "b0,b1" "branch")
+(define_query_cpu_unit "c" "control")
+
+;; Division units.
+(define_cpu_unit "idiv1,idiv2" "idiv")
+(define_cpu_unit "div1,div2,root" "div")
+
+;; Control instructions cannot be packed with others.
+(define_reservation "control" "i0+i1+i2+i3+f0+f1+f2+f3+b0+b1")
+
+;; Generic reservation for control insns
+(define_insn_reservation "control" 1
+ (eq_attr "type" "trap,spr,unknown,multi")
+ "c + control")
;; ::::::::::::::::::::
;; ::
;; ::
;; ::::::::::::::::::::
-;; Define reservation in order to describe only in terms of units.
-
-(define_reservation "i0" "sl0_i0")
-(define_reservation "f0" "sl0_fm0|sl1_fm0")
-(define_reservation "m0" "f0")
-(define_reservation "b0" "sl0_b0|sl1_b0|sl2_b0|sl3_b0")
-(define_reservation "c" "sl0_c")
-(define_reservation "i1" "sl1_i1|sl2_i1")
-(define_reservation "f1" "sl1_fm1|sl2_fm1|sl3_fm1")
-(define_reservation "m1" "f1")
-(define_reservation "b1" "sl1_b1|sl2_b1|sl3_b1")
-
;; Integer insns
-;; It is not possibly to issue load & store in one VLIW insn.
-(define_cpu_unit "idiv1" "idiv")
-(define_cpu_unit "idiv2" "idiv")
-(define_cpu_unit "l0" "nodiv")
-(define_cpu_unit "l1" "nodiv")
-(define_cpu_unit "s0" "nodiv")
-
-(exclusion_set "l1,l0" "s0")
-
-;; We set the default_latency of sethi to be 0 to allow sethi and setlo to be
-;; combined in the same VLIW instruction as allowed by the architecture. This
-;; assumes the only use of sethi is always followed by a setlo of the same
-;; register.
-(define_insn_reservation "i1_sethi" 0
+;; Synthetic units used to describe issue restrictions.
+(define_automaton "fr500_integer")
+(define_cpu_unit "fr500_load0,fr500_load1,fr500_store0" "fr500_integer")
+(exclusion_set "fr500_load0,fr500_load1" "fr500_store0")
+
+(define_bypass 0 "fr500_i1_sethi" "fr500_i1_setlo")
+(define_insn_reservation "fr500_i1_sethi" 1
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "sethi"))
- "i0|i1")
+ "i1|i0")
-(define_insn_reservation "i1_setlo" 1
+(define_insn_reservation "fr500_i1_setlo" 1
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "setlo"))
- "i0|i1")
+ "i1|i0")
-(define_insn_reservation "i1_int" 1
+(define_insn_reservation "fr500_i1_int" 1
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "int"))
- "i0|i1")
+ "i1|i0")
-(define_insn_reservation "i1_mul" 3
+(define_insn_reservation "fr500_i1_mul" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mul"))
- "i0|i1")
+ "i1|i0")
-(define_insn_reservation "i1_div" 19
+(define_insn_reservation "fr500_i1_div" 19
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "div"))
- "(i0|i1),(idiv1*18|idiv2*18)")
-
-(define_insn_reservation "i2_gload" 4
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "gload"))
- "(i0|i1)+(l0|l1)")
-
-(define_insn_reservation "i2_fload" 4
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fload"))
- "(i0|i1)+(l0|l1)")
+ "(i1|i0),(idiv1*18|idiv2*18)")
-(define_insn_reservation "i3_gstore" 0
+(define_insn_reservation "fr500_i2" 4
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "gstore"))
- "i0+s0")
+ (eq_attr "type" "gload,fload"))
+ "(i1|i0) + (fr500_load0|fr500_load1)")
-(define_insn_reservation "i3_fstore" 0
+(define_insn_reservation "fr500_i3" 0
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fstore"))
- "i0+s0")
+ (eq_attr "type" "gstore,fstore"))
+ "i0 + fr500_store0")
-(define_insn_reservation "i4_move_gf" 3
+(define_insn_reservation "fr500_i4" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "movgf"))
+ (eq_attr "type" "movgf,movfg"))
"i0")
-(define_insn_reservation "i4_move_fg" 3
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "movfg"))
- "i0")
-
-(define_insn_reservation "i5" 0
+(define_insn_reservation "fr500_i5" 0
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "jumpl"))
"i0")
-;; Clear/commit is not generated now:
-(define_insn_reservation "i6" 0 (const_int 0) "i0|i1")
-
;;
;; Branch-instructions
;;
-(define_insn_reservation "b1/b3" 0
+(define_insn_reservation "fr500_branch" 0
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "jump,branch,ccr"))
- "b0|b1")
-
-;; The following insn is not generated now.
+ "b1|b0")
-(define_insn_reservation "b2" 0 (const_int 0) "b0")
-
-(define_insn_reservation "b4" 0
+(define_insn_reservation "fr500_call" 0
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "call"))
"b0")
-;; The following insns are not generated now.
-(define_insn_reservation "b5" 0 (const_int 0) "b0|b1")
-(define_insn_reservation "b6" 0 (const_int 0) "b0|b1")
-
-;; Control insns
-(define_insn_reservation "trap" 0
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "trap"))
- "c")
+;; Floating point insns. The default latencies are for non-media
+;; instructions; media instructions incur an extra cycle.
-(define_insn_reservation "control" 0
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "spr"))
- "c")
-
-;; Floating point insns
-(define_cpu_unit "add0" "nodiv")
-(define_cpu_unit "add1" "nodiv")
-(define_cpu_unit "mul0" "nodiv")
-(define_cpu_unit "mul1" "nodiv")
-(define_cpu_unit "div1" "div")
-(define_cpu_unit "div2" "div")
-(define_cpu_unit "root" "div")
-
-(define_bypass 4 "f1" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f1" 3
+(define_bypass 4 "fr500_farith" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_insn_reservation "fr500_farith" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fsconv,fdconv"))
- "(f0|f1)")
+ (eq_attr "type" "fnop,fsconv,fsadd,fsmul,fsmadd,fdconv,fdadd,fdmul,fdmadd"))
+ "(f1|f0)")
-(define_bypass 4 "f2" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f2" 3
+(define_insn_reservation "fr500_fcmp" 4
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fsadd,fdadd"))
- "(f0|f1)+(add0|add1)")
+ (eq_attr "type" "fscmp,fdcmp"))
+ "(f1|f0)")
-(define_bypass 4 "f3" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f3" 3
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fsmul,fdmul"))
- "(f0|f1)+(mul0|mul1)")
-
-(define_bypass 11 "f4_div" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f4_div" 10
+(define_bypass 11 "fr500_fdiv" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_insn_reservation "fr500_fdiv" 10
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "fsdiv,fddiv"))
- "(f0|f1),(div1*9|div2*9)")
+ "(f1|f0),(div1*9 | div2*9)")
-(define_bypass 16 "f4_root" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f4_root" 15
+(define_bypass 16 "fr500_froot" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_insn_reservation "fr500_froot" 15
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "sqrt_single,sqrt_double"))
- "(f0|f1)+root*15")
+ "(f1|f0) + root*15")
-(define_bypass 4 "f5" "m1,m2,m3,m4,m5,m6,m7")
-(define_insn_reservation "f5" 3
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "fmas"))
- "(f0|f1)+(add0|add1)+(mul0|mul1)")
-
-;; The following insns are not generated by gcc now:
-(define_insn_reservation "f6" 0 (const_int 0) "(f0|f1)+add0+add1")
-(define_insn_reservation "f7" 0 (const_int 0) "(f0|f1)+mul0+mul1")
-
-;; Media insns. Now they are all not generated now.
-(define_cpu_unit "m1_0" "nodiv")
-(define_cpu_unit "m1_1" "nodiv")
-(define_cpu_unit "m2_0" "nodiv")
-(define_cpu_unit "m2_1" "nodiv")
-(define_cpu_unit "m3_0" "nodiv")
-(define_cpu_unit "m3_1" "nodiv")
-(define_cpu_unit "m4_0" "nodiv")
-(define_cpu_unit "m4_1" "nodiv")
-(define_cpu_unit "m5" "nodiv")
-(define_cpu_unit "m6" "nodiv")
-(define_cpu_unit "m7" "nodiv")
-
-(exclusion_set "m5,m6,m7" "m2_0,m2_1,m3_0,m3_1")
-(exclusion_set "m5" "m6,m7")
-(exclusion_set "m6" "m4_0,m4_1,m7")
-(exclusion_set "m7" "m1_0,m1_1,add0,add1,mul0,mul1")
-
-(define_bypass 2 "m1" "m1,m2,m3,m4,m5,m6,m7")
-(define_bypass 4 "m1" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
-(define_insn_reservation "m1" 3
+;; Media insns. Conflict table is as follows:
+;;
+;; M1 M2 M3 M4 M5 M6
+;; M1 - - - - - -
+;; M2 - - - - X X
+;; M3 - - - - X X
+;; M4 - - - - - X
+;; M5 - X X - X X
+;; M6 - X X X X X
+;;
+;; where X indicates an invalid combination.
+;;
+;; Target registers are as follows:
+;;
+;; M1 : FPRs
+;; M2 : FPRs
+;; M3 : ACCs
+;; M4 : ACCs
+;; M5 : FPRs
+;; M6 : ACCs
+;;
+;; The default FPR latencies are for integer instructions.
+;; Floating-point instructions need one cycle more and media
+;; instructions need one cycle less.
+(define_automaton "fr500_media")
+(define_cpu_unit "fr500_m2_0,fr500_m2_1" "fr500_media")
+(define_cpu_unit "fr500_m3_0,fr500_m3_1" "fr500_media")
+(define_cpu_unit "fr500_m4_0,fr500_m4_1" "fr500_media")
+(define_cpu_unit "fr500_m5" "fr500_media")
+(define_cpu_unit "fr500_m6" "fr500_media")
+
+(exclusion_set "fr500_m5,fr500_m6" "fr500_m2_0,fr500_m2_1,
+ fr500_m3_0,fr500_m3_1")
+(exclusion_set "fr500_m6" "fr500_m4_0,fr500_m4_1,fr500_m5")
+
+(define_bypass 2 "fr500_m1" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_bypass 4 "fr500_m1" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot")
+(define_insn_reservation "fr500_m1" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "mlogic,maveh,msath,maddh,mqaddh"))
- "(m0|m1)+(m1_0|m1_1)")
+ (eq_attr "type" "mnop,mlogic,maveh,msath,maddh,mqaddh"))
+ "(f1|f0)")
-(define_bypass 2 "m2" "m1,m2,m3,m4,m5,m6,m7")
-(define_bypass 4 "m2" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
-(define_insn_reservation "m2" 3
+(define_bypass 2 "fr500_m2" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_bypass 4 "fr500_m2" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot")
+(define_insn_reservation "fr500_m2" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mrdacc,mpackh,munpackh,mbhconv,mrot,mshift,mexpdhw,mexpdhd,mwcut,mcut,mdunpackh,mbhconve"))
- "(m0|m1)+(m2_0|m2_1)")
+ "(f1|f0) + (fr500_m2_0|fr500_m2_1)")
-(define_bypass 1 "m3" "m4")
-(define_insn_reservation "m3" 2
+(define_bypass 1 "fr500_m3" "fr500_m4")
+(define_insn_reservation "fr500_m3" 2
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mclracc,mwtacc"))
- "(m0|m1)+(m3_0|m3_1)")
+ "(f1|f0) + (fr500_m3_0|fr500_m3_1)")
-(define_bypass 1 "m4" "m4")
-(define_insn_reservation "m4" 2
+(define_bypass 1 "fr500_m4" "fr500_m4")
+(define_insn_reservation "fr500_m4" 2
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,mcpx,mqcpx"))
- "(m0|m1)+(m4_0|m4_1)")
+ "(f1|f0) + (fr500_m4_0|fr500_m4_1)")
-(define_bypass 2 "m5" "m1,m2,m3,m4,m5,m6,m7")
-(define_bypass 4 "m5" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
-(define_insn_reservation "m5" 3
+(define_bypass 2 "fr500_m5" "fr500_m1,fr500_m2,fr500_m3,
+ fr500_m4,fr500_m5,fr500_m6")
+(define_bypass 4 "fr500_m5" "fr500_farith,fr500_fcmp,fr500_fdiv,fr500_froot")
+(define_insn_reservation "fr500_m5" 3
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mdpackh"))
- "(m0|m1)+m5")
+ "(f1|f0) + fr500_m5")
-(define_bypass 1 "m6" "m4")
-(define_insn_reservation "m6" 2
+(define_bypass 1 "fr500_m6" "fr500_m4")
+(define_insn_reservation "fr500_m6" 2
(and (eq_attr "cpu" "generic,fr500,tomcat")
(eq_attr "type" "mclracca"))
- "(m0|m1)+m6")
-
-(define_bypass 2 "m7" "m1,m2,m3,m4,m5,m6,m7")
-(define_bypass 4 "m7" "f1,f2,f3,f4_div,f4_root,f5,f6,f7")
-
-(define_insn_reservation "m7" 3
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "m7"))
- "(m0|m1)+m7")
-
-;; Unknown & multi insns starts on new cycle and the next insn starts
-;; on new cycle. To describe this we consider as a control insn.
-(define_insn_reservation "unknown" 1
- (and (eq_attr "cpu" "generic,fr500,tomcat")
- (eq_attr "type" "unknown,multi"))
- "c")
+ "(f1|f0) + fr500_m6")
;; ::::::::::::::::::::
;; ::
;; with non-media instructions. Use fr400_m1unit to claim the M1 unit
;; without claiming a slot.
-(define_cpu_unit "fr400_m1unit" "nodiv")
-
-(define_reservation "fr400_i0" "sl0_i0")
-(define_reservation "fr400_i1" "sl1_i1")
-(define_reservation "fr400_m0" "sl0_fm0|sl1_fm0")
-(define_reservation "fr400_m1" "sl1_fm1")
-(define_reservation "fr400_meither" "fr400_m0|(fr400_m1+fr400_m1unit)")
-(define_reservation "fr400_mboth" "fr400_m0+fr400_m1unit")
-(define_reservation "fr400_b" "sl0_b0|sl1_b0")
-(define_reservation "fr400_c" "sl0_c")
-
;; Name Class Units Latency
;; ==== ===== ===== =======
;; int I1 I0/I1 1
;; unit too.
(define_insn_reservation "fr400_i1_int" 1
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
(eq_attr "type" "int"))
- "fr400_i0|fr400_i1")
+ "i1|i0")
-(define_insn_reservation "fr400_i1_sethi" 0
- (and (eq_attr "cpu" "fr400")
+(define_bypass 0 "fr400_i1_sethi" "fr400_i1_setlo")
+(define_insn_reservation "fr400_i1_sethi" 1
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
(eq_attr "type" "sethi"))
- "fr400_i0|fr400_i1")
+ "i1|i0")
(define_insn_reservation "fr400_i1_setlo" 1
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
(eq_attr "type" "setlo"))
- "fr400_i0|fr400_i1")
+ "i1|i0")
+;; 3 is the worst case (write-after-write hazard).
(define_insn_reservation "fr400_i1_mul" 3
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "mul"))
+ "i0")
+
+(define_insn_reservation "fr450_i1_mul" 2
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "mul"))
- "fr400_i0")
+ "i0")
+
+(define_bypass 1 "fr400_i1_macc" "fr400_i1_macc")
+(define_insn_reservation "fr400_i1_macc" 2
+ (and (eq_attr "cpu" "fr405,fr450")
+ (eq_attr "type" "macc"))
+ "i0|i1")
+
+(define_insn_reservation "fr400_i1_scan" 1
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
+ (eq_attr "type" "scan"))
+ "i0")
+
+(define_insn_reservation "fr400_i1_cut" 2
+ (and (eq_attr "cpu" "fr405,fr450")
+ (eq_attr "type" "cut"))
+ "i0")
+;; 20 is for a write-after-write hazard.
(define_insn_reservation "fr400_i1_div" 20
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "div"))
+ "i0 + idiv1*19")
+
+(define_insn_reservation "fr450_i1_div" 19
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "div"))
- "fr400_i0+idiv1*19")
+ "i0 + idiv1*19")
-(define_insn_reservation "fr400_i2_gload" 4
- (and (eq_attr "cpu" "fr400")
+;; 4 is for a write-after-write hazard.
+(define_insn_reservation "fr400_i2" 4
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "gload,fload"))
+ "i0")
+
+(define_insn_reservation "fr450_i2_gload" 3
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "gload"))
- "fr400_i0")
+ "i0")
-(define_insn_reservation "fr400_i2_fload" 4
- (and (eq_attr "cpu" "fr400")
+;; 4 is for a write-after-write hazard.
+(define_insn_reservation "fr450_i2_fload" 4
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "fload"))
- "fr400_i0")
+ "i0")
-(define_insn_reservation "fr400_i3_gstore" 0
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "gstore"))
- "fr400_i0")
+(define_insn_reservation "fr400_i3" 0
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
+ (eq_attr "type" "gstore,fstore"))
+ "i0")
-(define_insn_reservation "fr400_i3_fstore" 0
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "fstore"))
- "fr400_i0")
+;; 3 is for a write-after-write hazard.
+(define_insn_reservation "fr400_i4" 3
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "movfg,movgf"))
+ "i0")
-(define_insn_reservation "fr400_i4_movfg" 3
- (and (eq_attr "cpu" "fr400")
+(define_insn_reservation "fr450_i4_movfg" 2
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "movfg"))
- "fr400_i0")
+ "i0")
-(define_insn_reservation "fr400_i4_movgf" 3
- (and (eq_attr "cpu" "fr400")
+;; 3 is for a write-after-write hazard.
+(define_insn_reservation "fr450_i4_movgf" 3
+ (and (eq_attr "cpu" "fr450")
(eq_attr "type" "movgf"))
- "fr400_i0")
+ "i0")
-(define_insn_reservation "fr400_i5_jumpl" 0
- (and (eq_attr "cpu" "fr400")
+(define_insn_reservation "fr400_i5" 0
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
(eq_attr "type" "jumpl"))
- "fr400_i0")
+ "i0")
;; The bypass between FPR loads and media instructions, described above.
(define_bypass 3
- "fr400_i2_fload"
+ "fr400_i2"
"fr400_m1_1,fr400_m1_2,\
fr400_m2_1,fr400_m2_2,\
fr400_m3_1,fr400_m3_2,\
;; The branch instructions all use the B unit and produce no result.
(define_insn_reservation "fr400_b" 0
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405,fr450")
(eq_attr "type" "jump,branch,ccr,call"))
- "fr400_b")
-
-;; Control instructions use the C unit, which excludes all the others.
-
-(define_insn_reservation "fr400_c" 0
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "spr,trap"))
- "fr400_c")
-
-;; Unknown instructions use the C unit, since it requires single-operation
-;; packets.
-
-(define_insn_reservation "fr400_unknown" 1
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "unknown,multi"))
- "fr400_c")
+ "b0")
;; FP->FP moves are marked as "fsconv" instructions in the define_insns
;; below, but are implemented on the FR400 using "mlogic" instructions.
;; M1 instructions store their results in FPRs. Any instruction can read
;; the result in the following cycle, so no penalty occurs.
+(define_automaton "fr400_media")
+(define_cpu_unit "fr400_m1a,fr400_m1b,fr400_m2a" "fr400_media")
+(exclusion_set "fr400_m1a,fr400_m1b" "fr400_m2a")
+
+(define_reservation "fr400_m1" "(f1|f0) + (fr400_m1a|fr400_m1b)")
+(define_reservation "fr400_m2" "f0 + fr400_m2a")
+
(define_insn_reservation "fr400_m1_1" 1
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "fsconv,mlogic,maveh,msath,maddh,mabsh,mset"))
- "fr400_meither")
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "fsconv,mnop,mlogic,maveh,msath,maddh,mabsh,mset"))
+ "fr400_m1")
(define_insn_reservation "fr400_m1_2" 1
- (and (eq_attr "cpu" "fr400")
- (eq_attr "type" "mqaddh,mqsath"))
- "fr400_mboth")
+ (and (eq_attr "cpu" "fr400,fr405")
+ (eq_attr "type" "mqaddh,mqsath,mqlimh,mqshift"))
+ "fr400_m2")
;; M2 instructions store their results in accumulators, which are read
;; by M2 or M4 media commands. M2 instructions can read the results in
"fr400_m2_1,fr400_m2_2")
(define_insn_reservation "fr400_m2_1" 2
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mcpx,maddacc"))
- "fr400_meither")
+ "fr400_m1")
(define_insn_reservation "fr400_m2_2" 2
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mqmulh,mqmulxh,mqmach,mqcpx,mdaddacc"))
- "fr400_mboth")
+ "fr400_m2")
;; For our purposes, there seems to be little real difference between
;; M1 and M3 instructions. Keep them separate anyway in case the distinction
;; is needed later.
(define_insn_reservation "fr400_m3_1" 1
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mpackh,mrot,mshift,mexpdhw"))
- "fr400_meither")
+ "fr400_m1")
(define_insn_reservation "fr400_m3_2" 1
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "munpackh,mdpackh,mbhconv,mexpdhd,mwcut,mdrot,mcpl"))
- "fr400_mboth")
+ "fr400_m2")
;; M4 instructions write to accumulators or FPRs. MOVFG and STF
;; instructions can read an FPR result in the following cycle, but
;; M-unit instructions must wait a cycle more for either kind of result.
-(define_bypass 1
- "fr400_m4_1,fr400_m4_2"
- "fr400_i3_fstore,fr400_i4_movfg")
+(define_bypass 1 "fr400_m4_1,fr400_m4_2" "fr400_i3,fr400_i4")
(define_insn_reservation "fr400_m4_1" 2
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mrdacc,mcut,mclracc"))
- "fr400_meither")
+ "fr400_m1")
(define_insn_reservation "fr400_m4_2" 2
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mclracca,mdcut"))
- "fr400_mboth")
+ "fr400_m2")
;; M5 instructions always incur a 1-cycle penalty.
(define_insn_reservation "fr400_m5" 2
- (and (eq_attr "cpu" "fr400")
+ (and (eq_attr "cpu" "fr400,fr405")
(eq_attr "type" "mwtacc"))
- "fr400_mboth")
+ "fr400_m2")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: FR450 media scheduler description
+;; ::
+;; ::::::::::::::::::::
+
+;; The FR451 media restrictions are similar to the FR400's, but not as
+;; strict and not as regular. There are 6 categories with the following
+;; restrictions:
+;;
+;; M1
+;; M-1 M-2 M-3 M-4 M-5 M-6
+;; M-1: x x x
+;; M-2: x x x x x x
+;; M0 M-3: x x x
+;; M-4: x x x x
+;; M-5: x x x
+;; M-6: x x x x x x
+;;
+;; where "x" indicates a conflict.
+;;
+;; There is no difference between M-1 and M-3 as far as issue
+;; restrictions are concerned, so they are combined as "m13".
+
+;; Units for odd-numbered categories. There can be two of these
+;; in a packet.
+(define_cpu_unit "fr450_m13a,fr450_m13b" "float_media")
+(define_cpu_unit "fr450_m5a,fr450_m5b" "float_media")
+
+;; Units for even-numbered categories. There can only be one per packet.
+(define_cpu_unit "fr450_m2a,fr450_m4a,fr450_m6a" "float_media")
+
+;; Enforce the restriction matrix above.
+(exclusion_set "fr450_m2a,fr450_m4a,fr450_m6a" "fr450_m13a,fr450_m13b")
+(exclusion_set "fr450_m2a,fr450_m6a" "fr450_m5a,fr450_m5b")
+(exclusion_set "fr450_m4a,fr450_m6a" "fr450_m2a")
+
+(define_reservation "fr450_m13" "(f1|f0) + (fr450_m13a|fr450_m13b)")
+(define_reservation "fr450_m2" "f0 + fr450_m2a")
+(define_reservation "fr450_m4" "f0 + fr450_m4a")
+(define_reservation "fr450_m5" "(f1|f0) + (fr450_m5a|fr450_m5b)")
+(define_reservation "fr450_m6" "(f0|f1) + fr450_m6a")
+
+;; MD-1, MD-3 and MD-8 instructions, which are the same as far
+;; as scheduling is concerned. The inputs and outputs are FPRs.
+;; Instructions that have 32-bit inputs and outputs belong to M-1 while
+;; the rest belong to M-2.
+;;
+;; ??? Arithmetic shifts (MD-6) have an extra cycle latency, but we don't
+;; make the distinction between them and logical shifts.
+(define_insn_reservation "fr450_md138_1" 1
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "fsconv,mnop,mlogic,maveh,msath,maddh,mabsh,mset,
+ mrot,mshift,mexpdhw,mpackh"))
+ "fr450_m13")
+
+(define_insn_reservation "fr450_md138_2" 1
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mqaddh,mqsath,mqlimh,
+ mdrot,mwcut,mqshift,mexpdhd,
+ munpackh,mdpackh,mbhconv,mcpl"))
+ "fr450_m2")
+
+;; MD-2 instructions. These take FPR or ACC inputs and produce an ACC output.
+;; Instructions that write to double ACCs belong to M-3 while those that write
+;; to quad ACCs belong to M-4.
+(define_insn_reservation "fr450_md2_3" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mmulh,mmach,mcpx,mmulxh,mmrdh,maddacc"))
+ "fr450_m13")
+
+(define_insn_reservation "fr450_md2_4" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mqmulh,mqmach,mqcpx,mqmulxh,mdaddacc"))
+ "fr450_m4")
+
+;; Another MD-2 instruction can use the result on the following cycle.
+(define_bypass 1 "fr450_md2_3,fr450_md2_4" "fr450_md2_3,fr450_md2_4")
+
+;; MD-4 instructions that write to ACCs.
+(define_insn_reservation "fr450_md4_3" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mclracc"))
+ "fr450_m13")
+
+(define_insn_reservation "fr450_md4_4" 3
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mclracca"))
+ "fr450_m4")
+
+;; MD-4 instructions that write to FPRs.
+(define_insn_reservation "fr450_md4_1" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mcut"))
+ "fr450_m13")
+
+(define_insn_reservation "fr450_md4_5" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mrdacc"))
+ "fr450_m5")
+
+(define_insn_reservation "fr450_md4_6" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mdcut"))
+ "fr450_m6")
+
+;; Integer instructions can read the FPR result of an MD-4 instruction on
+;; the following cycle.
+(define_bypass 1 "fr450_md4_1,fr450_md4_5,fr450_md4_6"
+ "fr400_i3,fr450_i4_movfg")
+
+;; MD-5 instructions, which belong to M-3. They take FPR inputs and
+;; write to ACCs.
+(define_insn_reservation "fr450_md5_3" 2
+ (and (eq_attr "cpu" "fr450")
+ (eq_attr "type" "mwtacc"))
+ "fr450_m13")
+
+;; ::::::::::::::::::::
+;; ::
+;; :: FR550 scheduler description
+;; ::
+;; ::::::::::::::::::::
+
+;; Prevent loads and stores from being issued in the same packet.
+;; These units must go into the generic "integer" reservation because
+;; of the constraints on fr550_store0 and fr550_store1.
+(define_cpu_unit "fr550_load0,fr550_load1" "integer")
+(define_cpu_unit "fr550_store0,fr550_store1" "integer")
+(exclusion_set "fr550_load0,fr550_load1" "fr550_store0,fr550_store1")
+
+;; A store can only issue to I1 if one has also been issued to I0.
+(presence_set "fr550_store1" "fr550_store0")
+
+(define_bypass 0 "fr550_sethi" "fr550_setlo")
+(define_insn_reservation "fr550_sethi" 1
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "sethi"))
+ "i3|i2|i1|i0")
+
+(define_insn_reservation "fr550_setlo" 1
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "setlo"))
+ "i3|i2|i1|i0")
+
+(define_insn_reservation "fr550_int" 1
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "int"))
+ "i3|i2|i1|i0")
+
+(define_insn_reservation "fr550_mul" 2
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mul"))
+ "i1|i0")
+
+(define_insn_reservation "fr550_div" 19
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "div"))
+ "(i1|i0),(idiv1*18 | idiv2*18)")
+
+(define_insn_reservation "fr550_load" 3
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "gload,fload"))
+ "(i1|i0)+(fr550_load0|fr550_load1)")
+
+;; We can only issue a store to I1 if one was also issued to I0.
+;; This means that, as far as frv_reorder_packet is concerned,
+;; the instruction has the same priority as an I0-only instruction.
+(define_insn_reservation "fr550_store" 1
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "gstore,fstore"))
+ "(i0+fr550_store0)|(i1+fr550_store1)")
+
+(define_insn_reservation "fr550_transfer" 2
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "movgf,movfg"))
+ "i0")
+
+(define_insn_reservation "fr550_jumpl" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "jumpl"))
+ "i0")
+
+(define_cpu_unit "fr550_ccr0,fr550_ccr1" "float_media")
+
+(define_insn_reservation "fr550_branch" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "jump,branch"))
+ "b1|b0")
+
+(define_insn_reservation "fr550_ccr" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "ccr"))
+ "(b1|b0) + (fr550_ccr1|fr550_ccr0)")
+
+(define_insn_reservation "fr550_call" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "call"))
+ "b0")
+
+(define_automaton "fr550_float_media")
+(define_cpu_unit "fr550_add0,fr550_add1" "fr550_float_media")
+
+;; There are three possible combinations of floating-point/media instructions:
+;;
+;; - one media and one float
+;; - up to four float, no media
+;; - up to four media, no float
+(define_cpu_unit "fr550_f0,fr550_f1,fr550_f2,fr550_f3" "fr550_float_media")
+(define_cpu_unit "fr550_m0,fr550_m1,fr550_m2,fr550_m3" "fr550_float_media")
+(exclusion_set "fr550_f1,fr550_f2,fr550_f3" "fr550_m1,fr550_m2,fr550_m3")
+
+(define_reservation "fr550_float" "fr550_f0|fr550_f1|fr550_f2|fr550_f3")
+(define_reservation "fr550_media" "fr550_m0|fr550_m1|fr550_m2|fr550_m3")
+
+(define_insn_reservation "fr550_f1" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "fnop"))
+ "(f3|f2|f1|f0) + fr550_float")
+
+(define_insn_reservation "fr550_f2" 3
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "fsconv,fsadd,fscmp"))
+ "(f3|f2|f1|f0) + (fr550_add0|fr550_add1) + fr550_float")
+
+(define_insn_reservation "fr550_f3_mul" 3
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "fsmul"))
+ "(f1|f0) + fr550_float")
+
+(define_insn_reservation "fr550_f3_div" 10
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "fsdiv"))
+ "(f1|f0) + fr550_float")
+
+(define_insn_reservation "fr550_f3_sqrt" 15
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "sqrt_single"))
+ "(f1|f0) + fr550_float")
+
+;; Synthetic units for enforcing media issue restructions. Certain types
+;; of insn in M2 conflict with certain types in M0:
+;;
+;; M2
+;; MNOP MALU MSFT MMAC MSET
+;; MNOP - - x - -
+;; MALU - x x - -
+;; M0 MSFT - - x - x
+;; MMAC - - x x -
+;; MSET - - x - -
+;;
+;; where "x" indicates a conflict. The same restrictions apply to
+;; M3 and M1.
+;;
+;; In addition -- and this is the awkward bit! -- instructions that
+;; access ACC0-3 can only issue to M0 or M2. Those that access ACC4-7
+;; can only issue to M1 or M3. We refer to such instructions as "even"
+;; and "odd" respectively.
+(define_cpu_unit "fr550_malu0,fr550_malu1" "float_media")
+(define_cpu_unit "fr550_malu2,fr550_malu3" "float_media")
+(define_cpu_unit "fr550_msft0,fr550_msft1" "float_media")
+(define_cpu_unit "fr550_mmac0,fr550_mmac1" "float_media")
+(define_cpu_unit "fr550_mmac2,fr550_mmac3" "float_media")
+(define_cpu_unit "fr550_mset0,fr550_mset1" "float_media")
+(define_cpu_unit "fr550_mset2,fr550_mset3" "float_media")
+
+(exclusion_set "fr550_malu0" "fr550_malu2")
+(exclusion_set "fr550_malu1" "fr550_malu3")
+
+(exclusion_set "fr550_msft0" "fr550_mset2")
+(exclusion_set "fr550_msft1" "fr550_mset3")
+
+(exclusion_set "fr550_mmac0" "fr550_mmac2")
+(exclusion_set "fr550_mmac1" "fr550_mmac3")
+
+;; If an MSFT or MMAC instruction issues to a unit other than M0, we may
+;; need to insert some nops. In the worst case, the packet will end up
+;; having 4 integer instructions and 4 media instructions, leaving no
+;; room for any branch instructions that the DFA might have accepted.
+;;
+;; This doesn't matter for JUMP_INSNs and CALL_INSNs because they are
+;; always the last instructions to be passed to the DFA, and could be
+;; pushed out to a separate packet once the nops have been added.
+;; However, it does cause problems for ccr instructions since they
+;; can occur anywhere in the unordered packet.
+(exclusion_set "fr550_msft1,fr550_mmac1,fr550_mmac2,fr550_mmac3"
+ "fr550_ccr0,fr550_ccr1")
+
+(define_reservation "fr550_malu"
+ "(f3 + fr550_malu3) | (f2 + fr550_malu2)
+ | (f1 + fr550_malu1) | (f0 + fr550_malu0)")
+
+(define_reservation "fr550_msft_even"
+ "f0 + fr550_msft0")
+
+(define_reservation "fr550_msft_odd"
+ "f1 + fr550_msft1")
+
+(define_reservation "fr550_msft_either"
+ "(f1 + fr550_msft1) | (f0 + fr550_msft0)")
+
+(define_reservation "fr550_mmac_even"
+ "(f2 + fr550_mmac2) | (f0 + fr550_mmac0)")
+
+(define_reservation "fr550_mmac_odd"
+ "(f3 + fr550_mmac3) | (f1 + fr550_mmac1)")
+
+(define_reservation "fr550_mset"
+ "(f3 + fr550_mset3) | (f2 + fr550_mset2)
+ | (f1 + fr550_mset1) | (f0 + fr550_mset0)")
+
+(define_insn_reservation "fr550_mnop" 0
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mnop"))
+ "fr550_media + (f3|f2|f1|f0)")
+
+(define_insn_reservation "fr550_malu" 2
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mlogic,maveh,msath,mabsh,maddh,mqaddh,mqsath"))
+ "fr550_media + fr550_malu")
+
+;; These insns only operate on FPRs and so don't need to be classified
+;; as even/odd.
+(define_insn_reservation "fr550_msft_1_either" 2
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mrot,mwcut,mshift,mexpdhw,mexpdhd,mpackh,
+ munpackh,mdpackh,mbhconv,mdrot,mcpl"))
+ "fr550_media + fr550_msft_either")
+
+;; These insns read from ACC0-3.
+(define_insn_reservation "fr550_msft_1_even" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mcut,mrdacc,mdcut")
+ (eq_attr "acc_group" "even")))
+ "fr550_media + fr550_msft_even")
+
+;; These insns read from ACC4-7.
+(define_insn_reservation "fr550_msft_1_odd" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mcut,mrdacc,mdcut")
+ (eq_attr "acc_group" "odd")))
+ "fr550_media + fr550_msft_odd")
+
+;; MCLRACC with A=1 can issue to either M0 or M1.
+(define_insn_reservation "fr550_msft_2_either" 2
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mclracca"))
+ "fr550_media + fr550_msft_either")
+
+;; These insns write to ACC0-3.
+(define_insn_reservation "fr550_msft_2_even" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mclracc,mwtacc")
+ (eq_attr "acc_group" "even")))
+ "fr550_media + fr550_msft_even")
+
+;; These insns write to ACC4-7.
+(define_insn_reservation "fr550_msft_2_odd" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mclracc,mwtacc")
+ (eq_attr "acc_group" "odd")))
+ "fr550_media + fr550_msft_odd")
+
+;; These insns read from and write to ACC0-3.
+(define_insn_reservation "fr550_mmac_even" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,
+ maddacc,mdaddacc,mcpx,mqcpx")
+ (eq_attr "acc_group" "even")))
+ "fr550_media + fr550_mmac_even")
+
+;; These insns read from and write to ACC4-7.
+(define_insn_reservation "fr550_mmac_odd" 2
+ (and (eq_attr "cpu" "fr550")
+ (and (eq_attr "type" "mmulh,mmulxh,mmach,mmrdh,mqmulh,mqmulxh,mqmach,
+ maddacc,mdaddacc,mcpx,mqcpx")
+ (eq_attr "acc_group" "odd")))
+ "fr550_media + fr550_mmac_odd")
+
+(define_insn_reservation "fr550_mset" 1
+ (and (eq_attr "cpu" "fr550")
+ (eq_attr "type" "mset"))
+ "fr550_media + fr550_mset")
;; ::::::::::::::::::::
;; ::
(define_insn_reservation "fr300_lat1" 1
(and (eq_attr "cpu" "fr300,simple")
(eq_attr "type" "!gload,fload,movfg,movgf"))
- "c")
+ "c + control")
(define_insn_reservation "fr300_lat2" 2
(and (eq_attr "cpu" "fr300,simple")
(eq_attr "type" "gload,fload,movfg,movgf"))
- "c")
+ "c + control")
\f
;; ::::::::::::::::::::
"TARGET_HARD_FLOAT && TARGET_MULADD"
"fmadds %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fmas")])
+ (set_attr "type" "fsmadd")])
(define_insn "*mulsubsf4"
[(set (match_operand:SF 0 "fpr_operand" "=f")
"TARGET_HARD_FLOAT && TARGET_MULADD"
"fmsubs %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fmas")])
+ (set_attr "type" "fsmadd")])
;; Division
(define_insn "divsf3"
"TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD"
"fmaddd %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fmas")])
+ (set_attr "type" "fdmadd")])
(define_insn "*mulsubdf4"
[(set (match_operand:DF 0 "fpr_operand" "=f")
"TARGET_HARD_FLOAT && TARGET_DOUBLE && TARGET_MULADD"
"fmsubd %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fmas")])
+ (set_attr "type" "fdmadd")])
;; Division
(define_insn "divdf3"
"TARGET_HARD_FLOAT"
"fcmps %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fsadd")])
+ (set_attr "type" "fscmp")])
(define_insn "*cmpdf_cc_fp"
[(set (match_operand:CC_FP 0 "fcc_operand" "=u")
"TARGET_HARD_FLOAT && TARGET_DOUBLE"
"fcmpd %1,%2,%0"
[(set_attr "length" "4")
- (set_attr "type" "fdadd")])
+ (set_attr "type" "fdcmp")])
\f
;; ::::::::::::::::::::
[(set_attr "length" "4")
(set_attr "type" "int")])
+(define_insn "fnop"
+ [(const_int 1)]
+ ""
+ "fnop"
+ [(set_attr "length" "4")
+ (set_attr "type" "fnop")])
+
+(define_insn "mnop"
+ [(const_int 2)]
+ ""
+ "mnop"
+ [(set_attr "length" "4")
+ (set_attr "type" "mnop")])
+
;; Pseudo instruction that prevents the scheduler from moving code above this
;; point. Note, type unknown is used to make sure the VLIW instructions are
;; not continued past this point.
(UNSPEC_MHSETHIH 151)
(UNSPEC_MHDSETS 152)
(UNSPEC_MHDSETH 153)
+ (UNSPEC_MQLCLRHS 154)
+ (UNSPEC_MQLMTHS 155)
+ (UNSPEC_MQSLLHI 156)
+ (UNSPEC_MQSRAHI 157)
])
;; Logic operations: type "mlogic"
;; Expand halfword to word: type "mexpdhw"
(define_insn "mexpdhw"
- [(set (match_operand:SI 0 "even_fpr_operand" "=h")
+ [(set (match_operand:SI 0 "fpr_operand" "=f")
(unspec:SI [(match_operand:SI 1 "fpr_operand" "f")
(match_operand:SI 2 "uint1_operand" "I")]
UNSPEC_MEXPDHW))]
(match_operator 0 "ccr_eqne_operator"
[(match_operand 1 "cr_operand" "C")
(const_int 0)])
- (set (match_operand:SI 2 "even_fpr_operand" "=h")
+ (set (match_operand:SI 2 "fpr_operand" "=f")
(unspec:SI [(match_operand:SI 3 "fpr_operand" "f")
(match_operand:SI 4 "uint1_operand" "I")]
UNSPEC_MEXPDHW)))]
"
{
operands[0] = gen_rtx_REG (V4SImode, ACC_FIRST);
- operands[1] = gen_rtx_REG (V4SImode, ACC_FIRST + 4);
+ operands[1] = gen_rtx_REG (V4SImode, ACC_FIRST + (~3 & ACC_MASK));
operands[2] = gen_rtx_REG (V4QImode, ACCG_FIRST);
- operands[3] = gen_rtx_REG (V4QImode, ACCG_FIRST + 4);
+ operands[3] = gen_rtx_REG (V4QImode, ACCG_FIRST + (~3 & ACC_MASK));
}")
(define_expand "mclracca4"
[(set_attr "length" "4")
(set_attr "type" "mqsath")])
+;; Quad limit instructions: type "mqlimh"
+
+(define_insn "mqlclrhs"
+ [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+ (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+ (match_operand:DI 2 "even_fpr_operand" "h")]
+ UNSPEC_MQLCLRHS))]
+ "TARGET_MEDIA_FR450"
+ "mqlclrhs %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mqlimh")])
+
+(define_insn "mqlmths"
+ [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+ (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+ (match_operand:DI 2 "even_fpr_operand" "h")]
+ UNSPEC_MQLMTHS))]
+ "TARGET_MEDIA_FR450"
+ "mqlmths %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mqlimh")])
+
+(define_insn "mqsllhi"
+ [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+ (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+ (match_operand:SI 2 "int6_operand" "I")]
+ UNSPEC_MQSLLHI))]
+ "TARGET_MEDIA_FR450"
+ "mqsllhi %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mqshift")])
+
+(define_insn "mqsrahi"
+ [(set (match_operand:DI 0 "even_fpr_operand" "=h")
+ (unspec:DI [(match_operand:DI 1 "even_fpr_operand" "h")
+ (match_operand:SI 2 "int6_operand" "I")]
+ UNSPEC_MQSRAHI))]
+ "TARGET_MEDIA_FR450"
+ "mqsrahi %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mqshift")])
+
;; Set hi/lo instructions: type "mset"
(define_insn "mhsetlos"
DONE;
}")
+\f
+(define_constants
+ [
+ (UNSPEC_SMUL 154)
+ (UNSPEC_UMUL 155)
+ (UNSPEC_SMU 156)
+ (UNSPEC_ADDSS 157)
+ (UNSPEC_SUBSS 158)
+ (UNSPEC_SLASS 159)
+ (UNSPEC_SCAN 160)
+ (UNSPEC_INTSS 161)
+ (UNSPEC_SCUTSS 162)
+ (UNSPEC_PREFETCH0 163)
+ (UNSPEC_PREFETCH 164)
+ (UNSPEC_IACCreadll 165)
+ (UNSPEC_IACCreadl 166)
+ (UNSPEC_IACCsetll 167)
+ (UNSPEC_IACCsetl 168)
+ (UNSPEC_SMASS 169)
+ (UNSPEC_SMSSS 170)
+ (UNSPEC_IMUL 171)
+
+ (IACC0_REG 171)
+])
+
+(define_insn "smul"
+ [(set (match_operand:DI 0 "integer_register_operand" "=d")
+ (unspec:DI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_SMUL))]
+ ""
+ "smul %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mul")])
+
+(define_insn "umul"
+ [(set (match_operand:DI 0 "integer_register_operand" "=d")
+ (unspec:DI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_UMUL))]
+ ""
+ "umul %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "mul")])
+
+(define_insn "smass"
+ [(set (reg:DI IACC0_REG)
+ (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d")
+ (match_operand:SI 1 "integer_register_operand" "d")
+ (reg:DI IACC0_REG)]
+ UNSPEC_SMASS))]
+ "TARGET_FR405_BUILTINS"
+ "smass %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "macc")])
+
+(define_insn "smsss"
+ [(set (reg:DI IACC0_REG)
+ (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d")
+ (match_operand:SI 1 "integer_register_operand" "d")
+ (reg:DI IACC0_REG)]
+ UNSPEC_SMSSS))]
+ "TARGET_FR405_BUILTINS"
+ "smsss %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "macc")])
+
+(define_insn "smu"
+ [(set (reg:DI IACC0_REG)
+ (unspec:DI [(match_operand:SI 0 "integer_register_operand" "d")
+ (match_operand:SI 1 "integer_register_operand" "d")]
+ UNSPEC_SMU))]
+ "TARGET_FR405_BUILTINS"
+ "smu %1, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "macc")])
+
+(define_insn "addss"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_ADDSS))]
+ "TARGET_FR405_BUILTINS"
+ "addss %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "int")])
+
+(define_insn "subss"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_SUBSS))]
+ "TARGET_FR405_BUILTINS"
+ "subss %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "int")])
+
+(define_insn "slass"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_SLASS))]
+ "TARGET_FR405_BUILTINS"
+ "slass %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "int")])
+
+(define_insn "scan"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d")
+ (match_operand:SI 2 "integer_register_operand" "d")]
+ UNSPEC_SCAN))]
+ ""
+ "scan %1, %2, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "scan")])
+
+(define_insn "scutss"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (unspec:SI [(match_operand:SI 1 "integer_register_operand" "d")
+ (reg:DI IACC0_REG)]
+ UNSPEC_SCUTSS))]
+ "TARGET_FR405_BUILTINS"
+ "scutss %1,%0"
+ [(set_attr "length" "4")
+ (set_attr "type" "cut")])
+
+(define_insn "frv_prefetch0"
+ [(prefetch (unspec:SI [(match_operand:SI 0 "register_operand" "r")]
+ UNSPEC_PREFETCH0)
+ (const_int 0)
+ (const_int 0))]
+ ""
+ "dcpl %0, gr0, #0"
+ [(set_attr "length" "4")])
+
+(define_insn "frv_prefetch"
+ [(prefetch (unspec:SI [(match_operand:SI 0 "register_operand" "r")]
+ UNSPEC_PREFETCH)
+ (const_int 0)
+ (const_int 0))]
+ "TARGET_FR500_FR550_BUILTINS"
+ "nop.p\\n\\tnldub @(%0, gr0), gr0"
+ [(set_attr "length" "8")])
#MULTILIB_EXCEPTIONS = *mcpu=simple/*msoft-float* *mcpu=frv/*msoft-float*
#MULTILIB_EXTRA_OPTS = mlibrary-pic
-MULTILIB_OPTIONS = mcpu=frv/mcpu=fr400/mcpu=simple mno-pack mlibrary-pic/mfdpic
-MULTILIB_DIRNAMES = frv fr400 simple unpacked pic fdpic
-MULTILIB_MATCHES = mcpu?simple=mcpu?fr300 mlibrary-pic=multilib-library-pic
+MULTILIB_OPTIONS = mcpu=fr400/mcpu=fr550 mno-pack mlibrary-pic/mfdpic
+MULTILIB_DIRNAMES = fr400 fr550 unpacked pic fdpic
+MULTILIB_MATCHES = mcpu?simple=mcpu?fr300 \
+ mlibrary-pic=multilib-library-pic \
+ mcpu?fr400=mcpu?fr405 mcpu?fr400=mcpu?fr450
MULTILIB_EXCEPTIONS = mcpu=frv/mno-pack* mcpu=simple/mno-pack*
LIBGCC = stmp-multilib
-malloc-cc -mfixed-cc -mdword -mno-dword @gol
-mdouble -mno-double @gol
-mmedia -mno-media -mmuladd -mno-muladd @gol
--mfdpic -minline-plt -mgprel-ro -multilib-library-pic -mlinked-fp @gol
--mlibrary-pic -macc-4 -macc-8 @gol
+-mfdpic -minline-plt -mgprel-ro -multilib-library-pic @gol
+-mlinked-fp -mlong-calls -malign-labels @gol
+-mlibrary-pic -macc-4 -macc-8 @gol
-mpack -mno-pack -mno-eflags -mcond-move -mno-cond-move @gol
-mscc -mno-scc -mcond-exec -mno-cond-exec @gol
-mvliw-branch -mno-vliw-branch @gol
a stack frame is allocated. This option is enabled by default and can
be disabled with @option{-mno-linked-fp}.
+@item -mlong-calls
+@opindex mlong-calls
+
+Use indirect addressing to call functions outside the current
+compilation unit. This allows the functions to be placed anywhere
+within the 32-bit address space.
+
+@item -malign-labels
+@opindex malign-labels
+
+Try to align labels to an 8-byte boundary by inserting nops into the
+previous packet. This option only has an effect when VLIW packing
+is enabled. It doesn't create new packets; it merely adds nops to
+existing ones.
+
@item -mlibrary-pic
@opindex mlibrary-pic
@opindex mcpu
Select the processor type for which to generate code. Possible values are
-@samp{simple}, @samp{tomcat}, @samp{fr500}, @samp{fr400}, @samp{fr300},
-@samp{frv}.
+@samp{frv}, @samp{fr550}, @samp{tomcat}, @samp{fr500}, @samp{fr450},
+@samp{fr405}, @samp{fr400}, @samp{fr300} and @samp{simple}.
@end table