public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* revised PATCH: per-function back end reinitialization, part 2/2
@ 2007-07-30 19:37 Sandra Loosemore
  2007-08-04  9:53 ` Richard Sandiford
  0 siblings, 1 reply; 5+ messages in thread
From: Sandra Loosemore @ 2007-07-30 19:37 UTC (permalink / raw)
  To: GCC Patches
  Cc: David Ung, Nigel Stephens, Richard Sandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 392 bytes --]

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


[-- Attachment #2: 12b-mips16-funcattr.log --]
[-- Type: text/x-log, Size: 3562 bytes --]

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.
	



[-- Attachment #3: 12b-mips16-funcattr.patch --]
[-- Type: text/x-patch, Size: 57043 bytes --]

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 }
  };
  \f
*************** static const unsigned char mips16e_save_
*** 1203,1209 ****
    31, 30, 23, 22, 21, 20, 19, 18, 17, 16, 7, 6, 5, 4
  };
  \f
! /* 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
  };
  \f
! /* 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;
  }
  \f
*************** 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;
  }
  \f
  /* 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;
  }
  \f
  /* 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 ----

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: revised PATCH: per-function back end reinitialization, part 2/2
  2007-07-30 19:37 revised PATCH: per-function back end reinitialization, part 2/2 Sandra Loosemore
@ 2007-08-04  9:53 ` Richard Sandiford
  2007-08-06  7:16   ` Sandra Loosemore
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Sandiford @ 2007-08-04  9:53 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: GCC Patches, David Ung, Nigel Stephens, Ian Lance Taylor

Sandra Loosemore <sandra@codesourcery.com> writes:
> ! /* 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;

Why are only some of these GTY(())?

> +   /* 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));

I'm not sure I follow.  What sort of built-in functions are we talking
about here?  What is the TREE_TYPE test doing?  Do we ever see
error_mark_node here?  (My understanding is that we don't any more.)

> ! /* 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.  */

I think this is attacking it at the wrong level.  MIPS16 functions
should not be const_sibcall_operands (a predicate to be invented
for this purpose).  We will then force the address into a register.
That might still be a win over forcing a frame and using a normal
call.

> *************** 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)

I think this is simply:

      if ((TARGET_MIPS16 || mips_base_mips16)
          && cum->fp_code != 0)

> + /* Resets compiler middle end to match the instruction set mode selected for
> +    the current function.  */
> + static void

I'd prefer something like:

/* Set up the target-dependent global state so that it matches the
   current function's ISA mode.  */

> + 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) 
> +     {
> + 

Stray line.
> +       /* MIPS16 mode is incompatible with TARGET_DSP.  */

> +       if (TARGET_DSP)
> + 	error ("MIPS16 mode cannot be used with -mdsp");

Sorry, I know this is going back on what I said before, but I now
see that this is inconsitent with the way you're handling MIPS16 PIC.
Perhaps we should go back to leaving the error in mips_override_options
and simply mask out the DSP flags here.

> +       /* Select mips16 instruction set.  */
> +       target_flags |= MASK_MIPS16 | mips_base_mips16;

I don't understand this.  Isn't mips_base_mips16 either MASK_MIPS16 or 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;

I think it'd make sense to move the code that initialises
mips_split_addresses to a mips_init_split_addresses function
(like your mips_init_relocs) and call it from this function.
The fewer "base" variables the better IMO.

> +       /* 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;

I think we should simply restore the defaults before the "if (mips16_p)"
statement, like we do with the target flags, and move the overrides
to the !mips16_p arm.

> +       /* We don't have a thread pointer access instruction on MIPS16, or
> + 	 appropriate TLS relocations.  */
> +       targetm.have_tls = false;
> + 
> +     }

Stray line.

> +       /* Reset to select base non-mips16 ISA.  */
> +       target_flags &= ~(MASK_MIPS16);

Redundant brackets.

> +   if (!first)
> +     /* Reinitialize target-dependent state.  */
> +     target_reinit ();

Might as well just check "was_mips16_p >= 0" instead, and drop "first".

> +   was_mips16_p = !!TARGET_MIPS16;

No need for the !!; TARGET_MIPS16 is already 0 or 1.

> + /* 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)

/* Implement TARGET_PREPARE_FUNCTION_START.  Decide whether the current
   function should use the MIPS16 ISA and switch modes accordingly.  */

Blank line before function.

> + {
> +   tree x;
> + 
> +   if (!fndecl)
> +     return;

Why might it be null?  The documentation in the target-independent patch
doesn't explain.

> +   /* 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;

Please test without and see. ;)  Again, if we do, the documentation
for the hook should say why.

> + /* 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_END_OF_FILE_CLEANUP.  Restore the MIPS16 setting specified
   on the command line.  */

Blank line before function.

> +   /* 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;
> + 

Why reset it?  The comment is misleading at best, because we actually
restore the setting at the end of this function (i.e. at the end of
mips_override_options).

> +   /* 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;
> +     }
> + 

This should be a sorry rather than a warning.  The option name you use
isn't necessarily going to be more helpful either.  E.g. if the user is
using -mabicalls with binutils that don't support -mno-shared, you're
printing -fpic when the user specifies -mabicalls.  You're also printing
-fpic when the user specifies -fpie.  How about simply:

    sorry ("MIPS16 PIC");

> -       /* 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;

The patch appears to discard this entirely.  I don't think it should.

> --- 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;

The last two lines should be deleted now; mips_set_mips16_mode does
it for us.

> *************** 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)

This doesn't look right.  What is it supposed to be doing?

> *************** 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;

Following on from the comments above, I think these variables should
be caching values for which the only target-dependent changes are those
that apply to both modes.  Then the mips16_p and !mips16_p arms of
mips_set_mips16_mode should do the mode-dependent stuff.  That's almost
where we are with the patch as it stands; I've tried to catch the cases
where it isn't.

> *************** 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.

With the change suggested above, this condition should hopefully
reduce to !const_sibcall_operand (fnaddr, VOIDmode).

> *************** 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

Why is this needed?

> + /* 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;
> + 

For the record, we should use hash tables here.  However, since you're
just extending the use of an existing structure, let's leave it be for now.

> !   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);

Why is this needed?

> *************** 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);
> + 	}

Please split this into a separate function that returns true if
mips16 mode should be forced.

> +       /* 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;

This seems very counter-intuitive to me.  If we need a way of ignoring
the attributes, let's add an option specifically for it.  I think that
can be done as a follow-on patch, if there's demand.

> +       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);

Again, this should be a sorry().

> + @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}).  

Nice docs, thanks.  Watch out for the trailing whitespace though.

Richard

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: revised PATCH: per-function back end reinitialization, part 2/2
  2007-08-04  9:53 ` Richard Sandiford
@ 2007-08-06  7:16   ` Sandra Loosemore
  2007-08-06  7:46     ` Richard Sandiford
  2007-08-06 18:22     ` David Ung
  0 siblings, 2 replies; 5+ messages in thread
From: Sandra Loosemore @ 2007-08-06  7:16 UTC (permalink / raw)
  To: GCC Patches, David Ung, Nigel Stephens, Ian Lance Taylor, richard

Richard Sandiford wrote:
> Sandra Loosemore <sandra@codesourcery.com> writes:
>> ! /* 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;
> 
> Why are only some of these GTY(())?

For that matter, why are any of these marked GTY(())?  I assumed it had 
something to do with precompiled header support, which is a bit of the compiler 
I know nothing about (yet).  David, Nigel?

>> +   /* 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));
> 
> I'm not sure I follow.  What sort of built-in functions are we talking
> about here?  What is the TREE_TYPE test doing?  Do we ever see
> error_mark_node here?  (My understanding is that we don't any more.)

Hrmmm.  This didn't look implausible to me, but I tried commenting it out and 
didn't see any testsuite regressions with -mflip-mips16.  (In fact, that even 
fixed a few.)  David, was there a specific test case that was failing without 
this?  Otherwise I think we can chuck this part of the patch, as well as the 
changes to build_mips16_function_stub to support it.

>> > ! /* 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.  */
> 
> I think this is attacking it at the wrong level.  MIPS16 functions
> should not be const_sibcall_operands (a predicate to be invented
> for this purpose).  We will then force the address into a register.
> That might still be a win over forcing a frame and using a normal
> call.

I don't understand this comment.  I can move the test in mips_output_mi_thunk 
into a predicate, as you suggested farther down, but do you think what 
mips_function_ok_for_sibcall is doing is wrong?  Should it also be calling the 
same predicate?  Or is your complaint just directed at the comment attached to 
the function?

>> + static void
>> + mips_prepare_function_start (tree fndecl)
>> + {
>> +   tree x;
>> + 
>> +   if (!fndecl)
>> +     return;
> 
> Why might it be null?  The documentation in the target-independent patch
> doesn't explain.

This is the case for init_dummy_function_start in function.c.  I can update the 
docs, or would it be better to bypass invoking the hook altogether in that case?

>> +   /* 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;
> 
> Please test without and see. ;)  Again, if we do, the documentation
> for the hook should say why.

This piece of code is forcing nested functions to be compiled in the same mips16 
mode as their enclosing top-level function, so it really doesn't have anything 
to do with the behavior of the hook.  Assuming the semantics are what we want, 
though, it would probably be better to do it in mips_encode_section_info, where 
we're processing explicit mips16 annotations and the -mflip-mips16 stuff. 
David, Nigel -- is this what you want?

>> +   /* 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;
>> + 
> 
> Why reset it?  The comment is misleading at best, because we actually
> restore the setting at the end of this function (i.e. at the end of
> mips_override_options).

I think the issue here is that some of the base settings of other flags may 
depend on whether TARGET_MIPS16 is true at the time they are initialized.  Maybe 
there really should not be any such dependencies, but clearing the MASK_MIPS16 
bit ensures that the base settings really are the base settings.  I'll update 
the comment to say so explicitly.

>> *************** 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
> 
> Why is this needed?

Without this change, I get lots of link errors like:

(.text+0x30): relocation truncated to fit: R_MIPS_GPREL16 against `.text'

when running the testsuite in -mflip-mips16 mode.  IIRC, this was related to 
getting the constant pool to come out in the right section during end-of-file 
processing.

>> + /* 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;
>> + 
> 
> For the record, we should use hash tables here.  However, since you're
> just extending the use of an existing structure, let's leave it be for now.

If we take out the bit to make function stubs for builtin functions, then this 
bit of patch can go away, too.

>> !   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);
> 
> Why is this needed?

Maybe it's not, if we can get rid of this whole section of patch.  ;-)

>> +       /* 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;
> 
> This seems very counter-intuitive to me.  If we need a way of ignoring
> the attributes, let's add an option specifically for it.  I think that
> can be done as a follow-on patch, if there's demand.

David, Nigel -- is changing this behavior OK with you in terms of compatibility 
with what SDE does now?

Richard -- thanks for the detailed review.  I've fixed up the other issues you 
noted and am retesting.

-Sandra

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: revised PATCH: per-function back end reinitialization, part 2/2
  2007-08-06  7:16   ` Sandra Loosemore
@ 2007-08-06  7:46     ` Richard Sandiford
  2007-08-06 18:22     ` David Ung
  1 sibling, 0 replies; 5+ messages in thread
From: Richard Sandiford @ 2007-08-06  7:46 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: GCC Patches, David Ung, Nigel Stephens, Ian Lance Taylor

Thanks for the detailed reply.

Sandra Loosemore <sandra@codesourcery.com> writes:
> Richard Sandiford wrote:
>> Sandra Loosemore <sandra@codesourcery.com> writes:
>>> > ! /* 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.  */
>> 
>> I think this is attacking it at the wrong level.  MIPS16 functions
>> should not be const_sibcall_operands (a predicate to be invented
>> for this purpose).  We will then force the address into a register.
>> That might still be a win over forcing a frame and using a normal
>> call.
>
> I don't understand this comment.  I can move the test in mips_output_mi_thunk 
> into a predicate, as you suggested farther down, but do you think what 
> mips_function_ok_for_sibcall is doing is wrong?  Should it also be calling the 
> same predicate?  Or is your complaint just directed at the comment attached to 
> the function?

No, I mean that mips_function_ok_for_sibcall should allow such sibcalls,
and that we should add a new predicate (const_sibcall_operand) that says
whether such sibcalls can use direct jumps.  At the moment, we assume
that const_call_insn_operand covers both normal and sibling calls.

However, I suppose that's not always going to be a win, so let's
leave it be.  It would be nice to restrict the new condition to
const_call_insn_operands though; things like long calls _should_
be sibcalled.

Also, now that the function is nontrivial, please change the function
comment to "Implement TARGET_FUNCTION_OK_FOR_SIBCALL." and move
the detailed comments above each condition:

{
  /* Comment.  */
  if (...)
    return false;

  /* Otherwise we can handle any sibcall when TARGET_SIBCALLS is true.  */
  return TARGET_SIBCALLS;
}

>>> + static void
>>> + mips_prepare_function_start (tree fndecl)
>>> + {
>>> +   tree x;
>>> + 
>>> +   if (!fndecl)
>>> +     return;
>> 
>> Why might it be null?  The documentation in the target-independent patch
>> doesn't explain.
>
> This is the case for init_dummy_function_start in function.c.  I can
> update the docs, or would it be better to bypass invoking the hook
> altogether in that case?

The latter definitely sounds good to me.

>>> +   /* 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;
>> 
>> Please test without and see. ;)  Again, if we do, the documentation
>> for the hook should say why.
>
> This piece of code is forcing nested functions to be compiled in the
> same mips16 mode as their enclosing top-level function, so it really
> doesn't have anything to do with the behavior of the hook.  Assuming
> the semantics are what we want, though, it would probably be better to
> do it in mips_encode_section_info, where we're processing explicit
> mips16 annotations and the -mflip-mips16 stuff.  David, Nigel -- is
> this what you want?

I agree that encoding the symbol seems better.

>>> +   /* 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;
>>> + 
>> 
>> Why reset it?  The comment is misleading at best, because we actually
>> restore the setting at the end of this function (i.e. at the end of
>> mips_override_options).
>
> I think the issue here is that some of the base settings of other
> flags may depend on whether TARGET_MIPS16 is true at the time they are
> initialized.  Maybe there really should not be any such dependencies,
> but clearing the MASK_MIPS16 bit ensures that the base settings really
> are the base settings.  I'll update the comment to say so explicitly.

Instead, I think it would be better to audit the code to find out which
bits are mode-dependent, and move them to mips_set_mips16_mode.

>
>>> *************** 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
>> 
>> Why is this needed?
>
> Without this change, I get lots of link errors like:
>
> (.text+0x30): relocation truncated to fit: R_MIPS_GPREL16 against `.text'
>
> when running the testsuite in -mflip-mips16 mode.  IIRC, this was
> related to getting the constant pool to come out in the right section
> during end-of-file processing.

So this case occurs when you compile with -mips16, and have non-mips16
functions that refer to the constant pool?  OK, makes sense.

This code is actually redundant.  It should never make any difference
for constants in function pools, since references to the constant are
replaced by md_reorg.  One of the patches I'm working on removes the
TARGET_MIPS16 block entirely, and I think that's the correct thing
here too.  So, whoever's patch gets in first should be the one to
remove it.

I agree with you that removing the built-in function stuff would
be good, if it's possible.

Richard

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: revised PATCH: per-function back end reinitialization, part 2/2
  2007-08-06  7:16   ` Sandra Loosemore
  2007-08-06  7:46     ` Richard Sandiford
@ 2007-08-06 18:22     ` David Ung
  1 sibling, 0 replies; 5+ messages in thread
From: David Ung @ 2007-08-06 18:22 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: GCC Patches, Nigel Stephens, Ian Lance Taylor, richard

Sandra Loosemore wrote:
> Richard Sandiford wrote:
>> Sandra Loosemore <sandra@codesourcery.com> writes:
>>> ! /* 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;
>>
>> Why are only some of these GTY(())?
> 
> For that matter, why are any of these marked GTY(())?  I assumed it had 
> something to do with precompiled header support, which is a bit of the 
> compiler I know nothing about (yet).  David, Nigel?

aiye, it fixes the GCC PCH regressions.

> 
>>> +   /* 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));
>>
>> I'm not sure I follow.  What sort of built-in functions are we talking
>> about here?  What is the TREE_TYPE test doing?  Do we ever see
>> error_mark_node here?  (My understanding is that we don't any more.)
> 
> Hrmmm.  This didn't look implausible to me, but I tried commenting it 
> out and didn't see any testsuite regressions with -mflip-mips16.  (In 
> fact, that even fixed a few.)  David, was there a specific test case 
> that was failing without this?  Otherwise I think we can chuck this part 
> of the patch, as well as the changes to build_mips16_function_stub to 
> support it.

any function that does floating point, eg sin, cos (and we need to link to these 
mips16 functions) as the compiler don't automatically generate stubs in 
non-mips16 mode.
I am not remembering much about this at the moment.  I am ok chucking out bits 
that seem redundant until we find a test case for it.

David

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-08-06 18:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-30 19:37 revised PATCH: per-function back end reinitialization, part 2/2 Sandra Loosemore
2007-08-04  9:53 ` Richard Sandiford
2007-08-06  7:16   ` Sandra Loosemore
2007-08-06  7:46     ` Richard Sandiford
2007-08-06 18:22     ` David Ung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).