return rclass;
}
-/* Implement REGISTER_MOVE_COST. */
+/* RCLASS is a class involved in a REGISTER_MOVE_COST calculation.
+ Return a "canonical" class to represent it in later calculations. */
-int
-mips_register_move_cost (enum machine_mode mode,
- enum reg_class to, enum reg_class from)
+static enum reg_class
+mips_canonicalize_move_class (enum reg_class rclass)
{
- if (TARGET_MIPS16)
+ /* All moves involving accumulator registers have the same cost. */
+ if (reg_class_subset_p (rclass, ACC_REGS))
+ rclass = ACC_REGS;
+
+ /* Likewise promote subclasses of general registers to the most
+ interesting containing class. */
+ if (TARGET_MIPS16 && reg_class_subset_p (rclass, M16_REGS))
+ rclass = M16_REGS;
+ else if (reg_class_subset_p (rclass, GENERAL_REGS))
+ rclass = GENERAL_REGS;
+
+ return rclass;
+}
+
+/* Return the cost of moving a value of mode MODE from a register of
+ class FROM to a GPR. Return 0 for classes that are unions of other
+ classes handled by this function. */
+
+static int
+mips_move_to_gpr_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ enum reg_class from)
+{
+ switch (from)
{
- if (reg_class_subset_p (from, GENERAL_REGS)
- && reg_class_subset_p (to, GENERAL_REGS))
- {
- if (reg_class_subset_p (from, M16_REGS)
- || reg_class_subset_p (to, M16_REGS))
- return 2;
- /* Two MOVEs. */
- return 4;
- }
+ case GENERAL_REGS:
+ /* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro. */
+ return 2;
+
+ case ACC_REGS:
+ /* MFLO and MFHI. */
+ return 6;
+
+ case FP_REGS:
+ /* MFC1, etc. */
+ return 4;
+
+ case ST_REGS:
+ /* LUI followed by MOVF. */
+ return 4;
+
+ case COP0_REGS:
+ case COP2_REGS:
+ case COP3_REGS:
+ /* This choice of value is historical. */
+ return 5;
+
+ default:
+ return 0;
}
- else if (reg_class_subset_p (from, GENERAL_REGS))
+}
+
+/* Return the cost of moving a value of mode MODE from a GPR to a
+ register of class TO. Return 0 for classes that are unions of
+ other classes handled by this function. */
+
+static int
+mips_move_from_gpr_cost (enum machine_mode mode, enum reg_class to)
+{
+ switch (to)
{
- if (reg_class_subset_p (to, GENERAL_REGS))
- return 2;
- if (reg_class_subset_p (to, FP_REGS))
- return 4;
- if (reg_class_subset_p (to, COP0_REGS)
- || reg_class_subset_p (to, COP2_REGS)
- || reg_class_subset_p (to, COP3_REGS))
- return 5;
- if (reg_class_subset_p (to, ACC_REGS))
- return 6;
+ case GENERAL_REGS:
+ /* A MIPS16 MOVE instruction, or a non-MIPS16 MOVE macro. */
+ return 2;
+
+ case ACC_REGS:
+ /* MTLO and MTHI. */
+ return 6;
+
+ case FP_REGS:
+ /* MTC1, etc. */
+ return 4;
+
+ case ST_REGS:
+ /* A secondary reload through an FPR scratch. */
+ return (mips_register_move_cost (mode, GENERAL_REGS, FP_REGS)
+ + mips_register_move_cost (mode, FP_REGS, ST_REGS));
+
+ case COP0_REGS:
+ case COP2_REGS:
+ case COP3_REGS:
+ /* This choice of value is historical. */
+ return 5;
+
+ default:
+ return 0;
}
- else if (reg_class_subset_p (to, GENERAL_REGS))
+}
+
+/* Implement REGISTER_MOVE_COST. Return 0 for classes that are the
+ maximum of the move costs for subclasses; regclass will work out
+ the maximum for us. */
+
+int
+mips_register_move_cost (enum machine_mode mode,
+ enum reg_class from, enum reg_class to)
+{
+ enum reg_class dregs;
+ int cost1, cost2;
+
+ from = mips_canonicalize_move_class (from);
+ to = mips_canonicalize_move_class (to);
+
+ /* Handle moves that can be done without using general-purpose registers. */
+ if (from == FP_REGS)
{
- if (reg_class_subset_p (from, FP_REGS))
+ if (to == FP_REGS && mips_mode_ok_for_mov_fmt_p (mode))
+ /* MOV.FMT. */
return 4;
- if (reg_class_subset_p (from, ST_REGS))
- /* LUI followed by MOVF. */
- return 4;
- if (reg_class_subset_p (from, COP0_REGS)
- || reg_class_subset_p (from, COP2_REGS)
- || reg_class_subset_p (from, COP3_REGS))
- return 5;
- if (reg_class_subset_p (from, ACC_REGS))
- return 6;
+ if (to == ST_REGS)
+ /* The sequence generated by mips_expand_fcc_reload. */
+ return 8;
}
- else if (reg_class_subset_p (from, FP_REGS))
+
+ /* Handle cases in which only one class deviates from the ideal. */
+ dregs = TARGET_MIPS16 ? M16_REGS : GENERAL_REGS;
+ if (from == dregs)
+ return mips_move_from_gpr_cost (mode, to);
+ if (to == dregs)
+ return mips_move_to_gpr_cost (mode, from);
+
+ /* Handles cases that require a GPR temporary. */
+ cost1 = mips_move_to_gpr_cost (mode, from);
+ if (cost1 != 0)
{
- if (reg_class_subset_p (to, FP_REGS)
- && mips_mode_ok_for_mov_fmt_p (mode))
- return 4;
- if (reg_class_subset_p (to, ST_REGS))
- /* An expensive sequence. */
- return 8;
+ cost2 = mips_move_from_gpr_cost (mode, to);
+ if (cost2 != 0)
+ return cost1 + cost2;
}
- return 12;
+ return 0;
}
/* Implement TARGET_IRA_COVER_CLASSES. */