From cd3a59b38ed5414f55606720817999b869e02762 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Fri, 25 May 2007 22:02:37 -0400 Subject: [PATCH] mips.c (mips_attribute_table): Add "near" and "far" function attributes, "far" being an alias for "long_call". 2007-05-25 Sandra Loosemore Nigel Stephens 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 From-SVN: r125086 --- gcc/ChangeLog | 26 +++++++++++ gcc/config/mips/mips.c | 54 ++++++++++++++++++++-- gcc/config/mips/predicates.md | 8 ++-- gcc/doc/extend.texi | 13 ++++-- gcc/testsuite/gcc.target/mips/near-far-1.c | 21 +++++++++ gcc/testsuite/gcc.target/mips/near-far-2.c | 21 +++++++++ gcc/testsuite/gcc.target/mips/near-far-3.c | 18 ++++++++ gcc/testsuite/gcc.target/mips/near-far-4.c | 18 ++++++++ 8 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/near-far-1.c create mode 100644 gcc/testsuite/gcc.target/mips/near-far-2.c create mode 100644 gcc/testsuite/gcc.target/mips/near-far-3.c create mode 100644 gcc/testsuite/gcc.target/mips/near-far-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ad0d988ec63..79bb878276a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2007-05-25 Sandra Loosemore + Nigel Stephens + + * 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 * config.gcc: Add i386/t-fprules-softfp64 and soft-fp/t-softfp diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 07b5b78a6b5..ba36ecec233 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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 } }; @@ -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; +} /* 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; } } diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md index 16035c8cb2b..fbe3ab44bed 100644 --- a/gcc/config/mips/predicates.md +++ b/gcc/config/mips/predicates.md @@ -113,10 +113,10 @@ && !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 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 5ebee3dcc51..e1104dcc474 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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 index 00000000000..f8bc5c93ef4 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/near-far-1.c @@ -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 index 00000000000..d65c44cf9f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/near-far-2.c @@ -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 index 00000000000..d6902cdfeb0 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/near-far-3.c @@ -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 index 00000000000..7d156fabdc5 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/near-far-4.c @@ -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" } } */