This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
revised PATCH: per-function back end reinitialization, part 2/2
- From: Sandra Loosemore <sandra at codesourcery dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: David Ung <davidu at mips dot com>, Nigel Stephens <nigel at mips dot com>, Richard Sandiford <richard at codesourcery dot com>, Ian Lance Taylor <iant at google dot com>
- Date: Mon, 30 Jul 2007 15:36:46 -0400
- Subject: revised PATCH: per-function back end reinitialization, part 2/2
This is the MIPS-specific part of the patch that implements support for mixed
MIPS16 and non-MIPS16 code in the same file. The only bit that's changed since
the previous version I posted is a bit of cleanup at the point where it invokes
the non-MIPS-specific backend reinitialization (provided by part 1 of the patch).
Is this OK to commit now if the other part passes muster?
-Sandra
2007-07-30 Sandra Loosemore <sandra@codesourcery.com>
David Ung <davidu@mips.com>
Nigel Stephens <nigel@mips.com>
gcc/
Add mips16/nomips16 function attributes and -mflip-mips16 option
for testing mixed-mode compilation.
* config/mips/mips.opt (mflip-mips16): New.
(mhard-float, msoft-float): Make these control TARGET_HARD_FLOAT_ABI
and TARGET_SOFT_FLOAT_ABI, rather than TARGET_HARD_FLOAT and
TARGET_SOFT_FLOAT.
* config/mips/mips.h (mips16_hard_float): Delete.
(TARGET_HARD_FLOAT_ABI, TARGET_SOFT_FLOAT_ABI): Delete these
definitions, and replace with....
(TARGET_HARD_FLOAT, TARGET_SOFT_FLOAT): Define.
(SYMBOL_FLAG_MIPS16_FUNC): Define.
(SYMBOL_FLAG_MIPS16_FUNC_P): Define.
* config/mips/mips.c (mips16_hard_float): Delete. Replace
all references with (TARGET_MIPS16 && TARGET_HARD_FLOAT_ABI).
(mips_base_target_flags): New.
(mips_base_mips16): New.
(mips_base_schedule_insns): New.
(mips_base_align_loops): New.
(mips_base_align_functions): New.
(mips16_flipper): New.
(mips_base_split_addresses): New.
(mips_attribute_table): Add "mips16" and "nomips16" entries.
(TARGET_PREPARE_FUNCTION_START): Define.
(TARGET_END_OF_FILE_CLEANUP): Define.
(mips_mips16_type_p, mips_nomips16_type_p): New.
(mips_comp_type_attributes): Check mips16/nomips16 attributes.
(mips_cannot_force_const_mem): Check current have_tls setting, not
base setting for file.
(mips16_expand_call): Add check for built-in functions that
need function stubs.
(mips_function_ok_for_sibcall): Make it deal with functions with
mips16 attributes.
(function_arg): Must check base mips16 mode for file, not just
current setting.
(mips_init_relocs): New, split out from override_options.
(was_mips16_p): New.
(mips_set_mips16_mode): New, split out from override_options.
(mips_prepare_function_start): New.
(mips_end_of_file_cleanup): New.
(override_options): Save base option settings. Make it reflect new
interpretation of -mhard-float and -msoft-float as affecting ABI
settings. Warn about lack of PIC support. Call mips_set_mips16_mode
instead of doing initialization inline.
(mips_start_file): Move mips16 mode setting output from here....
(mips_output_function_prologue): ....to here.
(mips_output_mi_thunk): Check for mips16 function.
(mips_select_rtx_section): Don't try to put constant data in the same
section as the function if it's invoked without a function.
(mips16_fn_stubs): New.
(mips16_call_stubs): Renamed from mips16_stubs.
(build_mips16_function_stub): Make fn_decl and fp_code arguments.
Use assembler name for stub, if there is one. Cache stubs and
check if we've already emitted one before.
(mips_expand_builtin): Error in mips16 mode.
(mips_encode_section_info): Check for mips16/nomips16 attributes,
and/or flip mode if -mflip-mips16 was given. Set SYMBOL_REF_FLAGS
accordingly.
* doc/extend.texi (Function Attributes): Document new
mips16/nomips16 attributes.
* doc/invoke.texi (Option Summary): Add -mflip-mips16.
(MIPS Options): Document -mflip-mips16.
* testsuite/gcc.target/mips/mips16-attributes.c: New.
* testsuite/gcc.c-torture/compile/mipscop-1.c: Use nomips16
attribute instead of using #ifndef to disable test for mips16.
* testsuite/gcc.c-torture/compile/mipscop-2.c: Likewise.
* testsuite/gcc.c-torture/compile/mipscop-3.c: Likewise.
* testsuite/gcc.c-torture/compile/mipscop-4.c: Likewise.
* testsuite/gcc.dg/torture/mips-hilo-1.c: Likewise.
* testsuite/gcc.dg/torture/mips-hilo-2.c: Likewise.
* testsuite/gcc.dg/torture/pr19683-1.c: Likewise.
Index: gcc/config/mips/mips.opt
===================================================================
*** gcc/config/mips/mips.opt (revision 127016)
--- gcc/config/mips/mips.opt (working copy)
*************** mbranch-likely
*** 43,48 ****
--- 43,52 ----
Target Report Mask(BRANCHLIKELY)
Use Branch Likely instructions, overriding the architecture default
+ mflip-mips16
+ Target Report Var(TARGET_FLIP_MIPS16)
+ Switch on/off mips16 ASE on alternating functions for compiler testing
+
mcheck-zero-division
Target Report Mask(CHECK_ZERO_DIV)
Trap on integer divide by zero
*************** Target Report RejectNegative Mask(64BIT)
*** 146,153 ****
Use 64-bit general registers
mhard-float
! Target Report RejectNegative InverseMask(SOFT_FLOAT, HARD_FLOAT)
! Allow the use of hardware floating-point instructions
mips
Target RejectNegative Joined
--- 150,157 ----
Use 64-bit general registers
mhard-float
! Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
! Allow the use of hardware floating-point ABI and instructions
mips
Target RejectNegative Joined
*************** Target Report RejectNegative Mask(SMARTM
*** 218,224 ****
Use SmartMIPS instructions
msoft-float
! Target Report RejectNegative Mask(SOFT_FLOAT)
Prevent the use of all hardware floating-point instructions
msplit-addresses
--- 222,228 ----
Use SmartMIPS instructions
msoft-float
! Target Report RejectNegative Mask(SOFT_FLOAT_ABI)
Prevent the use of all hardware floating-point instructions
msplit-addresses
Index: gcc/config/mips/mips.h
===================================================================
*** gcc/config/mips/mips.h (revision 127016)
--- gcc/config/mips/mips.h (working copy)
*************** extern enum processor_type mips_arch;
*** 134,140 ****
extern enum processor_type mips_tune; /* which cpu to schedule for */
extern int mips_isa; /* architectural level */
extern int mips_abi; /* which ABI to use */
- extern int mips16_hard_float; /* mips16 without -msoft-float */
extern const struct mips_cpu_info mips_cpu_info_table[];
extern const struct mips_cpu_info *mips_arch_info;
extern const struct mips_cpu_info *mips_tune_info;
--- 134,139 ----
*************** extern const struct mips_rtx_cost_data *
*** 299,308 ****
#define TARGET_OLDABI (mips_abi == ABI_32 || mips_abi == ABI_O64)
#define TARGET_NEWABI (mips_abi == ABI_N32 || mips_abi == ABI_64)
! /* Similar to TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT, but reflect the ABI
! in use rather than whether the FPU is directly accessible. */
! #define TARGET_HARD_FLOAT_ABI (TARGET_HARD_FLOAT || mips16_hard_float)
! #define TARGET_SOFT_FLOAT_ABI (!TARGET_HARD_FLOAT_ABI)
/* IRIX specific stuff. */
#define TARGET_IRIX 0
--- 298,309 ----
#define TARGET_OLDABI (mips_abi == ABI_32 || mips_abi == ABI_O64)
#define TARGET_NEWABI (mips_abi == ABI_N32 || mips_abi == ABI_64)
! /* TARGET_HARD_FLOAT and TARGET_SOFT_FLOAT reflect whether the FPU is
! directly accessible, while the command-line options select
! TARGET_HARD_FLOAT_ABI and TARGET_SOFT_FLOAT_ABI to reflect the ABI
! in use. */
! #define TARGET_HARD_FLOAT (TARGET_HARD_FLOAT_ABI && !TARGET_MIPS16)
! #define TARGET_SOFT_FLOAT (TARGET_SOFT_FLOAT_ABI || TARGET_MIPS16)
/* IRIX specific stuff. */
#define TARGET_IRIX 0
*************** typedef struct mips_args {
*** 2234,2239 ****
--- 2235,2245 ----
#define SYMBOL_REF_LONG_CALL_P(X) \
((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_LONG_CALL) != 0)
+ /* Flag to mark a function decl symbol a "mips16" function. */
+ #define SYMBOL_FLAG_MIPS16_FUNC (SYMBOL_FLAG_MACH_DEP << 1)
+ #define SYMBOL_REF_MIPS16_FUNC_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_MIPS16_FUNC) != 0)
+
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction.
??? Using HImode in mips16 mode can cause overflow. */
Index: gcc/config/mips/mips.c
===================================================================
*** gcc/config/mips/mips.c (revision 127016)
--- gcc/config/mips/mips.c (working copy)
*************** static rtx mips_return_fpr_pair (enum ma
*** 356,362 ****
enum machine_mode mode2, HOST_WIDE_INT);
static rtx mips16_gp_pseudo_reg (void);
static void mips16_fp_args (FILE *, int, int);
! static void build_mips16_function_stub (FILE *);
static rtx dump_constants_1 (enum machine_mode, rtx, rtx);
static void dump_constants (struct mips16_constant *, rtx);
static int mips16_insn_length (rtx);
--- 356,362 ----
enum machine_mode mode2, HOST_WIDE_INT);
static rtx mips16_gp_pseudo_reg (void);
static void mips16_fp_args (FILE *, int, int);
! static void build_mips16_function_stub (FILE *, tree, int);
static rtx dump_constants_1 (enum machine_mode, rtx, rtx);
static void dump_constants (struct mips16_constant *, rtx);
static int mips16_insn_length (rtx);
*************** static rtx mips_expand_builtin_bposge (e
*** 426,431 ****
--- 426,434 ----
static void mips_encode_section_info (tree, rtx, int);
static void mips_extra_live_on_entry (bitmap);
static int mips_comp_type_attributes (tree, tree);
+ static void mips_set_mips16_mode (int);
+ static void mips_prepare_function_start (tree);
+ static void mips_end_of_file_cleanup (void);
static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
static bool mips_offset_within_alignment_p (rtx, HOST_WIDE_INT);
static void mips_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
*************** int mips_abi = MIPS_ABI_DEFAULT;
*** 619,635 ****
/* Cost information to use. */
const struct mips_rtx_cost_data *mips_cost;
! /* Whether we are generating mips16 hard float code. In mips16 mode
! we always set TARGET_SOFT_FLOAT; this variable is nonzero if
! -msoft-float was not specified by the user, which means that we
! should arrange to call mips32 hard floating point code. */
! int mips16_hard_float;
/* The architecture selected by -mipsN. */
static const struct mips_cpu_info *mips_isa_info;
/* If TRUE, we split addresses into their high and low parts in the RTL. */
int mips_split_addresses;
/* Mode used for saving/restoring general purpose registers. */
static enum machine_mode gpr_mode;
--- 622,644 ----
/* Cost information to use. */
const struct mips_rtx_cost_data *mips_cost;
! /* Remember the ambient target flags, excluding mips16. */
! static GTY(()) int mips_base_target_flags;
! /* The mips16 command-line target flags only. */
! static GTY(()) int mips_base_mips16;
! /* Similar copies of option settings. */
! static int mips_base_schedule_insns; /* flag_schedule_insns */
! static int mips_base_align_loops; /* align_loops */
! static int mips_base_align_jumps; /* align_jumps */
! static int mips_base_align_functions; /* align_functions */
! static GTY(()) int mips16_flipper;
/* The architecture selected by -mipsN. */
static const struct mips_cpu_info *mips_isa_info;
/* If TRUE, we split addresses into their high and low parts in the RTL. */
int mips_split_addresses;
+ int mips_base_split_addresses;
/* Mode used for saving/restoring general purpose registers. */
static enum machine_mode gpr_mode;
*************** const struct attribute_spec mips_attribu
*** 720,725 ****
--- 729,737 ----
{ "long_call", 0, 0, false, true, true, NULL },
{ "far", 0, 0, false, true, true, NULL },
{ "near", 0, 0, false, true, true, NULL },
+ /* Switch MIPS16 ASE on and off per-function. */
+ { "mips16", 0, 0, false, true, true, NULL },
+ { "nomips16", 0, 0, false, true, true, NULL },
{ NULL, 0, 0, false, false, false, NULL }
};
*************** static const unsigned char mips16e_save_
*** 1203,1209 ****
31, 30, 23, 22, 21, 20, 19, 18, 17, 16, 7, 6, 5, 4
};
! /* Nonzero if -march should decide the default value of MASK_SOFT_FLOAT. */
#ifndef MIPS_MARCH_CONTROLS_SOFT_FLOAT
#define MIPS_MARCH_CONTROLS_SOFT_FLOAT 0
#endif
--- 1215,1222 ----
31, 30, 23, 22, 21, 20, 19, 18, 17, 16, 7, 6, 5, 4
};
! /* Nonzero if -march should decide the default value of
! MASK_SOFT_FLOAT_ABI. */
#ifndef MIPS_MARCH_CONTROLS_SOFT_FLOAT
#define MIPS_MARCH_CONTROLS_SOFT_FLOAT 0
#endif
*************** static const unsigned char mips16e_save_
*** 1251,1256 ****
--- 1264,1275 ----
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall
+ #undef TARGET_PREPARE_FUNCTION_START
+ #define TARGET_PREPARE_FUNCTION_START mips_prepare_function_start
+
+ #undef TARGET_END_OF_FILE_CLEANUP
+ #define TARGET_END_OF_FILE_CLEANUP mips_end_of_file_cleanup
+
#undef TARGET_VALID_POINTER_MODE
#define TARGET_VALID_POINTER_MODE mips_valid_pointer_mode
#undef TARGET_RTX_COSTS
*************** mips_far_type_p (tree type)
*** 1369,1374 ****
--- 1388,1406 ----
|| lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
}
+ /* Similar predicates for "mips16"/"nomips16" attributes. */
+
+ static bool
+ mips_mips16_type_p (tree type)
+ {
+ return lookup_attribute ("mips16", TYPE_ATTRIBUTES (type)) != NULL;
+ }
+
+ static bool
+ mips_nomips16_type_p (tree type)
+ {
+ return lookup_attribute ("nomips16", TYPE_ATTRIBUTES (type)) != NULL;
+ }
/* Return 0 if the attributes for two types are incompatible, 1 if they
are compatible, and 2 if they are nearly compatible (which causes a
*************** mips_comp_type_attributes (tree type1, t
*** 1387,1392 ****
--- 1419,1429 ----
if (mips_near_type_p (type1) && mips_far_type_p (type2))
return 0;
+ /* Mips16/nomips16 attributes must match exactly. */
+ if (mips_nomips16_type_p (type1) != mips_nomips16_type_p (type2)
+ || mips_mips16_type_p (type1) != mips_mips16_type_p (type2))
+ return 0;
+
return 1;
}
*************** mips_cannot_force_const_mem (rtx x)
*** 1813,1819 ****
return true;
}
! if (TARGET_HAVE_TLS && for_each_rtx (&x, &mips_tls_symbol_ref_1, 0))
return true;
return false;
--- 1850,1856 ----
return true;
}
! if (targetm.have_tls && for_each_rtx (&x, &mips_tls_symbol_ref_1, 0))
return true;
return false;
*************** mips_expand_call (rtx result, rtx addr,
*** 3671,3681 ****
mips_load_call_address (addr, orig_addr, sibcall_p);
}
! if (mips16_hard_float
&& build_mips16_call_stub (result, addr, args_size,
aux == 0 ? 0 : (int) GET_MODE (aux)))
return;
if (result == 0)
pattern = (sibcall_p
? gen_sibcall_internal (addr, args_size)
--- 3708,3733 ----
mips_load_call_address (addr, orig_addr, sibcall_p);
}
! if (TARGET_MIPS16
! && TARGET_HARD_FLOAT_ABI
&& build_mips16_call_stub (result, addr, args_size,
aux == 0 ? 0 : (int) GET_MODE (aux)))
return;
+ /* If we are generating non-mips16 code for this function and we pass
+ -mips16 on the command line, we need to generate a fn_stub for any
+ built-in functions that we call. */
+ if (!TARGET_MIPS16
+ && mips_base_mips16
+ && TARGET_HARD_FLOAT_ABI
+ && GET_CODE (addr) == SYMBOL_REF
+ && SYMBOL_REF_DECL (addr)
+ && TREE_TYPE (SYMBOL_REF_DECL (addr))
+ && TREE_TYPE (SYMBOL_REF_DECL (addr)) != error_mark_node
+ && DECL_BUILT_IN (SYMBOL_REF_DECL (addr)))
+ build_mips16_function_stub (asm_out_file, SYMBOL_REF_DECL (addr),
+ aux == 0 ? 0 : (int) GET_MODE (aux));
+
if (result == 0)
pattern = (sibcall_p
? gen_sibcall_internal (addr, args_size)
*************** mips_expand_call (rtx result, rtx addr,
*** 3704,3716 ****
}
! /* We can handle any sibcall when TARGET_SIBCALLS is true. */
static bool
! mips_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
tree exp ATTRIBUTE_UNUSED)
{
! return TARGET_SIBCALLS;
}
/* Emit code to move general operand SRC into condition-code
--- 3756,3774 ----
}
! /* We can handle any sibcall when TARGET_SIBCALLS is true except when
! the called function is a MIPS16 function, since there is no direct
! "jx" instruction equivalent to "jalx" to switch the ISA mode. */
static bool
! mips_function_ok_for_sibcall (tree decl,
tree exp ATTRIBUTE_UNUSED)
{
! if (!TARGET_SIBCALLS)
! return 0;
! if (decl && SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (decl), 0)))
! return 0;
! return 1;
}
/* Emit code to move general operand SRC into condition-code
*************** function_arg (const CUMULATIVE_ARGS *cum
*** 4147,4153 ****
stored as the mode. */
if (mode == VOIDmode)
{
! if (TARGET_MIPS16 && cum->fp_code != 0)
return gen_rtx_REG ((enum machine_mode) cum->fp_code, 0);
else
--- 4205,4213 ----
stored as the mode. */
if (mode == VOIDmode)
{
! if ((TARGET_MIPS16
! || (!TARGET_MIPS16 && mips_base_mips16 && TARGET_HARD_FLOAT_ABI))
! && cum->fp_code != 0)
return gen_rtx_REG ((enum machine_mode) cum->fp_code, 0);
else
*************** mips_set_tune (const struct mips_cpu_inf
*** 4953,4958 ****
--- 5013,5239 ----
}
}
+ /* (Re-)Initialize information about relocs. */
+
+ static void
+ mips_init_relocs (void)
+ {
+ memset (mips_split_p, '\0', sizeof (mips_split_p));
+ memset (mips_hi_relocs, '\0', sizeof (mips_hi_relocs));
+ memset (mips_lo_relocs, '\0', sizeof (mips_lo_relocs));
+
+ if (ABI_HAS_64BIT_SYMBOLS)
+ {
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ mips_split_p[SYMBOL_64_HIGH] = true;
+ mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
+ mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
+
+ mips_split_p[SYMBOL_64_MID] = true;
+ mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
+ mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
+
+ mips_split_p[SYMBOL_64_LOW] = true;
+ mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
+ mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
+
+ mips_split_p[SYMBOL_GENERAL] = true;
+ mips_lo_relocs[SYMBOL_GENERAL] = "%lo(";
+ }
+ }
+ else
+ {
+ if (TARGET_EXPLICIT_RELOCS || mips_split_addresses)
+ {
+ mips_split_p[SYMBOL_GENERAL] = true;
+ mips_hi_relocs[SYMBOL_GENERAL] = "%hi(";
+ mips_lo_relocs[SYMBOL_GENERAL] = "%lo(";
+ }
+ }
+
+ if (TARGET_MIPS16)
+ {
+ /* The high part is provided by a pseudo copy of $gp. */
+ mips_split_p[SYMBOL_SMALL_DATA] = true;
+ mips_lo_relocs[SYMBOL_SMALL_DATA] = "%gprel(";
+ }
+
+ if (TARGET_EXPLICIT_RELOCS)
+ {
+ /* Small data constants are kept whole until after reload,
+ then lowered by mips_rewrite_small_data. */
+ mips_lo_relocs[SYMBOL_SMALL_DATA] = "%gp_rel(";
+
+ mips_split_p[SYMBOL_GOT_PAGE_OFST] = true;
+ if (TARGET_NEWABI)
+ {
+ mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got_page(";
+ mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%got_ofst(";
+ }
+ else
+ {
+ mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got(";
+ mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%lo(";
+ }
+
+ if (TARGET_XGOT)
+ {
+ /* The HIGH and LO_SUM are matched by special .md patterns. */
+ mips_split_p[SYMBOL_GOT_DISP] = true;
+
+ mips_split_p[SYMBOL_GOTOFF_DISP] = true;
+ mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
+ mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
+
+ mips_split_p[SYMBOL_GOTOFF_CALL] = true;
+ mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
+ mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call_lo(";
+ }
+ else
+ {
+ if (TARGET_NEWABI)
+ mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_disp(";
+ else
+ mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got(";
+ mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call16(";
+ }
+ }
+
+ if (TARGET_NEWABI)
+ {
+ mips_split_p[SYMBOL_GOTOFF_LOADGP] = true;
+ mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
+ mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
+ }
+
+ /* Thread-local relocation operators. */
+ mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
+ mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
+ mips_split_p[SYMBOL_DTPREL] = 1;
+ mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+ mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+ mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+ mips_split_p[SYMBOL_TPREL] = 1;
+ mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+ mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+
+ mips_lo_relocs[SYMBOL_HALF] = "%half(";
+ }
+
+ static GTY(()) int was_mips16_p = -1;
+
+ /* Resets compiler middle end to match the instruction set mode selected for
+ the current function. */
+ static void
+ mips_set_mips16_mode (int mips16_p)
+ {
+ static int first = 1;
+
+ if (mips16_p == was_mips16_p)
+ return;
+
+ target_flags = mips_base_target_flags;
+ if (mips16_p)
+ {
+
+ /* MIPS16 mode is incompatible with TARGET_DSP. */
+ if (TARGET_DSP)
+ error ("MIPS16 mode cannot be used with -mdsp");
+
+ /* Select mips16 instruction set. */
+ target_flags |= MASK_MIPS16 | mips_base_mips16;
+
+ /* Don't run the scheduler before reload, since it tends to
+ increase register pressure. */
+ flag_schedule_insns = 0;
+
+ /* Silently disable -mexplicit-relocs since it doesn't apply
+ to mips16 code. Even so, it would overly pedantic to warn
+ about "-mips16 -mexplicit-relocs", especially given that
+ we use a %gprel() operator. */
+ target_flags &= ~MASK_EXPLICIT_RELOCS;
+ mips_split_addresses = 0;
+
+ /* Use default default delayed_branch option. */
+ flag_delayed_branch = mips_flag_delayed_branch;
+
+ /* Force no alignment of mips16 code. */
+ /* XXX would 32-bit alignment be an acceptable compromise? */
+ align_loops = align_jumps = align_functions = 1;
+
+ /* We don't have a thread pointer access instruction on MIPS16, or
+ appropriate TLS relocations. */
+ targetm.have_tls = false;
+
+ }
+ else
+ {
+ /* Reset to select base non-mips16 ISA. */
+ target_flags &= ~(MASK_MIPS16);
+
+ /* When using explicit relocs, we call dbr_schedule from within
+ mips_reorg. */
+ if (TARGET_EXPLICIT_RELOCS)
+ flag_delayed_branch = 0;
+ else
+ flag_delayed_branch = mips_flag_delayed_branch;
+
+ /* Reset other flags overridden in mips16 mode. */
+ mips_split_addresses = mips_base_split_addresses;
+ flag_schedule_insns = mips_base_schedule_insns;
+ if (mips_base_align_loops > 0)
+ align_loops = mips_base_align_loops;
+ if (mips_base_align_jumps > 0)
+ align_jumps = mips_base_align_jumps;
+ if (mips_base_align_functions > 0)
+ align_functions = mips_base_align_functions;
+
+ /* TLS is only supported for per-file nomips16 processing, not
+ per-function, so we can correctly generate the initialization
+ code for TLS variables. */
+ targetm.have_tls = TARGET_HAVE_TLS && !mips_base_mips16;
+ }
+
+ /* (Re)initialise mips target internals for new ISA. */
+ mips_init_relocs ();
+
+ if (!first)
+ /* Reinitialize target-dependent state. */
+ target_reinit ();
+
+ first = 0;
+ was_mips16_p = !!TARGET_MIPS16;
+ }
+
+ /* Called just before starting to generate RTL for a function, and picks the
+ appropriate 16 or 32-bit mode, as selected by the "mips16" or "nomips16"
+ function attributes. */
+ static void
+ mips_prepare_function_start (tree fndecl)
+ {
+ tree x;
+
+ if (!fndecl)
+ return;
+
+ /* Get the DECL of the top-most enclosing function. */
+ /* XXX do we still need to do this? */
+ while ((x = decl_function_context (fndecl)))
+ fndecl = x;
+
+ mips_set_mips16_mode (SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (fndecl), 0)));
+ }
+
+ /* Called after finishing generating RTL for all functions in the file, and
+ before emitting deferred declarations and data; reset MIPS16 mode.
+ */
+ static void
+ mips_end_of_file_cleanup (void)
+ {
+ mips_set_mips16_mode (mips_base_mips16 != 0);
+ }
+
/* Implement TARGET_HANDLE_OPTION. */
static bool
*************** override_options (void)
*** 5001,5006 ****
--- 5282,5292 ----
int i, start, regno;
enum machine_mode mode;
+ /* Save the command-line MIPS16 setting, then disable. It will be
+ set again on a per-function basis by mips_set_mips16_mode(). */
+ mips_base_mips16 = target_flags & MASK_MIPS16;
+ target_flags ^= mips_base_mips16;
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
*************** override_options (void)
*** 5112,5132 ****
}
if (MIPS_MARCH_CONTROLS_SOFT_FLOAT
! && (target_flags_explicit & MASK_SOFT_FLOAT) == 0)
{
/* For some configurations, it is useful to have -march control
! the default setting of MASK_SOFT_FLOAT. */
switch ((int) mips_arch)
{
case PROCESSOR_R4100:
case PROCESSOR_R4111:
case PROCESSOR_R4120:
case PROCESSOR_R4130:
! target_flags |= MASK_SOFT_FLOAT;
break;
default:
! target_flags &= ~MASK_SOFT_FLOAT;
break;
}
}
--- 5398,5418 ----
}
if (MIPS_MARCH_CONTROLS_SOFT_FLOAT
! && (target_flags_explicit & MASK_SOFT_FLOAT_ABI) == 0)
{
/* For some configurations, it is useful to have -march control
! the default setting of MASK_SOFT_FLOAT_ABI. */
switch ((int) mips_arch)
{
case PROCESSOR_R4100:
case PROCESSOR_R4111:
case PROCESSOR_R4120:
case PROCESSOR_R4130:
! target_flags |= MASK_SOFT_FLOAT_ABI;
break;
default:
! target_flags &= ~MASK_SOFT_FLOAT_ABI;
break;
}
}
*************** override_options (void)
*** 5169,5174 ****
--- 5455,5471 ----
target_flags &= ~MASK_ABICALLS;
}
+ /* MIPS16 cannot generate PIC yet. */
+ if (mips_base_mips16 && (flag_pic || TARGET_ABICALLS))
+ {
+ warning (0, "%s is not supported with -mips16, ignored",
+ (flag_pic > 1 ? "-fPIC" :
+ flag_pic ? "-fpic" :
+ "-mabicalls"));
+ target_flags &= ~MASK_ABICALLS;
+ flag_pic = flag_pie = flag_shlib = 0;
+ }
+
if (TARGET_ABICALLS)
{
/* We need to set flag_pic for executables as well as DSOs
*************** override_options (void)
*** 5209,5246 ****
if (optimize > 2 && (target_flags_explicit & MASK_VR4130_ALIGN) == 0)
target_flags |= MASK_VR4130_ALIGN;
- /* When compiling for the mips16, we cannot use floating point. We
- record the original hard float value in mips16_hard_float. */
- if (TARGET_MIPS16)
- {
- if (TARGET_SOFT_FLOAT)
- mips16_hard_float = 0;
- else
- mips16_hard_float = 1;
- target_flags |= MASK_SOFT_FLOAT;
-
- /* Don't run the scheduler before reload, since it tends to
- increase register pressure. */
- flag_schedule_insns = 0;
-
- /* Don't do hot/cold partitioning. The constant layout code expects
- the whole function to be in a single section. */
- flag_reorder_blocks_and_partition = 0;
-
- /* Silently disable -mexplicit-relocs since it doesn't apply
- to mips16 code. Even so, it would overly pedantic to warn
- about "-mips16 -mexplicit-relocs", especially given that
- we use a %gprel() operator. */
- target_flags &= ~MASK_EXPLICIT_RELOCS;
- }
-
/* When using explicit relocs, we call dbr_schedule from within
mips_reorg. */
if (TARGET_EXPLICIT_RELOCS)
! {
! mips_flag_delayed_branch = flag_delayed_branch;
! flag_delayed_branch = 0;
! }
#ifdef MIPS_TFMODE_FORMAT
REAL_MODE_FORMAT (TFmode) = &MIPS_TFMODE_FORMAT;
--- 5506,5516 ----
if (optimize > 2 && (target_flags_explicit & MASK_VR4130_ALIGN) == 0)
target_flags |= MASK_VR4130_ALIGN;
/* When using explicit relocs, we call dbr_schedule from within
mips_reorg. */
+ mips_flag_delayed_branch = flag_delayed_branch;
if (TARGET_EXPLICIT_RELOCS)
! flag_delayed_branch = 0;
#ifdef MIPS_TFMODE_FORMAT
REAL_MODE_FORMAT (TFmode) = &MIPS_TFMODE_FORMAT;
*************** override_options (void)
*** 5270,5278 ****
if (TARGET_DSPR2)
target_flags |= MASK_DSP;
- if (TARGET_MIPS16 && TARGET_DSP)
- error ("-mips16 and -mdsp cannot be used together");
-
mips_print_operand_punct['?'] = 1;
mips_print_operand_punct['#'] = 1;
mips_print_operand_punct['/'] = 1;
--- 5540,5545 ----
*************** override_options (void)
*** 5366,5383 ****
&& size <= UNITS_PER_FPREG))
&& (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT
|| class == MODE_VECTOR_FLOAT)
! && size <= UNITS_PER_FPVALUE)
! /* Allow integer modes that fit into a single
! register. We need to put integers into FPRs
! when using instructions like cvt and trunc.
! We can't allow sizes smaller than a word,
! the FPU has no appropriate load/store
! instructions for those. */
! || (class == MODE_INT
! && size >= MIN_UNITS_PER_WORD
! && size <= UNITS_PER_FPREG)
! /* Allow TFmode for CCmode reloads. */
! || (ISA_HAS_8CC && mode == TFmode)));
else if (ACC_REG_P (regno))
temp = (INTEGRAL_MODE_P (mode)
--- 5633,5650 ----
&& size <= UNITS_PER_FPREG))
&& (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT
|| class == MODE_VECTOR_FLOAT)
! && size <= UNITS_PER_FPVALUE))
! /* Allow integer modes that fit into a single
! register. We need to put integers into FPRs
! when using instructions like cvt and trunc.
! We can't allow sizes smaller than a word,
! the FPU has no appropriate load/store
! instructions for those. */
! || (class == MODE_INT
! && size >= MIN_UNITS_PER_WORD
! && size <= UNITS_PER_FPREG)
! /* Allow TFmode for CCmode reloads. */
! || (ISA_HAS_8CC && mode == TFmode));
else if (ACC_REG_P (regno))
temp = (INTEGRAL_MODE_P (mode)
*************** override_options (void)
*** 5401,5407 ****
gpr_mode = TARGET_64BIT ? DImode : SImode;
/* Provide default values for align_* for 64-bit targets. */
! if (TARGET_64BIT && !TARGET_MIPS16)
{
if (align_loops == 0)
align_loops = 8;
--- 5668,5674 ----
gpr_mode = TARGET_64BIT ? DImode : SImode;
/* Provide default values for align_* for 64-bit targets. */
! if (TARGET_64BIT)
{
if (align_loops == 0)
align_loops = 8;
*************** override_options (void)
*** 5414,5522 ****
/* Function to allocate machine-dependent function status. */
init_machine_status = &mips_init_machine_status;
- if (ABI_HAS_64BIT_SYMBOLS)
- {
- if (TARGET_EXPLICIT_RELOCS)
- {
- mips_split_p[SYMBOL_64_HIGH] = true;
- mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
- mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
-
- mips_split_p[SYMBOL_64_MID] = true;
- mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
- mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
-
- mips_split_p[SYMBOL_64_LOW] = true;
- mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
- mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
-
- mips_split_p[SYMBOL_GENERAL] = true;
- mips_lo_relocs[SYMBOL_GENERAL] = "%lo(";
- }
- }
- else
- {
- if (TARGET_EXPLICIT_RELOCS || mips_split_addresses)
- {
- mips_split_p[SYMBOL_GENERAL] = true;
- mips_hi_relocs[SYMBOL_GENERAL] = "%hi(";
- mips_lo_relocs[SYMBOL_GENERAL] = "%lo(";
- }
- }
-
- if (TARGET_MIPS16)
- {
- /* The high part is provided by a pseudo copy of $gp. */
- mips_split_p[SYMBOL_SMALL_DATA] = true;
- mips_lo_relocs[SYMBOL_SMALL_DATA] = "%gprel(";
- }
-
- if (TARGET_EXPLICIT_RELOCS)
- {
- /* Small data constants are kept whole until after reload,
- then lowered by mips_rewrite_small_data. */
- mips_lo_relocs[SYMBOL_SMALL_DATA] = "%gp_rel(";
-
- mips_split_p[SYMBOL_GOT_PAGE_OFST] = true;
- if (TARGET_NEWABI)
- {
- mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got_page(";
- mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%got_ofst(";
- }
- else
- {
- mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got(";
- mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%lo(";
- }
-
- if (TARGET_XGOT)
- {
- /* The HIGH and LO_SUM are matched by special .md patterns. */
- mips_split_p[SYMBOL_GOT_DISP] = true;
-
- mips_split_p[SYMBOL_GOTOFF_DISP] = true;
- mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
- mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
-
- mips_split_p[SYMBOL_GOTOFF_CALL] = true;
- mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
- mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call_lo(";
- }
- else
- {
- if (TARGET_NEWABI)
- mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_disp(";
- else
- mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got(";
- mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call16(";
- }
- }
-
- if (TARGET_NEWABI)
- {
- mips_split_p[SYMBOL_GOTOFF_LOADGP] = true;
- mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
- mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
- }
-
- /* Thread-local relocation operators. */
- mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
- mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
- mips_split_p[SYMBOL_DTPREL] = 1;
- mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
- mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
- mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
- mips_split_p[SYMBOL_TPREL] = 1;
- mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
- mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
-
- mips_lo_relocs[SYMBOL_HALF] = "%half(";
-
- /* We don't have a thread pointer access instruction on MIPS16, or
- appropriate TLS relocations. */
- if (TARGET_MIPS16)
- targetm.have_tls = false;
-
/* Default to working around R4000 errata only if the processor
was selected explicitly. */
if ((target_flags_explicit & MASK_FIX_R4000) == 0
--- 5681,5686 ----
*************** override_options (void)
*** 5528,5533 ****
--- 5692,5708 ----
if ((target_flags_explicit & MASK_FIX_R4400) == 0
&& mips_matching_cpu_name_p (mips_arch_info->name, "r4400"))
target_flags |= MASK_FIX_R4400;
+
+ /* Save base state of options for 32-bit ISA. */
+ mips_base_target_flags = target_flags;
+ mips_base_split_addresses = mips_split_addresses;
+ mips_base_schedule_insns = flag_schedule_insns;
+ mips_base_align_loops = align_loops;
+ mips_base_align_jumps = align_jumps;
+ mips_base_align_functions = align_functions;
+
+ /* Now select the mips16 or 32-bit instruction set, as requested. */
+ mips_set_mips16_mode (mips_base_mips16 != 0);
}
/* Swap the register information for registers I and I + 1, which
*************** mips_file_start (void)
*** 6272,6280 ****
if (TARGET_ABICALLS)
fprintf (asm_out_file, "\t.abicalls\n");
- if (TARGET_MIPS16)
- fprintf (asm_out_file, "\t.set\tmips16\n");
-
if (flag_verbose_asm)
fprintf (asm_out_file, "\n%s -G value = %d, Arch = %s, ISA = %d\n",
ASM_COMMENT_START,
--- 6447,6452 ----
*************** static bool
*** 6614,6620 ****
mips16_cfun_returns_in_fpr_p (void)
{
tree return_type = DECL_RESULT (current_function_decl);
! return (mips16_hard_float
&& !aggregate_value_p (return_type, current_function_decl)
&& mips_return_mode_in_fpr_p (DECL_MODE (return_type)));
}
--- 6786,6793 ----
mips16_cfun_returns_in_fpr_p (void)
{
tree return_type = DECL_RESULT (current_function_decl);
! return (TARGET_MIPS16
! && TARGET_HARD_FLOAT_ABI
&& !aggregate_value_p (return_type, current_function_decl)
&& mips_return_mode_in_fpr_p (DECL_MODE (return_type)));
}
*************** mips_output_function_prologue (FILE *fil
*** 7102,7110 ****
floating point arguments. The linker will arrange for any 32-bit
functions to call this stub, which will then jump to the 16-bit
function proper. */
! if (mips16_hard_float
&& current_function_args_info.fp_code != 0)
! build_mips16_function_stub (file);
if (!FUNCTION_NAME_ALREADY_DECLARED)
{
--- 7275,7291 ----
floating point arguments. The linker will arrange for any 32-bit
functions to call this stub, which will then jump to the 16-bit
function proper. */
! if (TARGET_MIPS16
! && TARGET_HARD_FLOAT_ABI
&& current_function_args_info.fp_code != 0)
! build_mips16_function_stub (file, current_function_decl,
! current_function_args_info.fp_code);
!
! /* Select the mips16 mode for this function. */
! if (TARGET_MIPS16)
! fprintf (file, "\t.set\tmips16\n");
! else
! fprintf (file, "\t.set\tnomips16\n");
if (!FUNCTION_NAME_ALREADY_DECLARED)
{
*************** mips_output_mi_thunk (FILE *file, tree t
*** 8113,8119 ****
/* Jump to the target function. Use a sibcall if direct jumps are
allowed, otherwise load the address into a register first. */
fnaddr = XEXP (DECL_RTL (function), 0);
! if (TARGET_MIPS16 || TARGET_USE_GOT || SYMBOL_REF_LONG_CALL_P (fnaddr))
{
/* This is messy. gas treats "la $25,foo" as part of a call
sequence and may allow a global "foo" to be lazily bound.
--- 8294,8301 ----
/* Jump to the target function. Use a sibcall if direct jumps are
allowed, otherwise load the address into a register first. */
fnaddr = XEXP (DECL_RTL (function), 0);
! if (TARGET_MIPS16 || TARGET_USE_GOT || SYMBOL_REF_LONG_CALL_P (fnaddr)
! || SYMBOL_REF_MIPS16_FUNC_P (fnaddr))
{
/* This is messy. gas treats "la $25,foo" as part of a call
sequence and may allow a global "foo" to be lazily bound.
*************** static section *
*** 8188,8194 ****
mips_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
! if (TARGET_MIPS16)
{
/* In mips16 mode, the constant table always goes in the same section
as the function, so that constants can be loaded using PC relative
--- 8370,8376 ----
mips_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align)
{
! if (TARGET_MIPS16 && current_function_decl)
{
/* In mips16 mode, the constant table always goes in the same section
as the function, so that constants can be loaded using PC relative
*************** mips16_fp_args (FILE *file, int fp_code,
*** 8877,8910 ****
}
}
/* Build a mips16 function stub. This is used for functions which
take arguments in the floating point registers. It is 32-bit code
that moves the floating point args into the general registers, and
then jumps to the 16-bit code. */
static void
! build_mips16_function_stub (FILE *file)
{
const char *fnname;
char *secname, *stubname;
tree stubid, stubdecl;
int need_comma;
unsigned int f;
! fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
secname = (char *) alloca (strlen (fnname) + 20);
sprintf (secname, ".mips16.fn.%s", fnname);
stubname = (char *) alloca (strlen (fnname) + 20);
sprintf (stubname, "__fn_stub_%s", fnname);
stubid = get_identifier (stubname);
stubdecl = build_decl (FUNCTION_DECL, stubid,
build_function_type (void_type_node, NULL_TREE));
DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
! fprintf (file, "\t# Stub function for %s (", current_function_name ());
need_comma = 0;
! for (f = (unsigned int) current_function_args_info.fp_code; f != 0; f >>= 2)
{
fprintf (file, "%s%s",
need_comma ? ", " : "",
--- 9059,9128 ----
}
}
+
+ /* We keep 2 list of functions for which we have already built fn_stubs
+ and call_stubs. */
+
+ struct mips16_stub
+ {
+ struct mips16_stub *next;
+ char *name;
+ int fpret;
+ };
+
+ static struct mips16_stub *mips16_fn_stubs;
+ static struct mips16_stub *mips16_call_stubs;
+
/* Build a mips16 function stub. This is used for functions which
take arguments in the floating point registers. It is 32-bit code
that moves the floating point args into the general registers, and
then jumps to the 16-bit code. */
static void
! build_mips16_function_stub (FILE *file, tree fn_decl, int fp_code)
{
const char *fnname;
char *secname, *stubname;
tree stubid, stubdecl;
int need_comma;
unsigned int f;
+ struct mips16_stub *l;
! if (DECL_ASSEMBLER_NAME_SET_P (fn_decl))
! {
! fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl));
! /* Check for user assembler names. */
! if (fnname[0] == '*')
! {
! fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl)) + 1;
! /* Do we care about prefix such as -fleading-underscore?
! If so, handle user_label_prefix. */
! }
! }
! else
! fnname = XSTR (XEXP (DECL_RTL (fn_decl), 0), 0);
secname = (char *) alloca (strlen (fnname) + 20);
sprintf (secname, ".mips16.fn.%s", fnname);
stubname = (char *) alloca (strlen (fnname) + 20);
sprintf (stubname, "__fn_stub_%s", fnname);
stubid = get_identifier (stubname);
+
+ for (l = mips16_fn_stubs; l != NULL; l = l->next)
+ if (strcmp (l->name, fnname) == 0)
+ break;
+
+ if (l != NULL)
+ return;
+
stubdecl = build_decl (FUNCTION_DECL, stubid,
build_function_type (void_type_node, NULL_TREE));
DECL_SECTION_NAME (stubdecl) = build_string (strlen (secname), secname);
DECL_RESULT (stubdecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
! fprintf (file, "\t# Stub function for %s (",
! lang_hooks.decl_printable_name (fn_decl, 2));
need_comma = 0;
! for (f = (unsigned int) fp_code; f != 0; f >>= 2)
{
fprintf (file, "%s%s",
need_comma ? ", " : "",
*************** build_mips16_function_stub (FILE *file)
*** 8932,8938 ****
/* We don't want the assembler to insert any nops here. */
fprintf (file, "\t.set\tnoreorder\n");
! mips16_fp_args (file, current_function_args_info.fp_code, 1);
fprintf (asm_out_file, "\t.set\tnoat\n");
fprintf (asm_out_file, "\tla\t%s,", reg_names[GP_REG_FIRST + 1]);
--- 9150,9156 ----
/* We don't want the assembler to insert any nops here. */
fprintf (file, "\t.set\tnoreorder\n");
! mips16_fp_args (file, fp_code, 1);
fprintf (asm_out_file, "\t.set\tnoat\n");
fprintf (asm_out_file, "\tla\t%s,", reg_names[GP_REG_FIRST + 1]);
*************** build_mips16_function_stub (FILE *file)
*** 8957,8978 ****
fputs ("\n", file);
}
- fprintf (file, "\t.set\tmips16\n");
-
switch_to_section (function_section (current_function_decl));
- }
-
- /* We keep a list of functions for which we have already built stubs
- in build_mips16_call_stub. */
! struct mips16_stub
! {
! struct mips16_stub *next;
! char *name;
! int fpret;
! };
- static struct mips16_stub *mips16_stubs;
/* Emit code to return a double value from a mips16 stub. GPREG is the
first GP reg to use, FPREG is the first FP reg to use. */
--- 9175,9190 ----
fputs ("\n", file);
}
switch_to_section (function_section (current_function_decl));
! /* Record function stub. */
! l = (struct mips16_stub *) xmalloc (sizeof *l);
! l->name = xstrdup (fnname);
! l->fpret = -1;
! l->next = mips16_fn_stubs;
! mips16_fn_stubs = l;
! }
/* Emit code to return a double value from a mips16 stub. GPREG is the
first GP reg to use, FPREG is the first FP reg to use. */
*************** build_mips16_call_stub (rtx retval, rtx
*** 9046,9052 ****
/* We don't need to do anything if we aren't in mips16 mode, or if
we were invoked with the -msoft-float option. */
! if (!mips16_hard_float)
return 0;
/* Figure out whether the value might come back in a floating point
--- 9258,9264 ----
/* We don't need to do anything if we aren't in mips16 mode, or if
we were invoked with the -msoft-float option. */
! if (!TARGET_MIPS16 || TARGET_SOFT_FLOAT_ABI)
return 0;
/* Figure out whether the value might come back in a floating point
*************** build_mips16_call_stub (rtx retval, rtx
*** 9130,9136 ****
built a stub, we don't need to do anything further. */
fnname = XSTR (fn, 0);
! for (l = mips16_stubs; l != NULL; l = l->next)
if (strcmp (l->name, fnname) == 0)
break;
--- 9342,9349 ----
built a stub, we don't need to do anything further. */
fnname = XSTR (fn, 0);
!
! for (l = mips16_call_stubs; l != NULL; l = l->next)
if (strcmp (l->name, fnname) == 0)
break;
*************** build_mips16_call_stub (rtx retval, rtx
*** 9290,9303 ****
fputs ("\n", asm_out_file);
}
- fprintf (asm_out_file, "\t.set\tmips16\n");
-
/* Record this stub. */
l = (struct mips16_stub *) xmalloc (sizeof *l);
l->name = xstrdup (fnname);
l->fpret = fpret;
! l->next = mips16_stubs;
! mips16_stubs = l;
}
/* If we expect a floating point return value, but we've built a
--- 9503,9514 ----
fputs ("\n", asm_out_file);
}
/* Record this stub. */
l = (struct mips16_stub *) xmalloc (sizeof *l);
l->name = xstrdup (fnname);
l->fpret = fpret;
! l->next = mips16_call_stubs;
! mips16_call_stubs = l;
}
/* If we expect a floating point return value, but we've built a
*************** mips_init_libfuncs (void)
*** 10102,10108 ****
set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3");
}
! if (mips16_hard_float)
{
set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3");
set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3");
--- 10313,10319 ----
set_optab_libfunc (smod_optab, SImode, "__vr4120_modsi3");
}
! if (TARGET_MIPS16 && TARGET_HARD_FLOAT_ABI)
{
set_optab_libfunc (add_optab, SFmode, "__mips16_addsf3");
set_optab_libfunc (sub_optab, SFmode, "__mips16_subsf3");
*************** mips_expand_builtin (tree exp, rtx targe
*** 11409,11414 ****
--- 11620,11632 ----
const struct builtin_description *bdesc;
const struct bdesc_map *m;
+ if (TARGET_MIPS16)
+ {
+ error ("built-in function `%s' not supported for MIPS16",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return const0_rtx;
+ }
+
fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
fcode = DECL_FUNCTION_CODE (fndecl);
*************** mips_encode_section_info (tree decl, rtx
*** 11929,11938 ****
if (TREE_CODE (decl) == FUNCTION_DECL)
{
rtx symbol = XEXP (rtl, 0);
! if ((TARGET_LONG_CALLS && !mips_near_type_p (TREE_TYPE (decl)))
! || mips_far_type_p (TREE_TYPE (decl)))
SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
}
}
--- 12147,12200 ----
if (TREE_CODE (decl) == FUNCTION_DECL)
{
rtx symbol = XEXP (rtl, 0);
+ int is_mips16 = mips_base_mips16;
+ tree type = TREE_TYPE (decl);
! if ((TARGET_LONG_CALLS && !mips_near_type_p (type))
! || mips_far_type_p (type))
SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
+
+ /* MIPS16 function attribute handling. */
+ if (mips_mips16_type_p (type))
+ is_mips16 = 1;
+ else if (mips_nomips16_type_p (type))
+ is_mips16 = 0;
+ else if (TARGET_FLIP_MIPS16
+ && !DECL_BUILT_IN (decl)
+ && !DECL_ARTIFICIAL (decl))
+ {
+ if (first)
+ {
+ /* Debug: flip MIPS16 on each function. */
+ mips16_flipper = !mips16_flipper;
+ if (mips16_flipper)
+ is_mips16 = !is_mips16;
+ }
+ else
+ /* Don't flip after first again. */
+ is_mips16 = SYMBOL_REF_MIPS16_FUNC_P (symbol);
+ }
+
+ /* If there was an explicit -mno-mips16, then prevent MIPS16
+ selection, even when an explicit attribute is given. */
+ if ((target_flags_explicit & MASK_MIPS16)
+ && mips_base_mips16 == 0)
+ is_mips16 = 0;
+
+ if (is_mips16 && (flag_pic || TARGET_ABICALLS))
+ {
+ warning (0, "%J%s is not supported with mips16 attribute on '%F'; attribute ignored",
+ decl,
+ (flag_pic > 1 ? "-fPIC"
+ : flag_pic ? "-fpic"
+ : "-mabicalls"),
+ decl);
+ is_mips16 = 0;
+ }
+
+ if (is_mips16)
+ SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_MIPS16_FUNC;
+
}
}
Index: gcc/doc/extend.texi
===================================================================
*** gcc/doc/extend.texi (revision 127016)
--- gcc/doc/extend.texi (working copy)
*************** long as the old pointer is never referre
*** 2191,2196 ****
--- 2191,2214 ----
to the new pointer) after the function returns a non-@code{NULL}
value.
+ @item mips16/nomips16
+ @cindex @code{mips16} attribute
+ @cindex @code{nomips16} attribute
+
+ On MIPS targets, you can use the @code{mips16} and @code{nomips16}
+ function attributes to locally select or turn off MIPS16 code generation.
+ A function with the @code{mips16} attribute is emitted as MIPS16 code
+ unless an explicit @option{-mno-mips16} option was specified on the command
+ line. MIPS16 code generation is disabled for functions with the
+ @code{nomips16} attribute, even if @option{-mips16} was specified on the
+ command line. @xref{MIPS Options}, for more details about these options.
+
+ When compiling files containing mixed MIPS16 and non-MIPS16 code, the
+ preprocessor symbol @code{__mips16} reflects the setting on the command line,
+ not that within individual functions. Mixed MIPS16 and non-MIPS16 code
+ may interact badly with some GCC extensions such as @code{__builtin_apply}
+ (@pxref{Constructing Calls}).
+
@item model (@var{model-name})
@cindex function addressability on the M32R/D
@cindex variable addressability on the IA-64
Index: gcc/doc/invoke.texi
===================================================================
*** gcc/doc/invoke.texi (revision 127016)
--- gcc/doc/invoke.texi (working copy)
*************** Objective-C and Objective-C++ Dialects}.
*** 618,624 ****
@emph{MIPS Options}
@gccoptlist{-EL -EB -march=@var{arch} -mtune=@var{arch} @gol
-mips1 -mips2 -mips3 -mips4 -mips32 -mips32r2 -mips64 @gol
! -mips16 -mno-mips16 -mabi=@var{abi} -mabicalls -mno-abicalls @gol
-mshared -mno-shared -mxgot -mno-xgot -mgp32 -mgp64 @gol
-mfp32 -mfp64 -mhard-float -msoft-float @gol
-msingle-float -mdouble-float -mdsp -mno-dsp -mdspr2 -mno-dspr2 @gol
--- 618,625 ----
@emph{MIPS Options}
@gccoptlist{-EL -EB -march=@var{arch} -mtune=@var{arch} @gol
-mips1 -mips2 -mips3 -mips4 -mips32 -mips32r2 -mips64 @gol
! -mips16 -mno-mips16 -mflip-mips16 @gol
! -mabi=@var{abi} -mabicalls -mno-abicalls @gol
-mshared -mno-shared -mxgot -mno-xgot -mgp32 -mgp64 @gol
-mfp32 -mfp64 -mhard-float -msoft-float @gol
-msingle-float -mdouble-float -mdsp -mno-dsp -mdspr2 -mno-dspr2 @gol
*************** Equivalent to @samp{-march=mips64}.
*** 11529,11534 ****
--- 11530,11545 ----
Generate (do not generate) MIPS16 code. If GCC is targetting a
MIPS32 or MIPS64 architecture, it will make use of the MIPS16e ASE@.
+ MIPS16 code generation can also be controlled on a per-function basis
+ by means of @code{mips16} and @code{nomips16} attributes.
+ @xref{Function Attributes}, for more information.
+
+ @item -mflip-mips16
+ @opindex mflip-mips16
+ Generate MIPS16 code on alternating functions. This option is provided
+ for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
+ not intended for ordinary use in compiling user code.
+
@item -mabi=32
@itemx -mabi=o64
@itemx -mabi=n32
Index: gcc/testsuite/gcc.target/mips/mips16-attributes.c
===================================================================
*** gcc/testsuite/gcc.target/mips/mips16-attributes.c (revision 0)
--- gcc/testsuite/gcc.target/mips/mips16-attributes.c (revision 0)
***************
*** 0 ****
--- 1,82 ----
+ /* Verify that mips16 and nomips16 attributes work, checking all combinations
+ of calling a nomips16/mips16/default function from a nomips16/mips16/default
+ function. */
+ /* { dg-do run } */
+
+ #include <stdlib.h>
+
+ #define ATTR1 __attribute__ ((nomips16))
+ #define ATTR2 __attribute__ ((mips16))
+ #define ATTR3
+
+ double ATTR1
+ f1 (int i, float f, double d)
+ {
+ return i + f + d;
+ }
+
+ double ATTR2
+ f2 (int i, float f, double d)
+ {
+ return i + f + d;
+ }
+
+ double ATTR3
+ f3 (int i, float f, double d)
+ {
+ return i + f + d;
+ }
+
+ void ATTR1
+ g1 (int i, float f, double d)
+ {
+ double r = i + f + d;
+
+ if (f1 (i, f, d) != r)
+ abort ();
+ if (f2 (i+1, f+1, d+1) != r + 3)
+ abort ();
+ if (f3 (i+2, f+2, d+2) != r + 6)
+ abort ();
+ }
+
+ void ATTR2
+ g2 (int i, float f, double d)
+ {
+ double r = i + f + d;
+
+ if (f1 (i, f, d) != r)
+ abort ();
+ if (f2 (i+1, f+1, d+1) != r + 3)
+ abort ();
+ if (f3 (i+2, f+2, d+2) != r + 6)
+ abort ();
+ }
+
+ void ATTR3
+ g3 (int i, float f, double d)
+ {
+ double r = i + f + d;
+
+ if (f1 (i, f, d) != r)
+ abort ();
+ if (f2 (i+1, f+1, d+1) != r + 3)
+ abort ();
+ if (f3 (i+2, f+2, d+2) != r + 6)
+ abort ();
+ }
+
+ int ATTR3
+ main (void)
+ {
+ int i = 1;
+ float f = -2.0;
+ double d = 3.0;
+
+ g1 (i, f, d);
+ g2 (i, f, d);
+ g3 (i, f, d);
+
+ exit (0);
+ }
+
Index: gcc/testsuite/gcc.c-torture/compile/mipscop-1.c
===================================================================
*** gcc/testsuite/gcc.c-torture/compile/mipscop-1.c (revision 126515)
--- gcc/testsuite/gcc.c-torture/compile/mipscop-1.c (working copy)
***************
*** 1,9 ****
/* { dg-do compile { target mips*-*-* } } */
- #ifndef __mips16
register unsigned int cp0count asm ("$c0r1");
! int
main (int argc, char *argv[])
{
unsigned int d;
--- 1,8 ----
/* { dg-do compile { target mips*-*-* } } */
register unsigned int cp0count asm ("$c0r1");
! int __attribute__ ((nomips16))
main (int argc, char *argv[])
{
unsigned int d;
*************** main (int argc, char *argv[])
*** 11,14 ****
d = cp0count + 3;
printf ("%d\n", d);
}
- #endif
--- 10,12 ----
Index: gcc/testsuite/gcc.c-torture/compile/mipscop-2.c
===================================================================
*** gcc/testsuite/gcc.c-torture/compile/mipscop-2.c (revision 126515)
--- gcc/testsuite/gcc.c-torture/compile/mipscop-2.c (working copy)
***************
*** 1,11 ****
/* { dg-do compile { target mips*-*-* } } */
- #ifndef __mips16
register unsigned int c3r1 asm ("$c3r1");
extern unsigned int b, c;
! void
foo ()
{
unsigned int a, d;
--- 1,10 ----
/* { dg-do compile { target mips*-*-* } } */
register unsigned int c3r1 asm ("$c3r1");
extern unsigned int b, c;
! void __attribute__ ((nomips16))
foo ()
{
unsigned int a, d;
*************** foo ()
*** 17,20 ****
d = c3r1;
printf ("%d\n", d);
}
- #endif
--- 16,18 ----
Index: gcc/testsuite/gcc.c-torture/compile/mipscop-3.c
===================================================================
*** gcc/testsuite/gcc.c-torture/compile/mipscop-3.c (revision 126515)
--- gcc/testsuite/gcc.c-torture/compile/mipscop-3.c (working copy)
***************
*** 1,11 ****
/* { dg-do compile { target mips*-*-* } } */
- #ifndef __mips16
register unsigned int c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2");
extern unsigned int b, c;
! void
foo ()
{
unsigned int a, d;
--- 1,10 ----
/* { dg-do compile { target mips*-*-* } } */
register unsigned int c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2");
extern unsigned int b, c;
! void __attribute__ ((nomips16))
foo ()
{
unsigned int a, d;
*************** foo ()
*** 17,20 ****
d = c3r1;
printf ("%d\n", d);
}
- #endif
--- 16,18 ----
Index: gcc/testsuite/gcc.c-torture/compile/mipscop-4.c
===================================================================
*** gcc/testsuite/gcc.c-torture/compile/mipscop-4.c (revision 126515)
--- gcc/testsuite/gcc.c-torture/compile/mipscop-4.c (working copy)
***************
*** 1,11 ****
/* { dg-do compile { target mips*-*-* } } */
- #ifndef __mips16
register unsigned long c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2");
extern unsigned long b, c;
! void
foo ()
{
unsigned long a, d;
--- 1,10 ----
/* { dg-do compile { target mips*-*-* } } */
register unsigned long c3r1 asm ("$c3r1"), c3r2 asm ("$c3r2");
extern unsigned long b, c;
! void __attribute__ ((nomips16))
foo ()
{
unsigned long a, d;
*************** foo ()
*** 17,20 ****
d = c3r1;
printf ("%d\n", d);
}
! #endif
--- 16,19 ----
d = c3r1;
printf ("%d\n", d);
}
!
Index: gcc/testsuite/gcc.dg/torture/mips-hilo-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/mips-hilo-1.c (revision 126515)
--- gcc/testsuite/gcc.dg/torture/mips-hilo-1.c (working copy)
***************
*** 6,15 ****
extern void abort (void);
extern void exit (int);
- #if !defined(__mips16)
-
#define DECLARE(TYPE) \
! TYPE __attribute__ ((noinline)) \
f1##TYPE (TYPE x1, TYPE x2, TYPE x3) \
{ \
TYPE t1, t2; \
--- 6,13 ----
extern void abort (void);
extern void exit (int);
#define DECLARE(TYPE) \
! TYPE __attribute__ ((noinline)) __attribute__ ((nomips16)) \
f1##TYPE (TYPE x1, TYPE x2, TYPE x3) \
{ \
TYPE t1, t2; \
*************** extern void exit (int);
*** 19,25 ****
return t1 + t2; \
} \
\
! TYPE __attribute__ ((noinline)) \
f2##TYPE (TYPE x1, TYPE x2, TYPE x3) \
{ \
TYPE t1, t2; \
--- 17,23 ----
return t1 + t2; \
} \
\
! TYPE __attribute__ ((noinline)) __attribute__ ((nomips16)) \
f2##TYPE (TYPE x1, TYPE x2, TYPE x3) \
{ \
TYPE t1, t2; \
*************** main ()
*** 73,78 ****
#endif
exit (0);
}
- #else
- int main () { exit (0); }
- #endif
--- 71,73 ----
Index: gcc/testsuite/gcc.dg/torture/mips-hilo-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/mips-hilo-2.c (revision 126515)
--- gcc/testsuite/gcc.dg/torture/mips-hilo-2.c (working copy)
***************
*** 5,14 ****
extern void abort (void);
extern void exit (int);
- #if !defined(__mips16)
unsigned int g;
! unsigned long long f (unsigned int x)
{
union { unsigned long long ll; unsigned int parts[2]; } u;
--- 5,13 ----
extern void abort (void);
extern void exit (int);
unsigned int g;
! unsigned __attribute__ ((nomips16)) long long f (unsigned int x)
{
union { unsigned long long ll; unsigned int parts[2]; } u;
*************** unsigned long long f (unsigned int x)
*** 17,23 ****
return u.ll;
}
! int main ()
{
union { unsigned long long ll; unsigned int parts[2]; } u;
--- 16,22 ----
return u.ll;
}
! int __attribute__ ((nomips16)) main ()
{
union { unsigned long long ll; unsigned int parts[2]; } u;
*************** int main ()
*** 26,31 ****
abort ();
exit (0);
}
- #else
- int main () { exit (0); }
- #endif
--- 25,27 ----
Index: gcc/testsuite/gcc.dg/torture/pr19683-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr19683-1.c (revision 126515)
--- gcc/testsuite/gcc.dg/torture/pr19683-1.c (working copy)
***************
*** 6,12 ****
extern void abort (void);
extern void exit (int);
- #ifndef __mips16
#define REPEAT10(X, Y) \
X(Y##0); X(Y##1); X(Y##2); X(Y##3); X(Y##4); \
X(Y##5); X(Y##6); X(Y##7); X(Y##8); X(Y##9)
--- 6,11 ----
*************** extern void exit (int);
*** 17,23 ****
union u { unsigned long long ll; unsigned int i[2]; };
! unsigned int
foo (volatile unsigned int *ptr)
{
union u u;
--- 16,22 ----
union u { unsigned long long ll; unsigned int i[2]; };
! unsigned int __attribute__ ((nomips16))
foo (volatile unsigned int *ptr)
{
union u u;
*************** foo (volatile unsigned int *ptr)
*** 30,36 ****
return result;
}
! int
main (void)
{
unsigned int array[] = { 1000 * 1000 * 1000 };
--- 29,35 ----
return result;
}
! int __attribute__ ((nomips16))
main (void)
{
unsigned int array[] = { 1000 * 1000 * 1000 };
*************** main (void)
*** 41,50 ****
abort ();
exit (0);
}
- #else
- int
- main (void)
- {
- exit (0);
- }
- #endif
--- 40,42 ----