OSDN Git Service

Apply Dimitri Makarov's patch to import attribute short_call and #pragma
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 29 Feb 2000 01:42:52 +0000 (01:42 +0000)
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 29 Feb 2000 01:42:52 +0000 (01:42 +0000)
long_calls, no_long_calls.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32248 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/elf.h
gcc/config/arm/pe.c
gcc/config/arm/pe.h
gcc/extend.texi
gcc/invoke.texi

index 4d4d454..b5dd91b 100644 (file)
@@ -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.
index 74fb280..d19aa71 100644 (file)
@@ -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
index 4b288ca..ffa26bb 100644 (file)
@@ -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);
 }
-
 \f
-/* 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;
 }
 \f
 /* 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;
+    }
+}
+\f
+/* 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;
+}
 \f
 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. */
 
index 0a08a5a..c20d82b 100644 (file)
@@ -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))
+\f
+/* 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)
 \f
 /* Condition code information. */
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
index b1e1f34..ed1a3da 100644 (file)
   ""
   "
   {
-    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);
     /* 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);
   }"
 )
 
         (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\";
        (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\";
index 9b62020..b95c7fb 100644 (file)
@@ -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];                                     \
index 1f57e8b..90158ff 100644 (file)
@@ -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
index 41a3ceb..dfa5d4d 100644 (file)
@@ -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));             \
index 87cf291..fa13154 100644 (file)
@@ -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
index c2f45ad..3be7f72 100644 (file)
@@ -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.