From: Sandra Loosemore Date: Wed, 5 Sep 2007 14:40:04 +0000 (-0400) Subject: Add mips16/nomips16 function attributes and -mflip-mips16 option for testing mixed... X-Git-Tag: releases/gcc-4.3.0~2867 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f9e4a411f9209f967b25b2f038b117db132139a5;p=thirdparty%2Fgcc.git Add mips16/nomips16 function attributes and -mflip-mips16 option for testing mixed-mode compilation. 2007-09-05 Sandra Loosemore David Ung Nigel Stephens Add mips16/nomips16 function attributes and -mflip-mips16 option for testing mixed-mode compilation. gcc/ * config/mips/mips.opt (mflip-mips16): New. * config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Define. (SYMBOL_FLAG_MIPS16_FUNC_P): Define. * config/mips/mips.c (mips_base_target_flags): New. (mips_base_mips16): New. (mips_base_schedule_insns): New. (mips_base_reorder_blocks_and_partition): New. (mips_base_align_loops): New. (mips_base_align_jumps): New. (mips_base_align_functions): New. (mips16_flipper): New. (mips_attribute_table): Add "mips16" and "nomips16" entries. (TARGET_SET_CURRENT_FUNCTION): Define. (mips_mips16_type_p, mips_nomips16_type_p): New. (mips_comp_type_attributes): Check mips16/nomips16 attributes. (mips_function_ok_for_sibcall): Make it deal with functions with mips16 attributes. (mips_init_split_addresses): New, split out from override_options. (mips_init_relocs): New, split out from override_options. (was_mips16_p): New. (mips_set_mips16_mode): New, split out from override_options. (mips_set_current_function): New. (override_options): Add sorry for unsupported mips16/pic combination. Remove error for mips16/dsp combination. Save base option settings. (mips_file_start): Move mips16 mode setting output from here.... (mips_output_function_prologue): ....to here. (mips_output_mi_thunk): Check for mips16 function. (build_mips16_function_stub): Don't set .mips16 here. (build_mips16_call_stub): Likewise. (mips_expand_builtin): Error in mips16 mode. (mips_use_mips16_mode_p): New. (mips_encode_section_info): Check for mips16 function, and 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. gcc/testsuite/ * gcc.target/mips/mips16-attributes.c: New. Co-Authored-By: David Ung Co-Authored-By: Nigel Stephens From-SVN: r128134 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b32119985697..2051ef1a05c5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,54 @@ +2007-09-05 Sandra Loosemore + David Ung + Nigel Stephens + + Add mips16/nomips16 function attributes and -mflip-mips16 option + for testing mixed-mode compilation. + + * config/mips/mips.opt (mflip-mips16): New. + + * config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Define. + (SYMBOL_FLAG_MIPS16_FUNC_P): Define. + + * config/mips/mips.c (mips_base_target_flags): New. + (mips_base_mips16): New. + (mips_base_schedule_insns): New. + (mips_base_reorder_blocks_and_partition): New. + (mips_base_align_loops): New. + (mips_base_align_jumps): New. + (mips_base_align_functions): New. + (mips16_flipper): New. + (mips_attribute_table): Add "mips16" and "nomips16" entries. + (TARGET_SET_CURRENT_FUNCTION): Define. + (mips_mips16_type_p, mips_nomips16_type_p): New. + (mips_comp_type_attributes): Check mips16/nomips16 attributes. + (mips_function_ok_for_sibcall): Make it deal with functions with + mips16 attributes. + (mips_init_split_addresses): New, split out from override_options. + (mips_init_relocs): New, split out from override_options. + (was_mips16_p): New. + (mips_set_mips16_mode): New, split out from override_options. + (mips_set_current_function): New. + (override_options): Add sorry for unsupported mips16/pic + combination. Remove error for mips16/dsp combination. Save + base option settings. + (mips_file_start): Move mips16 mode setting output from here.... + (mips_output_function_prologue): ....to here. + (mips_output_mi_thunk): Check for mips16 function. + (build_mips16_function_stub): Don't set .mips16 here. + (build_mips16_call_stub): Likewise. + (mips_expand_builtin): Error in mips16 mode. + (mips_use_mips16_mode_p): New. + (mips_encode_section_info): Check for mips16 function, and 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. + 2007-09-05 Sandra Loosemore - gcc/ * config/mips/mips.c (mips_legitimize_tls_address): Call sorry if we encounter TLS address in MIPS16 mode. (mips_legitimize_const_move): Check cannot_force_const_mem for diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 937f5904550c..ae412dea6413 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -424,6 +424,8 @@ static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx); static void mips_encode_section_info (tree, rtx, int); static void mips_extra_live_on_entry (bitmap); static int mips_comp_type_attributes (const_tree, const_tree); +static void mips_set_mips16_mode (int); +static void mips_set_current_function (tree); 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; @@ -617,6 +619,18 @@ int mips_abi = MIPS_ABI_DEFAULT; /* Cost information to use. */ const struct mips_rtx_cost_data *mips_cost; +/* Remember the ambient target flags, excluding mips16. */ +static int mips_base_target_flags; +/* The mips16 command-line target flags only. */ +static bool mips_base_mips16; +/* Similar copies of option settings. */ +static int mips_base_schedule_insns; /* flag_schedule_insns */ +static int mips_base_reorder_blocks_and_partition; /* flag_reorder... */ +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 -mtext-loads setting. */ enum mips_code_readable_setting mips_code_readable = CODE_READABLE_YES; @@ -715,6 +729,9 @@ const struct attribute_spec mips_attribute_table[] = { "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 } }; @@ -1251,6 +1268,9 @@ static const unsigned char mips16e_save_restore_regs[] = { #undef TARGET_FUNCTION_OK_FOR_SIBCALL #define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION mips_set_current_function + #undef TARGET_VALID_POINTER_MODE #define TARGET_VALID_POINTER_MODE mips_valid_pointer_mode #undef TARGET_RTX_COSTS @@ -1369,6 +1389,19 @@ mips_far_type_p (const_tree type) || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL); } +/* Similar predicates for "mips16"/"nomips16" attributes. */ + +static bool +mips_mips16_type_p (const_tree type) +{ + return lookup_attribute ("mips16", TYPE_ATTRIBUTES (type)) != NULL; +} + +static bool +mips_nomips16_type_p (const_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 @@ -1387,6 +1420,11 @@ mips_comp_type_attributes (const_tree type1, const_tree type2) 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; } @@ -3789,13 +3827,22 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p) } -/* We can handle any sibcall when TARGET_SIBCALLS is true. */ +/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ static bool -mips_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, - tree exp ATTRIBUTE_UNUSED) +mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) { - return TARGET_SIBCALLS; + if (!TARGET_SIBCALLS) + return false; + + /* We can't do a sibcall if the called function is a MIPS16 function + because there is no direct "jx" instruction equivalent to "jalx" to + switch the ISA mode. */ + if (decl && SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (decl), 0))) + return false; + + /* Otherwise OK. */ + return true; } /* Emit code to move general operand SRC into condition-code @@ -5038,6 +5085,231 @@ mips_set_tune (const struct mips_cpu_info *info) } } +/* Initialize mips_split_addresses from the associated command-line + settings. + + mips_split_addresses is a half-way house between explicit + relocations and the traditional assembler macros. It can + split absolute 32-bit symbolic constants into a high/lo_sum + pair but uses macros for other sorts of access. + + Like explicit relocation support for REL targets, it relies + on GNU extensions in the assembler and the linker. + + Although this code should work for -O0, it has traditionally + been treated as an optimization. */ + +static void +mips_init_split_addresses (void) +{ + if (!TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES + && optimize && !flag_pic + && !ABI_HAS_64BIT_SYMBOLS) + mips_split_addresses = 1; + else + mips_split_addresses = 0; +} + +/* (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_ABSOLUTE] = true; + mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; + } + } + else + { + if (TARGET_EXPLICIT_RELOCS || mips_split_addresses || TARGET_MIPS16) + { + mips_split_p[SYMBOL_ABSOLUTE] = true; + mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi("; + mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; + + mips_lo_relocs[SYMBOL_32_HIGH] = "%hi("; + } + } + + if (TARGET_MIPS16) + { + /* The high part is provided by a pseudo copy of $gp. */ + mips_split_p[SYMBOL_GP_RELATIVE] = true; + mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%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_GP_RELATIVE] = "%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; + +/* Set up the target-dependent global state so that it matches the + current function's ISA mode. */ + +static void +mips_set_mips16_mode (int mips16_p) +{ + if (mips16_p == was_mips16_p) + return; + + /* Restore base settings of various flags. */ + target_flags = mips_base_target_flags; + align_loops = mips_base_align_loops; + align_jumps = mips_base_align_jumps; + align_functions = mips_base_align_functions; + flag_schedule_insns = mips_base_schedule_insns; + flag_reorder_blocks_and_partition = mips_base_reorder_blocks_and_partition; + flag_delayed_branch = mips_flag_delayed_branch; + + if (mips16_p) + { + /* Select mips16 instruction set. */ + target_flags |= MASK_MIPS16; + + /* 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; + + /* Silently disable DSP extensions. */ + target_flags &= ~MASK_DSP; + target_flags &= ~MASK_DSPR2; + } + 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; + + /* Provide default values for align_* for 64-bit targets. */ + if (TARGET_64BIT) + { + if (align_loops == 0) + align_loops = 8; + if (align_jumps == 0) + align_jumps = 8; + if (align_functions == 0) + align_functions = 8; + } + } + + /* (Re)initialize mips target internals for new ISA. */ + mips_init_split_addresses (); + mips_init_relocs (); + + if (was_mips16_p >= 0) + /* Reinitialize target-dependent state. */ + target_reinit (); + + was_mips16_p = TARGET_MIPS16; +} + +/* Implement TARGET_SET_CURRENT_FUNCTION. Decide whether the current + function should use the MIPS16 ISA and switch modes accordingly. */ + +static void +mips_set_current_function (tree fndecl) +{ + int mips16p; + if (fndecl) + mips16p = SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (fndecl), 0)); + else + mips16p = mips_base_mips16; + mips_set_mips16_mode (mips16p); +} + /* Implement TARGET_HANDLE_OPTION. */ static bool @@ -5265,6 +5537,14 @@ override_options (void) target_flags &= ~MASK_ABICALLS; } + /* MIPS16 cannot generate PIC yet. */ + if (TARGET_MIPS16 && (flag_pic || TARGET_ABICALLS)) + { + sorry ("MIPS16 PIC"); + 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 @@ -5282,54 +5562,12 @@ override_options (void) if (TARGET_VXWORKS_RTP && mips_section_threshold > 0) warning (0, "-G and -mrtp are incompatible"); - /* mips_split_addresses is a half-way house between explicit - relocations and the traditional assembler macros. It can - split absolute 32-bit symbolic constants into a high/lo_sum - pair but uses macros for other sorts of access. - - Like explicit relocation support for REL targets, it relies - on GNU extensions in the assembler and the linker. - - Although this code should work for -O0, it has traditionally - been treated as an optimization. */ - if (!TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES - && optimize && !flag_pic - && !ABI_HAS_64BIT_SYMBOLS) - mips_split_addresses = 1; - else - mips_split_addresses = 0; - /* -mvr4130-align is a "speed over size" optimization: it usually produces faster code, but at the expense of more nops. Enable it at -O3 and above. */ if (optimize > 2 && (target_flags_explicit & MASK_VR4130_ALIGN) == 0) target_flags |= MASK_VR4130_ALIGN; - if (TARGET_MIPS16) - { - /* 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; - } - /* Prefer a call to memcpy over inline code when optimizing for size, though see MOVE_RATIO in mips.h. */ if (optimize_size && (target_flags_explicit & MASK_MEMCPY) == 0) @@ -5363,9 +5601,6 @@ override_options (void) 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; @@ -5493,120 +5728,9 @@ override_options (void) initialized yet, so we can't use that here. */ 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; - if (align_jumps == 0) - align_jumps = 8; - if (align_functions == 0) - align_functions = 8; - } - /* 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_ABSOLUTE] = true; - mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; - } - } - else - { - if (TARGET_EXPLICIT_RELOCS || mips_split_addresses || TARGET_MIPS16) - { - mips_split_p[SYMBOL_ABSOLUTE] = true; - mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi("; - mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; - - mips_lo_relocs[SYMBOL_32_HIGH] = "%hi("; - } - } - - if (TARGET_MIPS16) - { - /* The high part is provided by a pseudo copy of $gp. */ - mips_split_p[SYMBOL_GP_RELATIVE] = true; - mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%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_GP_RELATIVE] = "%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("; - /* Default to working around R4000 errata only if the processor was selected explicitly. */ if ((target_flags_explicit & MASK_FIX_R4000) == 0 @@ -5618,6 +5742,19 @@ override_options (void) 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. */ + mips_base_mips16 = TARGET_MIPS16; + mips_base_target_flags = target_flags; + mips_base_schedule_insns = flag_schedule_insns; + mips_base_reorder_blocks_and_partition = flag_reorder_blocks_and_partition; + mips_base_align_loops = align_loops; + mips_base_align_jumps = align_jumps; + mips_base_align_functions = align_functions; + mips_flag_delayed_branch = flag_delayed_branch; + + /* Now select the mips16 or 32-bit instruction set, as requested. */ + mips_set_mips16_mode (mips_base_mips16); } /* Swap the register information for registers I and I + 1, which @@ -6373,9 +6510,6 @@ mips_file_start (void) 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, @@ -7230,6 +7364,12 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) && current_function_args_info.fp_code != 0) build_mips16_function_stub (file); + /* 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) { /* Get the function name the same way that toplev.c does before calling @@ -8186,7 +8326,6 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, TARGET_CALL_SAVED_GP ? 15 : GLOBAL_POINTER_REGNUM; SET_REGNO (pic_offset_table_rtx, cfun->machine->global_pointer); - } /* Set up the global pointer for n32 or n64 abicalls. If @@ -8237,7 +8376,8 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, /* 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)) + 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. @@ -9073,8 +9213,6 @@ build_mips16_function_stub (FILE *file) fputs ("\n", file); } - fprintf (file, "\t.set\tmips16\n"); - switch_to_section (function_section (current_function_decl)); } @@ -9406,8 +9544,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code) 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); @@ -11648,6 +11784,13 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); fcode = DECL_FUNCTION_CODE (fndecl); + if (TARGET_MIPS16) + { + error ("built-in function %qs not supported for MIPS16", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + return const0_rtx; + } + bdesc = NULL; for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++) { @@ -12154,6 +12297,43 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target) const1_rtx, const0_rtx); } +/* Return true if we should force MIPS16 mode for the function named by + the SYMBOL_REF SYMBOL, which belongs to DECL and has type TYPE. + FIRST is true if this is the first time handling this decl. */ + +static bool +mips_use_mips16_mode_p (rtx symbol, tree decl, int first, tree type) +{ + tree parent; + + /* Explicit function attributes take precedence. */ + if (mips_mips16_type_p (type)) + return true; + if (mips_nomips16_type_p (type)) + return false; + + /* A nested function should inherit the MIPS16 setting from its parent. */ + parent = decl_function_context (decl); + if (parent) + return SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (parent), 0)); + + /* Handle -mflip-mips16. */ + if (TARGET_FLIP_MIPS16 + && !DECL_BUILT_IN (decl) + && !DECL_ARTIFICIAL (decl)) + { + if (!first) + /* Use the setting we picked first time around. */ + return SYMBOL_REF_MIPS16_FUNC_P (symbol); + + mips16_flipper = !mips16_flipper; + if (mips16_flipper) + return !mips_base_mips16; + } + + return mips_base_mips16; +} + /* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL. FIRST is true if this is the first time handling this decl. */ @@ -12165,10 +12345,19 @@ mips_encode_section_info (tree decl, rtx rtl, int first) if (TREE_CODE (decl) == FUNCTION_DECL) { rtx symbol = XEXP (rtl, 0); + tree type = TREE_TYPE (decl); - if ((TARGET_LONG_CALLS && !mips_near_type_p (TREE_TYPE (decl))) - || mips_far_type_p (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; + + if (mips_use_mips16_mode_p (symbol, decl, first, type)) + { + if (flag_pic || TARGET_ABICALLS) + sorry ("MIPS16 PIC"); + else + SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_MIPS16_FUNC; + } } } diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index a44460b08532..cc6b50011be7 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2301,6 +2301,11 @@ typedef struct mips_args { #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) + /* True if we're generating a form of MIPS16 code in which jump tables are stored in the text section and encoded as 16-bit PC-relative offsets. This is only possible when general text loads are allowed, diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt index 6f6c109187cf..7f60bebc7b82 100644 --- a/gcc/config/mips/mips.opt +++ b/gcc/config/mips/mips.opt @@ -42,6 +42,10 @@ mbranch-likely 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 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 2016e451de57..0012740476b9 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2202,6 +2202,24 @@ long as the old pointer is never referred to (including comparing it 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, +while MIPS16 code generation is disabled for functions with the +@code{nomips16} attribute. These attributes override the +@option{-mips16} and @option{-mno-mips16} options on the command line +(@pxref{MIPS 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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9164078b75f5..734c8edfb45e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -620,7 +620,8 @@ Objective-C and Objective-C++ Dialects}. @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 +-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 @@ -11626,6 +11627,16 @@ Equivalent to @samp{-march=mips64}. 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c6ba699c47f0..e00d89c5ff26 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-09-05 Sandra Loosemore + David Ung + Nigel Stephens + + * gcc.target/mips/mips16-attributes.c: New. + 2007-09-05 Paul Thomas PR fortran/31564 diff --git a/gcc/testsuite/gcc.target/mips/mips16-attributes.c b/gcc/testsuite/gcc.target/mips/mips16-attributes.c new file mode 100644 index 000000000000..dca75e5d02f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/mips16-attributes.c @@ -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 { target mipsisa*-*-elf* } } */ + +#include + +#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); +} +