From 78fe751b3a78922e64f0d58744b18d675a5a7141 Mon Sep 17 00:00:00 2001 From: nickc Date: Tue, 29 Feb 2000 01:42:52 +0000 Subject: [PATCH] Apply Dimitri Makarov's patch to import attribute short_call and #pragma long_calls, no_long_calls. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32248 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 69 ++++++++++++ gcc/config/arm/arm-protos.h | 4 + gcc/config/arm/arm.c | 262 ++++++++++++++++++++++++++++++++------------ gcc/config/arm/arm.h | 74 ++++++++++++- gcc/config/arm/arm.md | 30 +++-- gcc/config/arm/elf.h | 1 + gcc/config/arm/pe.c | 11 +- gcc/config/arm/pe.h | 24 ++-- gcc/extend.texi | 11 ++ gcc/invoke.texi | 27 +++++ 10 files changed, 405 insertions(+), 108 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4d4d45420db..b5dd91be01b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,72 @@ +2000-02-28 Dmitri Makarov + + * extend.texi: Document ARM's support for long/short calls. + + * invoke.texi: Document ARM's -mlong-calls command line switch. + + * config/arm/arm-protos.h (arm_is_longcall_p): Add prototype. + (arm_encode_call_attribute): Add prototype. + (arm_set_default_type_attribute): Add prototype. + (arm_strip_name_encoding): Add prototype. + + * config/arm/arm.c (arm_init_cumulative_args): replace + initialisation og 'long_calls' field with initialisation of + 'call_cookie' field. + (enum arm_pragma_enum): New enum. + (arm_pragma_long_calls): New static variable. + (arm_process_pragma): Also process "#pragma long_calls_off". + (arm_valid_type_attribute_p): Accept short_call attribute. + (arm_comp_type_attributes): Check long/short call attributes. + (arm_encode_call_attribute): New function: Encode long_call + or short_call attribute in function name. + (arm_set_default_type_attributes): New function: Assign + default attributes to newly defined type. + (current_file_function_operand): New function: Return true if + the symbol is a function which has already been compiled. + (arm_is_longcall_p): New function: Return true if the + indicated function should be called via a long call. + (arm_get_strip_length): New function. Returns number of + prefix characters to be stripped from a function's name. + (arm_strip_name_encoding): New function. Strip prefix characters + from a function's name. + + * config/arm/arm.h (CUMULATIVE_ARGS): Replace 'long_call' field + with 'call_cookie'. + (SHORT_CALL_FAG_CHAR): Define. + (LONG_CALL_FAG_CHAR): Define. + (ENCODED_SHORT_CALL_ATTR_P): Define. + (ENCODED_LONG_CALL_ATTR_P): Define. + (ARM_NAME_ENCODING_LENGTHS): Define. + (STRIP_NAME_ENCODING): Define. + (ASM_OUTPUT_LABELREF): Define, and use to strip name encoding. + (ARM_ENCODE_CALL_TYPE): Define. + (ENCODE_SECTION): Invoke ARM_ENCODE_CALL_TYPE. + (ARM_DECLARE_FUNCTION_SIZE): Define. + (SET_DEFAULT_TYPE_ATTRIBUTES): Define. + + * config/arm/arm.md (call): Call arm_is_longcall_p to decide + if a long call is needed. + (call_value): Ditto. + (call_symbol): Ditto. + + * config/arm/elf.h (ASM_DECLARE_FUNCTION_SIZE): Add invocation of + ARM_DECLARE_FUNCTION_SIZE. + + * config/arm/pe.h (ARM_PE_FLAG_CHAR): Define. + (SUBTARGET_NAME_ENCODING_LENGTHS): Define. + (ARM_STRIP_NAME_ENCODING): Undefine. + (STRIP_NAME_ENCODING): Undefine. + (ASM_OUTPUT_LABELREF): Use arm_strip_name_encoding. + (ASM_DECLARE_FUNCTION_NAME): Ditto. + (ASM_OUTPUT_COMMON): Ditto. + (ASM_DECLARE_OBJECT_NAME): Ditto. + + * config/arm/pe.c (arm_dllexport_name_p): Check for + ARM_PE_FLAG_CHAR. + (arm_dllimport_name_p): Ditto. + (arm_mark_dllexport): Use ARM_PE_FLAG_CHAR. + (arm_mark_dllimport): Ditto. + Mon Feb 28 22:11:12 2000 J"orn Rennecke * sh.h (DWARF_LINE_MIN_INSTR_LENGTH): Define. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 74fb280c8f7..d19aa71d8b6 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -34,6 +34,7 @@ extern void output_ascii_pseudo_op PARAMS ((FILE *, unsigned char *, int)); extern void output_func_epilogue PARAMS ((int)); extern void output_func_prologue PARAMS ((FILE *, int)); extern int use_return_insn PARAMS ((int)); +extern const char * arm_strip_name_encoding PARAMS ((const char *)); #if defined AOF_ASSEMBLER extern void aof_add_import PARAMS ((char *)); extern char * aof_data_section PARAMS ((void)); @@ -62,6 +63,9 @@ extern void arm_pe_encode_section_info PARAMS ((tree)); extern tree arm_pe_merge_machine_decl_attributes PARAMS ((tree, tree)); extern void arm_pe_unique_section PARAMS ((tree, int)); extern int arm_pe_valid_machine_decl_attribute PARAMS ((tree, tree, tree, tree)); +extern void arm_set_default_type_attributes PARAMS ((tree)); +extern void arm_encode_call_attribute PARAMS ((tree, char)); +extern int arm_pe_return_in_memory PARAMS ((tree)); #endif #ifdef RTX_CODE diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 4b288ca7cbf..ffa26bb0cc8 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -40,19 +40,13 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "recog.h" #include "ggc.h" -#include "arm-protos.h" - -/* The maximum number of insns skipped which will be conditionalised if - possible. */ -static int max_insns_skipped = 5; - -extern FILE * asm_out_file; -/* Some function declarations. */ +#include "tm_p.h" #ifndef Mmode #define Mmode enum machine_mode #endif +/* Some function declarations. */ static HOST_WIDE_INT int_log2 PARAMS ((HOST_WIDE_INT)); static char * output_multi_immediate PARAMS ((rtx *, char *, char *, int, HOST_WIDE_INT)); static int arm_gen_constant PARAMS ((enum rtx_code, Mmode, HOST_WIDE_INT, rtx, rtx, int, int)); @@ -76,6 +70,12 @@ static enum arm_cond_code get_arm_condition_code PARAMS ((rtx)); static int const_ok_for_op PARAMS ((HOST_WIDE_INT, enum rtx_code)); static void arm_add_gc_roots PARAMS ((void)); +/* The maximum number of insns skipped which will be conditionalised if + possible. */ +static int max_insns_skipped = 5; + +extern FILE * asm_out_file; + /* True if we are currently building a constant table. */ int making_const_table; @@ -1487,9 +1487,8 @@ arm_init_cumulative_args (pcum, fntype, libname, indirect) int indirect ATTRIBUTE_UNUSED; { /* On the ARM, the offset starts at 0. */ - pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) - ? 1 : 0); - + pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0); + pcum->call_cookie = CALL_NORMAL; if (TARGET_LONG_CALLS) @@ -1534,73 +1533,37 @@ arm_function_arg (pcum, mode, type, named) return gen_rtx_REG (mode, pcum->nregs); } - -/* Return 1 if the operand is a SYMBOL_REF for a function - known to be defined in the current compilation unit. */ -static int -current_file_function_operand (sym_ref) - rtx sym_ref; +/* Encode the current state of the #pragma [no_]long_calls. */ +typedef enum { - /* XXX FIXME - we need some way to determine if SYMREF has already been - compiled. We wanted to used SYMBOL_REF_FLAG but this is already in use - by the constant pool generation code. */ - return - GET_CODE (sym_ref) == SYMBOL_REF - && sym_ref == XEXP (DECL_RTL (current_function_decl), 0) - && ! DECL_WEAK (current_function_decl); -} - -/* Return non-zero if a 32 bit "long call" should be generated for this - call. + OFF, /* No #pramgma [no_]long_calls is in effect. */ + LONG, /* #pragma long_calls is in effect. */ + SHORT /* #pragma no_long_calls is in effect. */ +} arm_pragma_enum; - We generate a long call if the function is not declared - __attribute__ ((short_call), +static arm_pragma_enum arm_pragma_long_calls = OFF; - AND: - - (1) the function is declared __attribute__ ((long_call)) - - OR - - (2) -mlong-calls is enabled and we don't know whether the target - function is declared in this file. - - This function will typically be called by C fragments in the machine - description file. CALL_REF is the matched rtl operand. CALL_COOKIE - describes the value of the long_call and short_call attributes for - the called functiion. CALL_SYMBOL is used to distinguish between - two different callers of the function. It is set to 1 in the "call_symbol" - and "call_symbol_value" patterns in arm.md and to 0 in the "call" and - "call_value" patterns. This is because of the difference of SYM_REFs passed - from "call_symbol" and "call" patterns. */ +/* Handle pragmas for compatibility with Intel's compilers. + FIXME: This is incomplete, since it does not handle all + the pragmas that the Intel compilers understand. */ int -arm_is_longcall_p (sym_ref, call_cookie, call_symbol) - rtx sym_ref; - int call_cookie; - int call_symbol; -{ - if (! call_symbol) - { - if (GET_CODE (sym_ref) != MEM) - return 0; - - sym_ref = XEXP (sym_ref, 0); - } - - if (GET_CODE (sym_ref) != SYMBOL_REF) - return 0; - - if (call_cookie & CALL_SHORT) - return 0; - - if (TARGET_LONG_CALLS && flag_function_sections) - return 1; - - if (current_file_function_operand (sym_ref, VOIDmode)) +arm_process_pragma (p_getc, p_ungetc, pname) + int (* p_getc) PARAMS ((void)) ATTRIBUTE_UNUSED; + void (* p_ungetc) PARAMS ((int)) ATTRIBUTE_UNUSED; + char * pname; +{ + /* Should be pragma 'far' or equivalent for callx/balx here. */ + if (strcmp (pname, "long_calls") == 0) + arm_pragma_long_calls = LONG; + else if (strcmp (pname, "no_long_calls") == 0) + arm_pragma_long_calls = SHORT; + else if (strcmp (pname, "long_calls_off") == 0) + arm_pragma_long_calls = OFF; + else return 0; - return (call_cookie & CALL_LONG) || TARGET_LONG_CALLS; + return 1; } /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific @@ -1624,7 +1587,7 @@ arm_valid_type_attribute_p (type, attributes, identifier, args) call. */ if (is_attribute_p ("long_call", identifier)) return (args == NULL_TREE); - + /* Whereas these functions are always known to reside within the 26 bit addressing range. */ if (is_attribute_p ("short_call", identifier)) @@ -1668,6 +1631,136 @@ arm_comp_type_attributes (type1, type2) return 1; } +/* Encode long_call or short_call attribute by prefixing + symbol name in DECL with a special character FLAG. */ +void +arm_encode_call_attribute (decl, flag) + tree decl; + char flag; +{ + char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + int len = strlen (str); + char * newstr; + + if (TREE_CODE (decl) != FUNCTION_DECL) + return; + + /* Do not allow weak functions to be treated as short call. */ + if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) + return; + + if (ggc_p) + newstr = ggc_alloc_string (NULL, len + 2); + else + newstr = permalloc (len + 2); + + sprintf (newstr, "%c%s", flag, str); + + XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; +} + +/* Assigns default attributes to newly defined type. This is used to + set short_call/long_call attributes for function types of + functions defined inside corresponding #pragma scopes. */ +void +arm_set_default_type_attributes (type) + tree type; +{ + /* Add __attribute__ ((long_call)) to all functions, when + inside #pragma long_calls or __attribute__ ((short_call)), + when inside #pragma no_long_calls. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + tree type_attr_list, attr_name; + type_attr_list = TYPE_ATTRIBUTES (type); + + if (arm_pragma_long_calls == LONG) + attr_name = get_identifier ("long_call"); + else if (arm_pragma_long_calls == SHORT) + attr_name = get_identifier ("short_call"); + else + return; + + type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list); + TYPE_ATTRIBUTES (type) = type_attr_list; + } +} + +/* Return 1 if the operand is a SYMBOL_REF for a function known to be + defined within the current compilation unit. If this caanot be + determined, then 0 is returned. */ +static int +current_file_function_operand (sym_ref) + rtx sym_ref; +{ + /* This is a bit of a fib. A function will have a short call flag + applied to its name if it has the short call attribute, or it has + already been defined within the current compilation unit. */ + if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) + return 1; + + /* The current funciton is always defined within the current compilation + unit. if it s a weak defintion however, then this may not be the real + defintion of the function, and so we have to say no. */ + if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) + && ! DECL_WEAK (current_function_decl)) + return 1; + + /* We cannot make the determination - default to returning 0. */ + return 0; +} + +/* Return non-zero if a 32 bit "long_call" should be generated for + this call. We generate a long_call if the function: + + a. has an __attribute__((long call)) + or b. is within the scope of a #pragma long_calls + or c. the -mlong-calls command line switch has been specified + + However we do not generate a long call if the function: + + d. has an __attribute__ ((short_call)) + or e. is inside the scope of a #pragma no_long_calls + or f. has an __attribute__ ((section)) + or g. is defined within the current compilation unit. + + This function will be called by C fragments contained in the machine + description file. CALL_REF and CALL_COOKIE correspond to the matched + rtl operands. CALL_SYMBOL is used to distinguish between + two different callers of the function. It is set to 1 in the + "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" + and "call_value" patterns. This is because of the difference in the + SYM_REFs passed by these patterns. */ +int +arm_is_longcall_p (sym_ref, call_cookie, call_symbol) + rtx sym_ref; + int call_cookie; + int call_symbol; +{ + if (! call_symbol) + { + if (GET_CODE (sym_ref) != MEM) + return 0; + + sym_ref = XEXP (sym_ref, 0); + } + + if (GET_CODE (sym_ref) != SYMBOL_REF) + return 0; + + if (call_cookie & CALL_SHORT) + return 0; + + if (TARGET_LONG_CALLS && flag_function_sections) + return 1; + + if (current_file_function_operand (sym_ref, VOIDmode)) + return 0; + + return (call_cookie & CALL_LONG) + || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) + || TARGET_LONG_CALLS; +} int legitimate_pic_operand_p (x) @@ -6988,6 +7081,31 @@ arm_final_prescan_insn (insn) } } +/* Return the length of a function name prefix + that starts with the character 'c'. */ +static int +arm_get_strip_length (char c) +{ + switch (c) + { + ARM_NAME_ENCODING_LENGTHS + default: return 0; + } +} + +/* Return a pointer to a function's name with any + and all prefix encodings stripped from it. */ +const char * +arm_strip_name_encoding (const char * name) +{ + int skip; + + while ((skip = arm_get_strip_length (* name))) + name += skip; + + return name; +} + #ifdef AOF_ASSEMBLER /* Special functions only needed when producing AOF syntax assembler. */ diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 0a08a5a5e8a..c20d82bb615 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -397,7 +397,7 @@ Unrecognized value in TARGET_CPU_DEFAULT. "Do not load the PIC register in function prologues" }, \ {"no-single-pic-base", -ARM_FLAG_SINGLE_PIC_BASE, "" }, \ {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate all call instructions as indirect calls"}, \ + "Generate call insns as indirect calls, if necessary"}, \ {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ SUBTARGET_SWITCHES \ {"", TARGET_DEFAULT, "" } \ @@ -1037,7 +1037,7 @@ enum reg_class else \ break; \ \ - high = ((((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000); \ + high = ((((val - low) & 0xffffffffUL) ^ 0x80000000UL) - 0x80000000UL);\ /* Check for overflow or zero */ \ if (low == 0 || high == 0 || (high + low != val)) \ break; \ @@ -1452,6 +1452,55 @@ CUMULATIVE_ARGS; When generating pic allow anything. */ #define LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X)) + +/* Special characters prefixed to function names + in order to encode attribute like information. + Note, '@' and '*' have already been taken. */ +#define SHORT_CALL_FLAG_CHAR '^' +#define LONG_CALL_FLAG_CHAR '#' + +#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) + +#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ + (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) + +#ifndef SUBTARGET_NAME_ENCODING_LENGTHS +#define SUBTARGET_NAME_ENCODING_LENGTHS +#endif + +/* This is a C fragement for the inside of a switch statement. + Each case label should return the number of characters to + be stripped from the start of a function's name, if that + name starts with the indicated character. */ +#define ARM_NAME_ENCODING_LENGTHS \ + case SHORT_CALL_FLAG_CHAR: return 1; \ + case LONG_CALL_FLAG_CHAR: return 1; \ + case '*': return 1; \ + SUBTARGET_NAME_ENCODING_LENGTHS + +/* This has to be handled by a function because more than part of the + ARM backend uses funciton name prefixes to encode attributes. */ +#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ + (VAR) = arm_strip_name_encoding (SYMBOL_NAME) + +/* This is how to output a reference to a user-level label named NAME. + `assemble_name' uses this. */ +#define ASM_OUTPUT_LABELREF(FILE, NAME) \ + fprintf (FILE, "%s%s", USER_LABEL_PREFIX, arm_strip_name_encoding (NAME)) + +/* If we are referencing a function that is weak then encode a long call + flag in the function name, otherwise if the function is static or + or known to be defined in this file then encode a short call flag. + This macro is used inside the ENCODE_SECTION macro. */ +#define ARM_ENCODE_CALL_TYPE(decl) \ + if (TREE_CODE (decl) == FUNCTION_DECL) \ + { \ + if (DECL_WEAK (decl)) \ + arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ + else if (! TREE_PUBLIC (decl)) \ + arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ + } \ /* Symbols in the text segment can be accessed without indirecting via the constant pool; it may take an extra binary operation, but this is still @@ -1470,9 +1519,18 @@ CUMULATIVE_ARGS; ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ } \ + ARM_ENCODE_CALL_TYPE (decl) \ +} +#else +#define ENCODE_SECTION_INFO(decl) \ +{ \ + ARM_ENCODE_CALL_TYPE (decl) \ } #endif +#define ARM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \ + arm_encode_call_attribute (DECL, SHORT_CALL_FLAG_CHAR) + /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. We have two alternate definitions for each of them. @@ -1892,8 +1950,8 @@ extern const char * arm_pic_register_string; ( ! symbol_mentioned_p (X) \ && ! label_mentioned_p (X) \ && (! CONSTANT_POOL_ADDRESS_P (X) \ - || ( ! symbol_mentioned_p (get_pool_constant (X))) \ - && ! label_mentioned_p (get_pool_constant (X)))) + || ( ! symbol_mentioned_p (get_pool_constant (X)) \ + && ! label_mentioned_p (get_pool_constant (X))))) /* We need to know when we are making a constant pool; this determines whether data needs to be in the GOT or can be referenced via a GOT @@ -1912,6 +1970,14 @@ extern int making_const_table; generated). */ #define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \ (arm_comp_type_attributes (TYPE1, TYPE2)) + +/* If defined, a C statement that assigns default attributes to newly + defined TYPE. */ +#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \ + arm_set_default_type_attributes (TYPE) + +/* Handle pragmas for compatibility with Intel's compilers. */ +#define HANDLE_PRAGMA(GET, UNGET, NAME) arm_process_pragma (GET, UNGET, NAME) /* Condition code information. */ /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index b1e1f34d302..ed1a3da80b7 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -4514,18 +4514,24 @@ "" " { - rtx callee = XEXP (operands[0], 0); + rtx callee; - /* Decide if we need to generate an indirect call by loading the 32 bit - address of the callee into a register and then jumping to the contents - of that register. operands[2] contains the long_call / short_call - attribute. The third parameter to arm_is_longcall_p tells it that it - is being passed a (MEM) and not a SYMREF(). */ - /* In an untyped call, we can get NULL for operand 2. */ if (operands[2] == NULL_RTX) operands[2] = const0_rtx; + /* This is to decide if we should generate indirect calls by loading the + 32 bit address of the callee into a register before performing the + branch and link. operand[2] encodes the long_call/short_call + attribute of the function being called. This attribute is set whenever + __attribute__((long_call/short_call)) or #pragma long_call/no_long_call + is used, and the short_call attribute can also be set if function is + declared as static or if it has already been defined in the current + compilation unit. See arm.c and arm.h for info about this. The third + parameter to arm_is_longcall_p is used to tell it which pattern + invoked it. */ + callee = XEXP (operands[0], 0); + if (GET_CODE (callee) != REG && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) XEXP (operands[0], 0) = force_reg (Pmode, callee); @@ -4575,7 +4581,7 @@ /* See the comment in define_expand \"call\". */ if (GET_CODE (callee) != REG && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) - XEXP (operands[1], 0) = force_reg (Pmode, callee); + XEXP (operands[1], 0) = force_reg (Pmode, callee); }" ) @@ -4613,8 +4619,8 @@ (match_operand:SI 1 "general_operand" "g")) (use (match_operand 2 "" "")) (clobber (reg:SI 14))] - "! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1) - && GET_CODE (operands[0]) == SYMBOL_REF" + "(GET_CODE (operands[0]) == SYMBOL_REF) + && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\"; @@ -4627,8 +4633,8 @@ (match_operand:SI 2 "general_operand" "g"))) (use (match_operand 3 "" "")) (clobber (reg:SI 14))] - "! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1) - && GET_CODE (operands[1]) == SYMBOL_REF" + "(GET_CODE (operands[1]) == SYMBOL_REF) + && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" "* { return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\"; diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h index 9b620206da6..b95c7fbecc0 100644 --- a/gcc/config/arm/elf.h +++ b/gcc/config/arm/elf.h @@ -127,6 +127,7 @@ Boston, MA 02111-1307, USA. */ #define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ do \ { \ + ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL); \ if (!flag_inhibit_size_directive) \ { \ char label[256]; \ diff --git a/gcc/config/arm/pe.c b/gcc/config/arm/pe.c index 1f57e8bd3f8..90158ff6f27 100644 --- a/gcc/config/arm/pe.c +++ b/gcc/config/arm/pe.c @@ -19,9 +19,8 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include #include "config.h" +#include "system.h" #include "rtl.h" #include "output.h" #include "flags.h" @@ -240,7 +239,7 @@ int arm_dllexport_name_p (symbol) char * symbol; { - return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; + return symbol[0] == ARM_PE_FLAG_CHAR && symbol[1] == 'e' && symbol[2] == '.'; } /* Return non-zero if SYMBOL is marked as being dllimport'd. */ @@ -249,7 +248,7 @@ int arm_dllimport_name_p (symbol) char * symbol; { - return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; + return symbol[0] == ARM_PE_FLAG_CHAR && symbol[1] == 'i' && symbol[2] == '.'; } /* Mark a DECL as being dllexport'd. @@ -278,7 +277,7 @@ arm_mark_dllexport (decl) return; /* already done */ newname = alloca (strlen (oldname) + 4); - sprintf (newname, "@e.%s", oldname); + sprintf (newname, "%ce.%s", ARM_PE_FLAG_CHAR, oldname); /* We pass newname through get_identifier to ensure it has a unique address. RTL processing can sometimes peek inside the symbol ref @@ -349,7 +348,7 @@ arm_mark_dllimport (decl) } newname = alloca (strlen (oldname) + 11); - sprintf (newname, "@i.__imp_%s", oldname); + sprintf (newname, "%ci.__imp_%s", ARM_PE_FLAG_CHAR, oldname); /* We pass newname through get_identifier to ensure it has a unique address. RTL processing can sometimes peek inside the symbol ref diff --git a/gcc/config/arm/pe.h b/gcc/config/arm/pe.h index 41a3ceb24a1..dfa5d4d08b4 100644 --- a/gcc/config/arm/pe.h +++ b/gcc/config/arm/pe.h @@ -19,6 +19,12 @@ along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#define ARM_PE_FLAG_CHAR '@' + +/* Ensure that @x. will be stripped from the function name. */ +#define SUBTARGET_NAME_ENCODING_LENGTHS \ + case ARM_PE_FLAG_CHAR: return 3; + #include "arm/coff.h" #undef USER_LABEL_PREFIX @@ -123,16 +129,6 @@ Boston, MA 02111-1307, USA. */ #define REDO_SECTION_INFO_P(DECL) 1 #endif -/* Utility used only in this file. */ -#define ARM_STRIP_NAME_ENCODING(SYM_NAME) \ -((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0)) - -/* Strip any text from SYM_NAME added by ENCODE_SECTION_INFO and store - the result in VAR. */ -#undef STRIP_NAME_ENCODING -#define STRIP_NAME_ENCODING(VAR, SYM_NAME) \ -(VAR) = ARM_STRIP_NAME_ENCODING (SYM_NAME) - /* Define this macro if in some cases global symbols from one translation unit may not be bound to undefined symbols in another translation unit without user intervention. For instance, under Microsoft Windows @@ -184,7 +180,7 @@ Boston, MA 02111-1307, USA. */ /* Output a reference to a label. */ #undef ASM_OUTPUT_LABELREF #define ASM_OUTPUT_LABELREF(STREAM, NAME) \ - fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, ARM_STRIP_NAME_ENCODING (NAME)) + fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, arm_strip_name_encoding (NAME)) /* Output a function definition label. */ #undef ASM_DECLARE_FUNCTION_NAME @@ -195,7 +191,7 @@ Boston, MA 02111-1307, USA. */ { \ drectve_section (); \ fprintf (STREAM, "\t.ascii \" -export:%s\"\n",\ - ARM_STRIP_NAME_ENCODING (NAME)); \ + arm_strip_name_encoding (NAME)); \ function_section (DECL); \ } \ if (TARGET_POKE_FUNCTION_NAME) \ @@ -213,7 +209,7 @@ Boston, MA 02111-1307, USA. */ { \ drectve_section (); \ fprintf ((STREAM), "\t.ascii \" -export:%s\"\n",\ - ARM_STRIP_NAME_ENCODING (NAME)); \ + arm_strip_name_encoding (NAME)); \ } \ if (! arm_dllimport_name_p (NAME)) \ { \ @@ -235,7 +231,7 @@ Boston, MA 02111-1307, USA. */ enum in_section save_section = in_section; \ drectve_section (); \ fprintf (STREAM, "\t.ascii \" -export:%s\"\n",\ - ARM_STRIP_NAME_ENCODING (NAME)); \ + arm_strip_name_encoding (NAME)); \ switch_to_section (save_section, (DECL)); \ } \ ASM_OUTPUT_LABEL ((STREAM), (NAME)); \ diff --git a/gcc/extend.texi b/gcc/extend.texi index 87cf2914289..fa13154d7fe 100644 --- a/gcc/extend.texi +++ b/gcc/extend.texi @@ -1613,6 +1613,17 @@ compiler to always call the function via a pointer, so that functions which reside further than 64 megabytes (67,108,864 bytes) from the current location can be called. +@item long_call/short_call +@cindex indirect calls on ARM +This attribute allows to specify how to call a particular function on +ARM. Both attributes override the @code{-mlong-calls} (@pxref{ARM Options}) +command line switch and @code{#pragma long_calls} settings. The +@code{long_call} 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. The @code{short_call} attribute always places +the offset to the function from the call site into the @samp{BL} +instruction directly. + @item dllimport @cindex functions which are imported from a dll on PowerPC Windows NT On the PowerPC running Windows NT, the @code{dllimport} attribute causes diff --git a/gcc/invoke.texi b/gcc/invoke.texi index c2f45ad76c6..3be7f72f6e9 100644 --- a/gcc/invoke.texi +++ b/gcc/invoke.texi @@ -269,6 +269,7 @@ in the following sections. -mstructure-size-boundary= -mbsd -mxopen -mno-symrename -mabort-on-noreturn +-mlong-calls -mno-long-calls -mnop-fun-dllimport -mno-nop-fun-dllimport -msingle-pic-base -mno-single-pic-base -mpic-register= @@ -4608,6 +4609,32 @@ value as future versions of the toolchain may default to this value. Generate a call to the function abort at the end of a noreturn function. It will be executed if the function tries to return. +@item -mlong-calls +@itemx -mno-long-calls +Tells the compiler to perform function calls by first loading the +address of the function into a register and then performing a subroutine +call on this register. This switch is needed if the target function +will lie outside of the 64 megabyte addressing range of the offset based +version of subroutine call instruction. + +Even if this switch is enabled, not all function calls will be turned +into long calls. The heuristic is that static functions, functions +which have the @samp{short-call} attribute, functions that are inside +the scope of a @samp{#pragma no_long_calls} directive and functions whose +definitions have already been compiled within the current compilation +unit, will not be turned into long calls. The exception to this rule is +that weak function defintions, functions with the @samp{long-call} +attribute or the @samp{section} attribute, and functions that are within +the scope of a @samp{#pragma long_calls} directive, will always be +turned into long calls. + +This feature is not enabled by default. Specifying +@samp{--no-long-calls} will restore the default behaviour, as will +placing the function calls within the scope of a @samp{#pragma +long_calls_off} directive. Note these switches have no effect on how +the compiler generates code to handle function calls via function +pointers. + @item -mnop-fun-dllimport @kindex -mnop-fun-dllimport Disable the support for the @emph{dllimport} attribute. -- 2.11.4.GIT