mips.c (mips_attribute_table): Add "near" and "far" function attributes, "far" being...
authorSandra Loosemore <sandra@codesourcery.com>
Sat, 26 May 2007 02:02:37 +0000 (22:02 -0400)
committerSandra Loosemore <sandra@gcc.gnu.org>
Sat, 26 May 2007 02:02:37 +0000 (22:02 -0400)
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.

Co-Authored-By: Nigel Stephens <nigel@mips.com>
From-SVN: r125086

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/predicates.md
gcc/doc/extend.texi
gcc/testsuite/gcc.target/mips/near-far-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/near-far-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/near-far-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/near-far-4.c [new file with mode: 0644]

index ad0d988ec631c55989d9a6a4a7abf50293febd1f..79bb878276aa3e21077a24849a2e52642cc9bb6a 100644 (file)
@@ -1,3 +1,29 @@
+2007-05-25  Sandra Loosemore  <sandra@codesourcery.com>
+           Nigel Stephens  <nigel@mips.com>
+
+       * 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.
+
 2007-05-25  Eric Christopher  <echristo@apple.com>
 
        * config.gcc: Add i386/t-fprules-softfp64 and soft-fp/t-softfp
index 07b5b78a6b598aed1cd3dbaa1604b6c851d967ce..ba36ecec2338c0d855867294571da14735cff713 100644 (file)
@@ -411,6 +411,7 @@ static rtx mips_expand_builtin_compare (enum mips_builtin_type,
 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);
 
@@ -685,6 +686,8 @@ const enum reg_class mips_regno_to_class[] =
 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 }
 };
 \f
@@ -1249,7 +1252,48 @@ static struct mips_rtx_cost_data const mips_rtx_cost_data[PROCESSOR_MAX] =
 #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;
+}
 \f
 /* Return true if SYMBOL_REF X is associated with a global symbol
    (in the STB_GLOBAL sense).  */
@@ -7332,7 +7376,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   /* Jump to the target function.  Use a sibcall if direct jumps are
      allowed, otherwise load the address into a register first.  */
   fnaddr = XEXP (DECL_RTL (function), 0);
-  if (TARGET_MIPS16 || TARGET_USE_GOT || TARGET_LONG_CALLS)
+  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.
@@ -11139,11 +11183,13 @@ mips_encode_section_info (tree decl, rtx rtl, int first)
 {
   default_encode_section_info (decl, rtl, first);
 
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       rtx symbol = XEXP (rtl, 0);
-      SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
+
+      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 16035c8cb2b1949404c3234f995a5d3917172c88..fbe3ab44bed2c51aad1c866d4c1ec25a1c48249d 100644 (file)
               && !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);
+      /* 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 5ebee3dcc51ce7a6d750d1e22024f4f29a47d661..e1104dcc4748b4308eec8a75cef68a95cdb9c29f 100644 (file)
@@ -2110,13 +2110,16 @@ PowerPC, the @code{#pragma longcall} setting.
 @xref{RS/6000 and PowerPC Options}, for more information on whether long
 calls are necessary.
 
-@item long_call
+@item long_call/near/far
 @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
+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 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
diff --git a/gcc/testsuite/gcc.target/mips/near-far-1.c b/gcc/testsuite/gcc.target/mips/near-far-1.c
new file mode 100644 (file)
index 0000000..f8bc5c9
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-2.c b/gcc/testsuite/gcc.target/mips/near-far-2.c
new file mode 100644 (file)
index 0000000..d65c44c
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-3.c b/gcc/testsuite/gcc.target/mips/near-far-3.c
new file mode 100644 (file)
index 0000000..d6902cd
--- /dev/null
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.target/mips/near-far-4.c b/gcc/testsuite/gcc.target/mips/near-far-4.c
new file mode 100644 (file)
index 0000000..7d156fa
--- /dev/null
@@ -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" } } */