arm-protos.h (arm_encode_call_attribute): Delete.
authorRichard Sandiford <richard@codesourcery.com>
Fri, 25 May 2007 11:36:06 +0000 (11:36 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Fri, 25 May 2007 11:36:06 +0000 (11:36 +0000)
gcc/
* config/arm/arm-protos.h (arm_encode_call_attribute): Delete.
(arm_is_longcall_p): Rename to...
(arm_is_long_call_p): ...this.  Take a single tree argument and
return a bool.
* config/arm/arm.h (CALL_SHORT, CALL_LONG, CALL_NORMAL): Delete.
(CUMULATIVE_ARGS): Remove call_cookie.
(SHORT_CALL_FLAG_CHAR, LONG_CALL_FLAG_CHAR, ENCODED_SHORT_CALL_ATTR_P)
(ENCODED_LONG_CALL_ATTR_P): Delete.
(ARM_NAME_ENCODING_LENGTHS): Remove SHORT_CALL_FLAG_CHAR and
LONG_CALL_FLAG_CHAR cases.
(ARM_DECLARE_FUNCTION_SIZE): Delete.
* config/arm/elf.h (ASM_DECLARE_FUNCTION_SIZE): Don't use
ARM_DECLARE_FUNCTION_SIZE.
* config/arm/arm.c (arm_init_cumulative_args): Don't set call_cookie.
(arm_function_arg): Return const0_rtx for VOIDmode arguments.
(arm_encode_call_attribute, current_file_function_operand): Delete.
(arm_function_in_section_p): New function.
(arm_is_longcall_p): Rename to...
(arm_is_long_call_p): ...this.  Take the target function as a single
argument and return a bool.  Do not rely on call cookies.  Check
whether the target symbol is in the same section as the current
function, not just the same compilation unit.
(arm_function_ok_for_sibcall): Use arm_is_long_call_p.
(arm_encode_section_info): Don't encode a call type.
* config/arm/arm.md (call, call_value): Update calls to
arm_is_long(_)call_p.  Simplify logic.
(*call_symbol, *call_value_symbol, *call_insn, *call_value_insn):
Update calls to arm_is_long(_)call_p.

gcc/testsuite/
* gcc.target/arm/long-calls-1.c: New test.
* gcc.target/arm/long-calls-2.c: Likewise.
* gcc.target/arm/long-calls-3.c: Likewise.
* gcc.target/arm/long-calls-4.c: Likewise.

From-SVN: r125060

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/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/long-calls-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/long-calls-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/long-calls-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/long-calls-4.c [new file with mode: 0644]

index 2342dad..bebad9a 100644 (file)
@@ -1,3 +1,34 @@
+2007-05-25  Richard Sandiford  <richard@codesourcery.com>
+
+       * config/arm/arm-protos.h (arm_encode_call_attribute): Delete.
+       (arm_is_longcall_p): Rename to...
+       (arm_is_long_call_p): ...this.  Take a single tree argument and
+       return a bool.
+       * config/arm/arm.h (CALL_SHORT, CALL_LONG, CALL_NORMAL): Delete.
+       (CUMULATIVE_ARGS): Remove call_cookie.
+       (SHORT_CALL_FLAG_CHAR, LONG_CALL_FLAG_CHAR, ENCODED_SHORT_CALL_ATTR_P)
+       (ENCODED_LONG_CALL_ATTR_P): Delete.
+       (ARM_NAME_ENCODING_LENGTHS): Remove SHORT_CALL_FLAG_CHAR and
+       LONG_CALL_FLAG_CHAR cases.
+       (ARM_DECLARE_FUNCTION_SIZE): Delete.
+       * config/arm/elf.h (ASM_DECLARE_FUNCTION_SIZE): Don't use
+       ARM_DECLARE_FUNCTION_SIZE.
+       * config/arm/arm.c (arm_init_cumulative_args): Don't set call_cookie.
+       (arm_function_arg): Return const0_rtx for VOIDmode arguments.
+       (arm_encode_call_attribute, current_file_function_operand): Delete.
+       (arm_function_in_section_p): New function.
+       (arm_is_longcall_p): Rename to...
+       (arm_is_long_call_p): ...this.  Take the target function as a single
+       argument and return a bool.  Do not rely on call cookies.  Check
+       whether the target symbol is in the same section as the current
+       function, not just the same compilation unit.
+       (arm_function_ok_for_sibcall): Use arm_is_long_call_p.
+       (arm_encode_section_info): Don't encode a call type.
+       * config/arm/arm.md (call, call_value): Update calls to
+       arm_is_long(_)call_p.  Simplify logic.
+       (*call_symbol, *call_value_symbol, *call_insn, *call_value_insn):
+       Update calls to arm_is_long(_)call_p.
+
 2007-05-25  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/31982
index 9d24cd2..d9ec19a 100644 (file)
@@ -45,7 +45,6 @@ extern void arm_output_fn_unwind (FILE *, bool);
 
 #ifdef TREE_CODE
 extern int arm_return_in_memory (tree);
-extern void arm_encode_call_attribute (tree, int);
 #endif
 #ifdef RTX_CODE
 extern bool arm_vector_mode_supported_p (enum machine_mode);
@@ -121,7 +120,7 @@ extern void arm_print_operand (FILE *, rtx, int);
 extern void arm_print_operand_address (FILE *, rtx);
 extern void arm_final_prescan_insn (rtx);
 extern int arm_debugger_arg_offset (int, rtx);
-extern int arm_is_longcall_p (rtx, int, int);
+extern bool arm_is_long_call_p (tree);
 extern int    arm_emit_vector_const (FILE *, rtx);
 extern const char * arm_output_load_gr (rtx *);
 extern const char *vfp_output_fstmd (rtx *);
index c6b06da..dd75551 100644 (file)
@@ -104,7 +104,6 @@ static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
                               rtx);
 static void arm_reorg (void);
 static bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
-static int current_file_function_operand (rtx);
 static unsigned long arm_compute_save_reg0_reg12_mask (void);
 static unsigned long arm_compute_save_reg_mask (void);
 static unsigned long arm_isr_value (tree);
@@ -2782,21 +2781,6 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
   pcum->iwmmxt_nregs = 0;
   pcum->can_split = true;
 
-  pcum->call_cookie = CALL_NORMAL;
-
-  if (TARGET_LONG_CALLS)
-    pcum->call_cookie = CALL_LONG;
-
-  /* Check for long call/short call attributes.  The attributes
-     override any command line option.  */
-  if (fntype)
-    {
-      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
-       pcum->call_cookie = CALL_SHORT;
-      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
-       pcum->call_cookie = CALL_LONG;
-    }
-
   /* Varargs vectors are treated the same as long long.
      named_count avoids having to change the way arm handles 'named' */
   pcum->named_count = 0;
@@ -2867,8 +2851,8 @@ arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
     pcum->nregs++;
 
   if (mode == VOIDmode)
-    /* Compute operand 2 of the call insn.  */
-    return GEN_INT (pcum->call_cookie);
+    /* Pick an arbitrary value for operand 2 of the call insn.  */
+    return const0_rtx;
 
   /* Only allow splitting an arg between regs and memory if all preceding
      args were allocated to regs.  For args passed by reference we only count
@@ -3121,27 +3105,6 @@ arm_comp_type_attributes (tree type1, tree 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 (tree decl, int flag)
-{
-  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-  int          len = strlen (str);
-  char *       newstr;
-
-  /* Do not allow weak functions to be treated as short call.  */
-  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
-    return;
-
-  newstr = alloca (len + 2);
-  newstr[0] = flag;
-  strcpy (newstr + 1, str);
-
-  newstr = (char *) ggc_alloc_string (newstr, len + 1);
-  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.  */
@@ -3168,92 +3131,79 @@ arm_set_default_type_attributes (tree type)
     }
 }
 \f
-/* Return 1 if the operand is a SYMBOL_REF for a function known to be
-   defined within the current compilation unit.  If this cannot be
-   determined, then 0 is returned.  */
-static int
-current_file_function_operand (rtx sym_ref)
+/* Return true if DECL is known to be linked into section SECTION.  */
+
+static bool
+arm_function_in_section_p (tree decl, section *section)
 {
-  /* 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;
+  /* We can only be certain about functions defined in the same
+     compilation unit.  */
+  if (!TREE_STATIC (decl))
+    return false;
 
-  /* The current function is always defined within the current compilation
-     unit.  If it s a weak definition however, then this may not be the real
-     definition 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;
+  /* Make sure that SYMBOL always binds to the definition in this
+     compilation unit.  */
+  if (!targetm.binds_local_p (decl))
+    return false;
 
-  /* We cannot make the determination - default to returning 0.  */
-  return 0;
+  /* If DECL_SECTION_NAME is set, assume it is trustworthy.  */
+  if (!DECL_SECTION_NAME (decl))
+    {
+      /* Only cater for unit-at-a-time mode, where we know that the user
+        cannot later specify a section for DECL.  */
+      if (!flag_unit_at_a_time)
+       return false;
+
+      /* Make sure that we will not create a unique section for DECL.  */
+      if (flag_function_sections || DECL_ONE_ONLY (decl))
+       return false;
+    }
+
+  return function_section (decl) == section;
 }
 
 /* Return nonzero if a 32-bit "long_call" should be generated for
-   this call.  We generate a long_call if the function:
+   a call from the current function to DECL.  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
-         .  and either:
-                1. -ffunction-sections is in effect
-            or 2. the current function has __attribute__ ((section))
-            or 3. the target function has __attribute__ ((section))
 
    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.  is defined within the current compilation unit.
-
-   This function will be called by C fragments contained in the machine
-   description file.  SYM_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 (rtx sym_ref, int call_cookie, int call_symbol)
-{
-  if (!call_symbol)
-    {
-      if (GET_CODE (sym_ref) != MEM)
-       return 0;
+     or f.  is defined in the same section as the current function.  */
 
-      sym_ref = XEXP (sym_ref, 0);
-    }
+bool
+arm_is_long_call_p (tree decl)
+{
+  tree attrs;
 
-  if (GET_CODE (sym_ref) != SYMBOL_REF)
-    return 0;
+  if (!decl)
+    return TARGET_LONG_CALLS;
 
-  if (call_cookie & CALL_SHORT)
-    return 0;
+  attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
+  if (lookup_attribute ("short_call", attrs))
+    return false;
 
-  if (TARGET_LONG_CALLS)
-    {
-      if (flag_function_sections
-         || DECL_SECTION_NAME (current_function_decl))
-       /* c.3 is handled by the definition of the
-          ARM_DECLARE_FUNCTION_SIZE macro.  */
-       return 1;
-    }
+  /* For "f", be conservative, and only cater for cases in which the
+     whole of the current function is placed in the same section.  */
+  if (!flag_reorder_blocks_and_partition
+      && arm_function_in_section_p (decl, current_function_section ()))
+    return false;
 
-  if (current_file_function_operand (sym_ref))
-    return 0;
+  if (lookup_attribute ("long_call", attrs))
+    return true;
 
-  return (call_cookie & CALL_LONG)
-    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
-    || TARGET_LONG_CALLS;
+  return TARGET_LONG_CALLS;
 }
 
 /* Return nonzero if it is ok to make a tail-call to DECL.  */
 static bool
 arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
   unsigned long func_type;
 
   if (cfun->machine->sibcall_blocked)
@@ -3264,16 +3214,9 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   if (decl == NULL || TARGET_THUMB)
     return false;
 
-  /* Get the calling method.  */
-  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
-    call_type = CALL_SHORT;
-  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
-    call_type = CALL_LONG;
-
   /* Cannot tail-call to long calls, since these are out of range of
-     a branch instruction.  However, if not compiling PIC, we know
-     we can reach the symbol if it is in this compilation unit.  */
-  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
+     a branch instruction.  */
+  if (arm_is_long_call_p (decl))
     return false;
 
   /* If we are interworking and the function is not declared static
@@ -15603,17 +15546,6 @@ arm_encode_section_info (tree decl, rtx rtl, int first)
     SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
 #endif
 
-  /* 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.  */
-  if (first && DECL_P (decl))
-    {
-      if (TREE_CODE (decl) == FUNCTION_DECL && 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);
-    }
-
   default_encode_section_info (decl, rtl, first);
 }
 #endif /* !ARM_PE */
index d09bb73..e73b576 100644 (file)
@@ -1368,11 +1368,6 @@ do {                                                                           \
    than a word, or if they contain elements offset from zero in the struct.  */
 #define DEFAULT_PCC_STRUCT_RETURN 0
 
-/* Flags for the call/call_value rtl operations set up by function_arg.  */
-#define CALL_NORMAL            0x00000000      /* No special processing.  */
-#define CALL_LONG              0x00000001      /* Always call indirect.  */
-#define CALL_SHORT             0x00000002      /* Never call indirect.  */
-
 /* These bits describe the different types of function supported
    by the ARM backend.  They are exclusive.  i.e. a function cannot be both a
    normal function and an interworked function, for example.  Knowing the
@@ -1471,8 +1466,6 @@ typedef struct
   int iwmmxt_nregs;
   int named_count;
   int nargs;
-  /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT.  */
-  int call_cookie;
   int can_split;
 } CUMULATIVE_ARGS;
 
@@ -1853,18 +1846,6 @@ typedef struct
    && (TARGET_32BIT ? ARM_LEGITIMATE_CONSTANT_P (X)    \
                    : THUMB_LEGITIMATE_CONSTANT_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
@@ -1874,8 +1855,6 @@ typedef struct
    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
 
@@ -1942,15 +1921,6 @@ typedef struct
 #define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P true
 #endif
 
-/* Set the short-call flag for any function compiled in the current
-   compilation unit.  We skip this for functions with the section
-   attribute when long-calls are in effect as this tells the compiler
-   that the section might be placed a long way from the caller.
-   See arm_is_longcall_p() for more information.  */
-#define ARM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL)  \
-  if (!TARGET_LONG_CALLS || ! DECL_SECTION_NAME (DECL)) \
-    arm_encode_call_attribute (DECL, SHORT_CALL_FLAG_CHAR)
-
 #define ARM_OUTPUT_FN_UNWIND(F, PROLOGUE) arm_output_fn_unwind (F, PROLOGUE)
 
 #ifdef TARGET_UNWIND_INFO
index 37bfe88..2ae732a 100644 (file)
     if (operands[2] == NULL_RTX)
       operands[2] = const0_rtx;
       
-    /* This is to decide if we should generate indirect calls by loading the
+    /* 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) == SYMBOL_REF
-        && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
-       || (GET_CODE (callee) != SYMBOL_REF
-           && GET_CODE (callee) != REG))
+       branch and link.  */
+    callee = XEXP (operands[0], 0);
+    if (GET_CODE (callee) == SYMBOL_REF
+       ? arm_is_long_call_p (SYMBOL_REF_DECL (callee))
+       : !REG_P (callee))
       XEXP (operands[0], 0) = force_reg (Pmode, callee);
   }"
 )
   "TARGET_EITHER"
   "
   {
-    rtx callee = XEXP (operands[1], 0);
+    rtx callee;
     
     /* In an untyped call, we can get NULL for operand 2.  */
     if (operands[3] == 0)
       operands[3] = const0_rtx;
       
-    /* See the comment in define_expand \"call\".  */
-    if ((GET_CODE (callee) == SYMBOL_REF
-        && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
-       || (GET_CODE (callee) != SYMBOL_REF
-           && GET_CODE (callee) != REG))
+    /* 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.  */
+    callee = XEXP (operands[1], 0);
+    if (GET_CODE (callee) == SYMBOL_REF
+       ? arm_is_long_call_p (SYMBOL_REF_DECL (callee))
+       : !REG_P (callee))
       XEXP (operands[1], 0) = force_reg (Pmode, callee);
   }"
 )
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_ARM
    && (GET_CODE (operands[0]) == SYMBOL_REF)
-   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
+   && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
   "*
   {
     return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_ARM
    && (GET_CODE (operands[1]) == SYMBOL_REF)
-   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
+   && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
   "*
   {
     return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB
    && GET_CODE (operands[0]) == SYMBOL_REF
-   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
+   && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
   "bl\\t%a0"
   [(set_attr "length" "4")
    (set_attr "type" "call")]
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_THUMB
    && GET_CODE (operands[1]) == SYMBOL_REF
-   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
+   && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
   "bl\\t%a1"
   [(set_attr "length" "4")
    (set_attr "type" "call")]
index 89584ce..bce5ad6 100644 (file)
@@ -87,7 +87,6 @@
   do                                                           \
     {                                                          \
       ARM_OUTPUT_FN_UNWIND (FILE, FALSE);                      \
-      ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL);           \
       if (!flag_inhibit_size_directive)                                \
        ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME);                 \
     }                                                          \
index c0cbf9b..499acb2 100644 (file)
@@ -1,3 +1,10 @@
+2007-05-25  Richard Sandiford  <richard@codesourcery.com>
+
+       * gcc.target/arm/long-calls-1.c: New test.
+       * gcc.target/arm/long-calls-2.c: Likewise.
+       * gcc.target/arm/long-calls-3.c: Likewise.
+       * gcc.target/arm/long-calls-4.c: Likewise.
+
 2007-05-25  Richard Guenther  <rguenther@suse.de>
        Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
diff --git a/gcc/testsuite/gcc.target/arm/long-calls-1.c b/gcc/testsuite/gcc.target/arm/long-calls-1.c
new file mode 100644 (file)
index 0000000..7c2e7fe
--- /dev/null
@@ -0,0 +1,126 @@
+/* Check that long calls to different sections are not optimized to "bl".  */
+/* { dg-do compile { target { arm32 && nonpic } } } */
+/* { dg-options "-O2" } */
+
+#define section(S) __attribute__((section(S)))
+#define weak __attribute__((weak))
+#define noinline __attribute__((noinline))
+#define long_call __attribute__((long_call))
+#define short_call __attribute__((short_call))
+
+#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS ID (void);                                  \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
+
+#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS noinline ID (void) { return #ID; }          \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  static const char *TARGET_ATTRS noinline ID (void) { return #ID; }   \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS)                       \
+  TEST (ID##1, TARGET_ATTRS, )                                         \
+  TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b"))  \
+  TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
+
+#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS)                     \
+  DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS)                         \
+  DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call)               \
+  DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
+
+DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
+DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
+DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
+DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
+
+
+/* Calls to remote_* should honor the call type sttribute,
+   with "short" being the default.  */
+
+/* { dg-final { scan-assembler "\tbl\tremote_n1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_n3\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tremote_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s3\n" } } */
+
+
+/* Calls to strong_*2 calls should honor the call type attribute,
+   with "short" being the default.  Calls to other strong_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_n1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_n2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_n3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_l1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_l3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s3\n" } } */
+
+
+/* Calls to weak_* should honor the call type sttribute,
+   with "short" being the default.  */
+
+/* { dg-final { scan-assembler "\tbl\tweak_n1\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_n2\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_n3\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n3\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tweak_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s3\n" } } */
+
+
+/* Calls to static_*2 calls should honor the call type attribute,
+   with "short" being the default.  Calls to other static_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_n1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_l1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_l3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s3\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/long-calls-2.c b/gcc/testsuite/gcc.target/arm/long-calls-2.c
new file mode 100644 (file)
index 0000000..c63f8ab
--- /dev/null
@@ -0,0 +1,121 @@
+/* Check that long calls to different sections are not optimized to "bl".  */
+/* { dg-do compile { target { arm32 && nonpic } } } */
+/* { dg-options "-O2 -mlong-calls" } */
+
+#define section(S) __attribute__((section(S)))
+#define weak __attribute__((weak))
+#define noinline __attribute__((noinline))
+#define long_call __attribute__((long_call))
+#define short_call __attribute__((short_call))
+
+#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS ID (void);                                  \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
+
+#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS noinline ID (void) { return #ID; }          \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  static const char *TARGET_ATTRS noinline ID (void) { return #ID; }   \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS)                       \
+  TEST (ID##1, TARGET_ATTRS, )                                         \
+  TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b"))  \
+  TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
+
+#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS)                     \
+  DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS)                         \
+  DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call)               \
+  DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
+
+DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
+DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
+DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
+DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
+
+
+/* Calls to remote_* should honor the call type sttribute,
+   with "long" being the default.  */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_n1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_n2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_n3\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tremote_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s3\n" } } */
+
+
+/* Calls to strong_*2 calls should honor the call type attribute,
+   with "long" being the default.  Calls to other strong_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_n1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tstrong_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_n3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_l1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_l3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s3\n" } } */
+
+
+/* Calls to weak_* should honor the call type sttribute,
+   with "long" being the default.  */
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n3\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tweak_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s3\n" } } */
+
+
+/* Calls to static_*2 calls should honor the call type attribute,
+   with "long" being the default.  Calls to other static_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_n1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_n2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_l1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l1\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_l3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l3\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_s1\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s1\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s2\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s2\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s3\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s3\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/long-calls-3.c b/gcc/testsuite/gcc.target/arm/long-calls-3.c
new file mode 100644 (file)
index 0000000..9281715
--- /dev/null
@@ -0,0 +1,117 @@
+/* Check that long calls to different sections are not optimized to "bl".  */
+/* { dg-do compile { target { arm32 && fpic } } } */
+/* { dg-options "-O2 -fpic" } */
+
+#define section(S) __attribute__((section(S)))
+#define weak __attribute__((weak))
+#define noinline __attribute__((noinline))
+#define long_call __attribute__((long_call))
+#define short_call __attribute__((short_call))
+
+#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS ID (void);                                  \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
+
+#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS noinline ID (void) { return #ID; }          \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  static const char *TARGET_ATTRS noinline ID (void) { return #ID; }   \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS)                       \
+  TEST (ID##1, TARGET_ATTRS, )                                         \
+  TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b"))  \
+  TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
+
+#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS)                     \
+  DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS)                         \
+  DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call)               \
+  DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
+
+DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
+DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
+DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
+DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
+
+
+/* Calls to remote_*, strong_* and weak_* should honor the call type
+   sttribute, with "short" being the default.  */
+
+/* { dg-final { scan-assembler "\tbl\tremote_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tremote_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s3\\(PLT\\)\n" } } */
+
+
+/* { dg-final { scan-assembler "\tbl\tstrong_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_n3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl\tstrong_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tstrong_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s3\\(PLT\\)\n" } } */
+
+
+/* { dg-final { scan-assembler "\tbl\tweak_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_n3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tweak_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s3\\(PLT\\)\n" } } */
+
+
+/* Calls to static_*2 calls should honor the call type attribute,
+   with "short" being the default.  Calls to other static_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_n1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n3(\\(PLT\\))\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_l1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_l3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l3(\\(PLT\\))\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_s1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s3(\\(PLT\\))\n" } } */
diff --git a/gcc/testsuite/gcc.target/arm/long-calls-4.c b/gcc/testsuite/gcc.target/arm/long-calls-4.c
new file mode 100644 (file)
index 0000000..facf85c
--- /dev/null
@@ -0,0 +1,110 @@
+/* Check that long calls to different sections are not optimized to "bl".  */
+/* { dg-do compile { target { arm32 && fpic } } } */
+/* { dg-options "-O2 -fpic -mlong-calls" } */
+
+#define section(S) __attribute__((section(S)))
+#define weak __attribute__((weak))
+#define noinline __attribute__((noinline))
+#define long_call __attribute__((long_call))
+#define short_call __attribute__((short_call))
+
+#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS ID (void);                                  \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
+
+#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  const char *TARGET_ATTRS noinline ID (void) { return #ID; }          \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS)                      \
+  static const char *TARGET_ATTRS noinline ID (void) { return #ID; }   \
+  const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }                \
+  const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
+
+#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS)                       \
+  TEST (ID##1, TARGET_ATTRS, )                                         \
+  TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b"))  \
+  TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
+
+#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS)                     \
+  DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS)                         \
+  DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call)               \
+  DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
+
+DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
+DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
+DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
+DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
+
+
+/* Calls to remote_*, strong_* and weak_* should honor the call type
+   sttribute, with "long" being the default.  */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl\tremote_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl\tremote_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tremote_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tremote_s3\\(PLT\\)\n" } } */
+
+
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstrong_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstrong_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstrong_s3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tstrong_s3\\(PLT\\)\n" } } */
+
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_n3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\\(PLT\\)\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tweak_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s1\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s2\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tbl\tweak_s3\\(PLT\\)\n" } } */
+/* { dg-final { scan-assembler "\tb\tweak_s3\\(PLT\\)\n" } } */
+
+
+/* Calls to static_*2 calls should honor the call type attribute,
+   with "long" being the default.  Calls to other static_* functions
+   should be short.  */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_n1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_n2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_n3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_n3(\\(PLT\\))\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_l1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_l3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_l3(\\(PLT\\))\n" } } */
+
+/* { dg-final { scan-assembler "\tbl\tstatic_s1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s1(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s2(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tbl\tstatic_s3(\\(PLT\\))\n" } } */
+/* { dg-final { scan-assembler "\tb\tstatic_s3(\\(PLT\\))\n" } } */