+\f
+/* Choose the section to use for the constant rtx expression X that has
+ mode MODE. */
+
+mips_select_rtx_section (mode, x)
+ enum machine_mode mode;
+ rtx x;
+{
+ if (TARGET_EMBEDDED_DATA)
+ {
+ /* For embedded applications, always put constants in read-only data,
+ in order to reduce RAM usage. */
+ READONLY_DATA_SECTION ();
+ }
+ else
+ {
+ /* For hosted applications, always put constants in small data if
+ possible, as this gives the best performance. */
+
+ if (GET_MODE_SIZE (mode) <= mips_section_threshold
+ && mips_section_threshold > 0)
+ SMALL_DATA_SECTION ();
+ else
+ READONLY_DATA_SECTION ();
+ }
+}
+
+/* Choose the section to use for DECL. RELOC is true if its value contains
+ any relocatable expression. */
+
+mips_select_section (decl, reloc)
+ tree decl;
+ int reloc;
+{
+ int size = int_size_in_bytes (TREE_TYPE (decl));
+
+ if (TARGET_EMBEDDED_PIC
+ && TREE_CODE (decl) == STRING_CST
+ && !flag_writable_strings)
+ {
+ /* For embedded position independent code, put constant strings
+ in the text section, because the data section is limited to
+ 64K in size. */
+
+ text_section ();
+ }
+ else if (TARGET_EMBEDDED_DATA)
+ {
+ /* For embedded applications, always put an object in read-only data
+ if possible, in order to reduce RAM usage. */
+
+ if (((TREE_CODE (decl) == VAR_DECL
+ && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)
+ && DECL_INITIAL (decl)
+ && (DECL_INITIAL (decl) == error_mark_node
+ || TREE_CONSTANT (DECL_INITIAL (decl))))
+ /* Deal with calls from output_constant_def_contents. */
+ || (TREE_CODE (decl) != VAR_DECL
+ && (TREE_CODE (decl) != STRING_CST
+ || !flag_writable_strings)))
+ && ! (flag_pic && reloc))
+ READONLY_DATA_SECTION ();
+ else if (size > 0 && size <= mips_section_threshold)
+ SMALL_DATA_SECTION ();
+ else
+ data_section ();
+ }
+ else
+ {
+ /* For hosted applications, always put an object in small data if
+ possible, as this gives the best performance. */
+
+ if (size > 0 && size <= mips_section_threshold)
+ SMALL_DATA_SECTION ();
+ else if (((TREE_CODE (decl) == VAR_DECL
+ && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)
+ && DECL_INITIAL (decl)
+ && (DECL_INITIAL (decl) == error_mark_node
+ || TREE_CONSTANT (DECL_INITIAL (decl))))
+ /* Deal with calls from output_constant_def_contents. */
+ || (TREE_CODE (decl) != VAR_DECL
+ && (TREE_CODE (decl) != STRING_CST
+ || !flag_writable_strings)))
+ && ! (flag_pic && reloc))
+ READONLY_DATA_SECTION ();
+ else
+ data_section ();
+ }
+}
+\f
+#ifdef MIPS_ABI_DEFAULT
+/* Support functions for the 64 bit ABI. */
+
+/* Return register to use for a function return value with VALTYPE for function
+ FUNC. */
+
+rtx
+mips_function_value (valtype, func)
+ tree valtype;
+ tree func;
+{
+ int reg = GP_RETURN;
+ enum machine_mode mode = TYPE_MODE (valtype);
+ enum mode_class mclass = GET_MODE_CLASS (mode);
+
+ /* ??? How should we return complex float? */
+ if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+ {
+ if (TARGET_SINGLE_FLOAT
+ && (mclass == MODE_FLOAT
+ ? GET_MODE_SIZE (mode) > 4
+ : GET_MODE_SIZE (mode) / 2 > 4))
+ reg = GP_RETURN;
+ else
+ reg = FP_RETURN;
+ }
+ else if (TREE_CODE (valtype) == RECORD_TYPE
+ && mips_abi != ABI_32 && mips_abi != ABI_EABI)
+ {
+ /* A struct with only one or two floating point fields is returned in
+ the floating point registers. */
+ tree field, fields[2];
+ int i;
+
+ for (i = 0, field = TYPE_FIELDS (valtype); field;
+ field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ if (TREE_CODE (TREE_TYPE (field)) != REAL_TYPE || i >= 2)
+ break;
+
+ fields[i++] = field;
+ }
+
+ /* Must check i, so that we reject structures with no elements. */
+ if (! field)
+ {
+ if (i == 1)
+ {
+ /* The structure has DImode, but we don't allow DImode values
+ in FP registers, so we use a PARALLEL even though it isn't
+ strictly necessary. */
+ enum machine_mode field_mode = TYPE_MODE (TREE_TYPE (fields[0]));
+
+ return gen_rtx (PARALLEL, mode,
+ gen_rtvec (1,
+ gen_rtx (EXPR_LIST, VOIDmode,
+ gen_rtx (REG, field_mode, FP_RETURN),
+ const0_rtx)));
+ }
+ else if (i == 2)
+ {
+ enum machine_mode first_mode
+ = TYPE_MODE (TREE_TYPE (fields[0]));
+ enum machine_mode second_mode
+ = TYPE_MODE (TREE_TYPE (fields[1]));
+ int first_offset
+ = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fields[0]));
+ int second_offset
+ = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fields[1]));
+
+ return gen_rtx (PARALLEL, mode,
+ gen_rtvec (2,
+ gen_rtx (EXPR_LIST, VOIDmode,
+ gen_rtx (REG, first_mode, FP_RETURN),
+ GEN_INT (first_offset / BITS_PER_UNIT)),
+ gen_rtx (EXPR_LIST, VOIDmode,
+ gen_rtx (REG, second_mode, FP_RETURN + 2),
+ GEN_INT (second_offset / BITS_PER_UNIT))));
+ }
+ }
+ }
+
+ return gen_rtx (REG, mode, reg);
+}
+
+/* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE. Return
+ nonzero when an argument must be passed by reference. */
+
+int
+function_arg_pass_by_reference (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int size;
+
+ if (mips_abi != ABI_EABI)
+ return 0;
+
+ /* ??? How should SCmode be handled? */
+ if (type == NULL_TREE || mode == DImode || mode == DFmode)
+ return 0;
+
+ size = int_size_in_bytes (type);
+ return size == -1 || size > UNITS_PER_WORD;
+}
+
+#endif
+
+/* This function returns the register class required for a secondary
+ register when copying between one of the registers in CLASS, and X,
+ using MODE. If IN_P is nonzero, the copy is going from X to the
+ register, otherwise the register is the source. A return value of
+ NO_REGS means that no secondary register is required. */
+
+enum reg_class
+mips_secondary_reload_class (class, mode, x, in_p)
+ enum reg_class class;
+ enum machine_mode mode;
+ rtx x;
+ int in_p;
+{
+ int regno = -1;
+
+ if (GET_CODE (x) == SIGN_EXTEND)
+ {
+ int off = 0;
+
+ x = XEXP (x, 0);
+
+ /* We may be called with reg_renumber NULL from regclass.
+ ??? This is probably a bug. */
+ if (reg_renumber)
+ regno = true_regnum (x);
+ else
+ {
+ while (GET_CODE (x) == SUBREG)
+ {
+ off += SUBREG_WORD (x);
+ x = SUBREG_REG (x);
+ }
+ if (GET_CODE (x) == REG)
+ regno = REGNO (x) + off;
+ }
+ }
+ else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+ regno = true_regnum (x);
+
+ /* We always require a general register when copying anything to
+ HILO_REGNUM, except when copying an SImode value from HILO_REGNUM
+ to a general register, or when copying from register 0. */
+ if (class == HILO_REG && regno != GP_REG_FIRST + 0)
+ {
+ if (! in_p
+ && GP_REG_P (regno)
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
+ return NO_REGS;
+ return GR_REGS;
+ }
+ if (regno == HILO_REGNUM)
+ {
+ if (in_p
+ && class == GR_REGS
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (SImode))
+ return NO_REGS;
+ return GR_REGS;
+ }
+
+ /* Copying from HI or LO to anywhere other than a general register
+ requires a general register. */
+ if (class == HI_REG || class == LO_REG || class == MD_REGS)
+ {
+ if (GP_REG_P (regno))
+ return NO_REGS;
+ return GR_REGS;
+ }
+ if (MD_REG_P (regno))
+ {
+ if (class == GR_REGS)
+ return NO_REGS;
+ return GR_REGS;
+ }
+
+ /* We can only copy a value to a condition code register from a
+ floating point register, and even then we require a scratch
+ floating point register. We can only copy a value out of a
+ condition code register into a general register. */
+ if (class == ST_REGS)
+ {
+ if (in_p)
+ return FP_REGS;
+ if (GP_REG_P (regno))
+ return NO_REGS;
+ return GR_REGS;
+ }
+ if (ST_REG_P (regno))
+ {
+ if (! in_p)
+ return FP_REGS;
+ if (class == GR_REGS)
+ return NO_REGS;
+ return GR_REGS;
+ }
+
+ return NO_REGS;
+}