This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: near/far function attributes for MIPS


This patch adds "far" as a synonym for the "long_call" attribute to locally override -mno-long-calls, and "near" to do the reverse. OK to commit?

-Sandra

2007-05-25  Sandra Loosemore  <sandra@codesourcery.com>
	    Nigel Stephens  <nigel@mips.com>

	gcc/
	* config/mips/mips.c (mips_attribute_table): Add "near" and "far"
	function attributes, "far" being an alias for "long_call".
	(TARGET_COMP_TYPE_ATTRIBUTES): Define as mips_comp_type_attributes.
	(mips_near_type_p, mips_far_type_p): New.
	(mips_comp_type_attributes): New function to check that attributes
	attached to a function type are compatible.
	(mips_output_mi_thunk): Test SYMBOL_REF_LONG_CALL_P() rather than
	TARGET_LONG_CALLS when deciding	whether we can do a direct sibcall
	to the target function of the thunk.
	(mips_encode_section_info): Check for "near" and "far" function
	attributes, and always set the SYMBOL_FLAG_LONG_CALL bit explicitly.

	* config/mips/predicates.md (const_call_insn_operand): Test only
	SYMBOL_REF_LONG_CALL_P() and not TARGET_LONG_CALLS.

	* doc/extend.texi (Function Attributes): Document MIPS "near" and
	"far" attributes.

	* testsuite/gcc.target/mips/near-far-1.c:  New test case.
	* testsuite/gcc.target/mips/near-far-2.c:  New test case.
	* testsuite/gcc.target/mips/near-far-3.c:  New test case.
	* testsuite/gcc.target/mips/near-far-4.c:  New test case.
Index: gcc/config/mips/mips.c
===================================================================
*** gcc/config/mips/mips.c	(revision 125063)
--- gcc/config/mips/mips.c	(working copy)
*************** static rtx mips_expand_builtin_compare (
*** 411,416 ****
--- 411,417 ----
  static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx);
  static void mips_encode_section_info (tree, rtx, int);
  static void mips_extra_live_on_entry (bitmap);
+ static int mips_comp_type_attributes (tree, tree);
  static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
  static bool mips_offset_within_alignment_p (rtx, HOST_WIDE_INT);
  
*************** const enum reg_class mips_regno_to_class
*** 685,690 ****
--- 686,693 ----
  const struct attribute_spec mips_attribute_table[] =
  {
    { "long_call",   0, 0, false, true,  true,  NULL },
+   { "far",     	   0, 0, false, true,  true,  NULL },
+   { "near",        0, 0, false, true,  true,  NULL },
    { NULL,	   0, 0, false, false, false, NULL }
  };
  
*************** static struct mips_rtx_cost_data const m
*** 1249,1255 ****
--- 1252,1299 ----
  #undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
  #define TARGET_USE_ANCHORS_FOR_SYMBOL_P mips_use_anchors_for_symbol_p
  
+ #undef  TARGET_COMP_TYPE_ATTRIBUTES
+ #define TARGET_COMP_TYPE_ATTRIBUTES mips_comp_type_attributes
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
+ 
+ 
+ /* Predicates to test for presence of "near" and "far"/"long_call"
+    attributes on the given TYPE.  */
+ 
+ static bool
+ mips_near_type_p (tree type)
+ {
+   return lookup_attribute ("near", TYPE_ATTRIBUTES (type)) != NULL;
+ }
+ 
+ static bool
+ mips_far_type_p (tree type)
+ {
+   return (lookup_attribute ("long_call", TYPE_ATTRIBUTES (type)) != NULL
+ 	  || lookup_attribute ("far", 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
+    warning to be generated).  */
+ 
+ static int
+ mips_comp_type_attributes (tree type1, tree type2)
+ {
+   /* Check for mismatch of non-default calling convention.  */
+   if (TREE_CODE (type1) != FUNCTION_TYPE)
+     return 1;
+ 
+   /* Disallow mixed near/far attributes.  */
+   if (mips_far_type_p (type1) && mips_near_type_p (type2))
+     return 0;
+   if (mips_near_type_p (type1) && mips_far_type_p (type2))
+     return 0;
+ 
+   return 1;
+ }
  
  /* Return true if SYMBOL_REF X is associated with a global symbol
     (in the STB_GLOBAL sense).  */
*************** mips_output_mi_thunk (FILE *file, tree t
*** 7332,7338 ****
    /* 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 || TARGET_LONG_CALLS)
      {
        /* This is messy.  gas treats "la $25,foo" as part of a call
  	 sequence and may allow a global "foo" to be lazily bound.
--- 7376,7382 ----
    /* 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.
*************** mips_encode_section_info (tree decl, rtx
*** 11139,11149 ****
  {
    default_encode_section_info (decl, rtl, first);
  
!   if (TREE_CODE (decl) == FUNCTION_DECL
!       && lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
      {
        rtx symbol = XEXP (rtl, 0);
!       SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
      }
  }
  
--- 11183,11195 ----
  {
    default_encode_section_info (decl, rtl, first);
  
!   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;
      }
  }
  
Index: gcc/config/mips/predicates.md
===================================================================
*** gcc/config/mips/predicates.md	(revision 125063)
--- gcc/config/mips/predicates.md	(working copy)
***************
*** 113,122 ****
  	       && !DECL_EXTERNAL (SYMBOL_REF_DECL (op))))
  	return false;
  
!       /* If -mlong-calls, force all calls to use register addressing.  Also,
! 	 if this function has the long_call attribute, we must use register
! 	 addressing.  */
!       return !TARGET_LONG_CALLS && !SYMBOL_REF_LONG_CALL_P (op);
  
      case SYMBOL_GOT_DISP:
        /* Without explicit relocs, there is no special syntax for
--- 113,122 ----
  	       && !DECL_EXTERNAL (SYMBOL_REF_DECL (op))))
  	return false;
  
!       /* If -mlong-calls or if this function has an explicit long_call
! 	 attribute, we must use register addressing.  The
! 	 SYMBOL_FLAG_LONG_CALL bit is set by mips_encode_section_info.  */
!       return !SYMBOL_REF_LONG_CALL_P (op);
  
      case SYMBOL_GOT_DISP:
        /* Without explicit relocs, there is no special syntax for
Index: gcc/doc/extend.texi
===================================================================
*** gcc/doc/extend.texi	(revision 125063)
--- gcc/doc/extend.texi	(working copy)
*************** PowerPC, the @code{#pragma longcall} set
*** 2085,2097 ****
  @xref{RS/6000 and PowerPC Options}, for more information on whether long
  calls are necessary.
  
! @item long_call
  @cindex indirect calls on MIPS
! This attribute specifies how a particular function is called on MIPS@.
! The attribute overrides the @option{-mlong-calls} (@pxref{MIPS Options})
! command line switch.  This attribute causes the compiler to always call
  the function by first loading its address into a register, and then using
! the contents of that register.
  
  @item malloc
  @cindex @code{malloc} attribute
--- 2085,2100 ----
  @xref{RS/6000 and PowerPC Options}, for more information on whether long
  calls are necessary.
  
! @item long_call/near/far
  @cindex indirect calls on MIPS
! These attributes specify how a particular function is called on MIPS@.
! The attributes override the @option{-mlong-calls} (@pxref{MIPS Options})
! command-line switch.  The @code{long_call} and @code{far} attributes are
! synonyms, and cause the compiler to always call
  the function by first loading its address into a register, and then using
! the contents of that register.  The @code{near} attribute has the opposite
! effect; it specifies that non-PIC calls should be made using the more 
! efficient @code{jal} instruction.
  
  @item malloc
  @cindex @code{malloc} attribute
Index: gcc/testsuite/gcc.target/mips/near-far-1.c
===================================================================
*** gcc/testsuite/gcc.target/mips/near-far-1.c	(revision 0)
--- gcc/testsuite/gcc.target/mips/near-far-1.c	(revision 0)
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do compile } */
+ /* { dg-mips-options "-mlong-calls" } */
+ /* { dg-require-effective-target nonpic } */
+ 
+ extern int long_call_func () __attribute__((long_call));
+ extern int far_func () __attribute__((far));
+ extern int near_func () __attribute__((near));
+ extern int normal_func ();
+ 
+ int test ()
+ {
+   return (long_call_func ()
+           + far_func ()
+           + near_func ()
+           + normal_func ());
+ }
+ 
+ /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
+ /* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tjal\tnormal_func\n" } } */
Index: gcc/testsuite/gcc.target/mips/near-far-2.c
===================================================================
*** gcc/testsuite/gcc.target/mips/near-far-2.c	(revision 0)
--- gcc/testsuite/gcc.target/mips/near-far-2.c	(revision 0)
***************
*** 0 ****
--- 1,21 ----
+ /* { dg-do compile } */
+ /* { dg-mips-options "-mno-long-calls" } */
+ /* { dg-require-effective-target nonpic } */
+ 
+ extern int long_call_func () __attribute__((long_call));
+ extern int far_func () __attribute__((far));
+ extern int near_func () __attribute__((near));
+ extern int normal_func ();
+ 
+ int test ()
+ {
+   return (long_call_func ()
+           + far_func ()
+           + near_func ()
+           + normal_func ());
+ }
+ 
+ /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
+ /* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
+ /* { dg-final { scan-assembler     "\tjal\tnormal_func\n" } } */
Index: gcc/testsuite/gcc.target/mips/near-far-3.c
===================================================================
*** gcc/testsuite/gcc.target/mips/near-far-3.c	(revision 0)
--- gcc/testsuite/gcc.target/mips/near-far-3.c	(revision 0)
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */
+ /* { dg-mips-options "-mlong-calls -O2 -mno-mips16" } */
+ /* { dg-require-effective-target nonpic } */
+ 
+ extern int long_call_func () __attribute__((long_call));
+ extern int far_func () __attribute__((far));
+ extern int near_func () __attribute__((near));
+ extern int normal_func ();
+ 
+ int test1 () { return long_call_func (); }
+ int test2 () { return far_func (); }
+ int test3 () { return near_func (); }
+ int test4 () { return normal_func (); }
+ 
+ /* { dg-final { scan-assembler-not "\tj\tlong_call_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tj\tfar_func\n" } } */
+ /* { dg-final { scan-assembler     "\tj\tnear_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tj\tnormal_func\n" } } */
Index: gcc/testsuite/gcc.target/mips/near-far-4.c
===================================================================
*** gcc/testsuite/gcc.target/mips/near-far-4.c	(revision 0)
--- gcc/testsuite/gcc.target/mips/near-far-4.c	(revision 0)
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */
+ /* { dg-mips-options "-mno-long-calls -O2 -mno-mips16" } */
+ /* { dg-require-effective-target nonpic } */
+ 
+ extern int long_call_func () __attribute__((long_call));
+ extern int far_func () __attribute__((far));
+ extern int near_func () __attribute__((near));
+ extern int normal_func ();
+ 
+ int test1 () { return long_call_func (); }
+ int test2 () { return far_func (); }
+ int test3 () { return near_func (); }
+ int test4 () { return normal_func (); }
+ 
+ /* { dg-final { scan-assembler-not "\tj\tlong_call_func\n" } } */
+ /* { dg-final { scan-assembler-not "\tj\tfar_func\n" } } */
+ /* { dg-final { scan-assembler     "\tj\tnear_func\n" } } */
+ /* { dg-final { scan-assembler     "\tj\tnormal_func\n" } } */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]