Apply Dimitri Makarov's patch to import attribute short_call and #pragma
long_calls, no_long_calls. From-SVN: r32248
This commit is contained in:
parent
8aacf01600
commit
c27ba9120a
|
@ -1,3 +1,72 @@
|
|||
2000-02-28 Dmitri Makarov <dim@windriver.com>
|
||||
|
||||
* 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 <amylaar@cygnus.co.uk>
|
||||
|
||||
* sh.h (DWARF_LINE_MIN_INSTR_LENGTH): Define.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
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;
|
||||
|
||||
/* Return non-zero if a 32 bit "long call" should be generated for this
|
||||
call.
|
||||
static arm_pragma_enum arm_pragma_long_calls = OFF;
|
||||
|
||||
We generate a long call if the function is not declared
|
||||
__attribute__ ((short_call),
|
||||
|
||||
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;
|
||||
arm_process_pragma (p_getc, p_ungetc, pname)
|
||||
int (* p_getc) PARAMS ((void)) ATTRIBUTE_UNUSED;
|
||||
void (* p_ungetc) PARAMS ((int)) ATTRIBUTE_UNUSED;
|
||||
char * pname;
|
||||
{
|
||||
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))
|
||||
/* 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. */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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\";
|
||||
|
|
|
@ -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]; \
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#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
|
||||
|
|
|
@ -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)); \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue