Add ARM/thumb attribute target
authorChristian Bruel <christian.bruel@st.com>
Wed, 10 Jun 2015 07:50:59 +0000 (09:50 +0200)
committerChristian Bruel <chrbr@gcc.gnu.org>
Wed, 10 Jun 2015 07:50:59 +0000 (09:50 +0200)
PR target/52144

* config/arm/arm.opt (THUMB, arm_restrict_it, inline_asm_unified): Save.
* config/arm/arm-protos.h (arm_valid_target_attribute_tree): Declare.
(arm_reset_previous_fndecl, arm_change_mode_p): Likewise.
* config/arm/arm.h (SWITCHABLE_TARGET): Define.
* config/arm/arm.c (arm_reset_previous_fndecl): New functions.
(arm_valid_target_attribute_tree, arm_change_mode_p): Likewise.
(arm_valid_target_attribute_p): Likewise.
(arm_set_current_function, arm_can_inline_p): Likewise.
(arm_valid_target_attribute_rec): Likewise.
(arm_previous_fndecl): New variable.
(TARGET_SET_CURRENT_FUNCTION, TARGET_OPTION_VALID_ATTRIBUTE_P): Define.
(TARGET_CAN_INLINE_P): Define.
(arm_asm_trampoline_template): Emit mode.
(arm_file_start): Don't set unified syntax.
(arm_declare_function_name): Set unified syntax and mode.
(arm_option_override): Init target_option_default_node.
and target_option_current_node.
* config/arm/arm.md (*call_value_symbol): Set mode when possible.
(*call_symbol): Likewise.
* doc/extend.texi: Document ARM/Thumb target attribute.
* doc/invoke.texi: Likewise.

* gcc.target/arm/attr_arm.c: New test
* gcc.target/arm/attr_arm-err.c: New test
* gcc.target/arm/attr_thumb.c: New test
* gcc.target/arm/attr_thumb-static.c: New test

From-SVN: r224314

13 files changed:
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/arm.opt
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/attr_arm-err.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/attr_arm.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/attr_thumb-static.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/attr_thumb.c [new file with mode: 0644]

index bd62288ed7375f572b49f20b5be3b5922c513988..a73afaa6b28fb1c85549e410e60f32e4bc00f7f4 100644 (file)
@@ -1,3 +1,28 @@
+2015-06-09  Christian Bruel  <christian.bruel@st.com>
+
+       PR target/52144
+       * config/arm/arm.opt (THUMB, arm_restrict_it, inline_asm_unified): Save.
+       * config/arm/arm-protos.h (arm_valid_target_attribute_tree): Declare.
+       (arm_reset_previous_fndecl, arm_change_mode_p): Likewise.
+       * config/arm/arm.h (SWITCHABLE_TARGET): Define.
+       * config/arm/arm.c (arm_reset_previous_fndecl): New functions.
+       (arm_valid_target_attribute_tree, arm_change_mode_p): Likewise.
+       (arm_valid_target_attribute_p): Likewise.
+       (arm_set_current_function, arm_can_inline_p): Likewise.
+       (arm_valid_target_attribute_rec): Likewise.
+       (arm_previous_fndecl): New variable.
+       (TARGET_SET_CURRENT_FUNCTION, TARGET_OPTION_VALID_ATTRIBUTE_P): Define.
+       (TARGET_CAN_INLINE_P): Define.
+       (arm_asm_trampoline_template): Emit mode.
+       (arm_file_start): Don't set unified syntax.
+       (arm_declare_function_name): Set unified syntax and mode.
+       (arm_option_override): Init target_option_default_node.
+       and target_option_current_node.
+       * config/arm/arm.md (*call_value_symbol): Set mode when possible.
+       (*call_symbol): Likewise.
+       * doc/extend.texi: Document ARM/Thumb target attribute.
+       * doc/invoke.texi: Likewise.
+
 2015-06-09  Alexandre Oliva <aoliva@redhat.com>
 
        Revert:
index d1f2d4ecdace7bf711bc7e87864a13ba4e6e727a..3092b1a0592e454c0ff32d031bb67989f865a7de 100644 (file)
@@ -210,6 +210,9 @@ extern int arm_dllexport_p (tree);
 extern int arm_dllimport_p (tree);
 extern void arm_mark_dllexport (tree);
 extern void arm_mark_dllimport (tree);
+extern bool arm_change_mode_p (tree);
+extern tree arm_valid_target_attribute_tree (tree, struct gcc_options *,
+                                            struct gcc_options *);
 #endif
 
 extern void arm_pr_long_calls (struct cpp_reader *);
@@ -326,6 +329,8 @@ extern bool arm_autoinc_modes_ok_p (machine_mode, enum arm_auto_incmodes);
 
 extern void arm_emit_eabi_attribute (const char *, int, int);
 
+extern void arm_reset_previous_fndecl (void);
+
 /* Defined in gcc/common/config/arm-common.c.  */
 extern const char *arm_rewrite_selected_cpu (const char *name);
 
index a959b9c420d40301afaa49ba44cbe2674f77b68d..353c2c599d90e167dd072c689aa39c1678604fdc 100644 (file)
@@ -81,6 +81,7 @@
 #include "opts.h"
 #include "dumpfile.h"
 #include "gimple-expr.h"
+#include "target-globals.h"
 #include "builtins.h"
 #include "tm-constrs.h"
 #include "rtl-iter.h"
@@ -252,6 +253,9 @@ static tree arm_build_builtin_va_list (void);
 static void arm_expand_builtin_va_start (tree, rtx);
 static tree arm_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 static void arm_option_override (void);
+static void arm_set_current_function (tree);
+static bool arm_can_inline_p (tree, tree);
+static bool arm_valid_target_attribute_p (tree, tree, tree, int);
 static unsigned HOST_WIDE_INT arm_shift_truncation_mask (machine_mode);
 static bool arm_macro_fusion_p (void);
 static bool arm_cannot_copy_insn_p (rtx_insn *);
@@ -400,6 +404,9 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef  TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
 
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P arm_can_inline_p
+
 #undef  TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE arm_option_override
 
@@ -418,6 +425,12 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef  TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST arm_adjust_cost
 
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION arm_set_current_function
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P arm_valid_target_attribute_p
+
 #undef TARGET_SCHED_REORDER
 #define TARGET_SCHED_REORDER arm_sched_reorder
 
@@ -2778,6 +2791,9 @@ arm_option_params_internal (struct gcc_options *opts)
     max_insns_skipped = current_tune->max_insns_skipped;
 }
 
+/* Options after initial target override.  */
+static GTY(()) tree init_optimize;
+
 /* Reset options between modes that the user has specified.  */
 static void
 arm_option_override_internal (struct gcc_options *opts,
@@ -2800,23 +2816,29 @@ arm_option_override_internal (struct gcc_options *opts,
   if (TARGET_THUMB_P (opts->x_target_flags) && TARGET_CALLEE_INTERWORKING)
     opts->x_target_flags |= MASK_INTERWORK;
 
+  /* need to remember initial values so combinaisons of options like
+     -mflip-thumb -mthumb -fno-schedule-insns work for any attribute.  */
+  cl_optimization *to = TREE_OPTIMIZATION (init_optimize);
+
   if (! opts_set->x_arm_restrict_it)
     opts->x_arm_restrict_it = arm_arch8;
 
   if (!TARGET_THUMB2_P (opts->x_target_flags))
     opts->x_arm_restrict_it = 0;
 
+  /* Don't warn since it's on by default in -O2.  */
   if (TARGET_THUMB1_P (opts->x_target_flags))
-    {
-      /* Don't warn since it's on by default in -O2.  */
-      opts->x_flag_schedule_insns = 0;
-    }
+    opts->x_flag_schedule_insns = 0;
+  else
+    opts->x_flag_schedule_insns = to->x_flag_schedule_insns;
 
   /* Disable shrink-wrap when optimizing function for size, since it tends to
      generate additional returns.  */
   if (optimize_function_for_size_p (cfun)
       && TARGET_THUMB2_P (opts->x_target_flags))
     opts->x_flag_shrink_wrap = false;
+  else
+    opts->x_flag_shrink_wrap = to->x_flag_shrink_wrap;
 
   /* In Thumb1 mode, we emit the epilogue in RTL, but the last insn
      - epilogue_insns - does not accurately model the corresponding insns
@@ -2828,6 +2850,8 @@ arm_option_override_internal (struct gcc_options *opts,
      fipa-ra.  */
   if (TARGET_THUMB1_P (opts->x_target_flags))
     opts->x_flag_ipa_ra = 0;
+  else
+    opts->x_flag_ipa_ra = to->x_flag_ipa_ra;
 
   /* Thumb2 inline assembly code should always use unified syntax.
      This will apply to ARM and Thumb1 eventually.  */
@@ -3330,12 +3354,20 @@ arm_option_override (void)
       && (!arm_arch7 || !current_tune->prefer_ldrd_strd))
     flag_schedule_fusion = 0;
 
+  /* Need to remember initial options before they are overriden.  */
+  init_optimize = build_optimization_node (&global_options);
+
   arm_option_override_internal (&global_options, &global_options_set);
   arm_option_check_internal (&global_options);
   arm_option_params_internal (&global_options);
 
   /* Register global variables with the garbage collector.  */
   arm_add_gc_roots ();
+
+  /* Save the initial options in case the user does function specific
+     options.  */
+  target_option_default_node = target_option_current_node
+    = build_target_option_node (&global_options);
 }
 
 static void
@@ -3489,13 +3521,20 @@ arm_warn_func_return (tree decl)
 static void
 arm_asm_trampoline_template (FILE *f)
 {
+  if (TARGET_UNIFIED_ASM)
+    fprintf (f, "\t.syntax unified\n");
+  else
+    fprintf (f, "\t.syntax divided\n");
+
   if (TARGET_ARM)
     {
+      fprintf (f, "\t.arm\n");
       asm_fprintf (f, "\tldr\t%r, [%r, #0]\n", STATIC_CHAIN_REGNUM, PC_REGNUM);
       asm_fprintf (f, "\tldr\t%r, [%r, #0]\n", PC_REGNUM, PC_REGNUM);
     }
   else if (TARGET_THUMB2)
     {
+      fprintf (f, "\t.thumb\n");
       /* The Thumb-2 trampoline is similar to the arm implementation.
         Unlike 16-bit Thumb, we enter the stub in thumb mode.  */
       asm_fprintf (f, "\tldr.w\t%r, [%r, #4]\n",
@@ -24193,6 +24232,24 @@ arm_init_expanders (void)
     mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
 }
 
+/* Check that FUNC is called with a different mode.  */
+
+bool
+arm_change_mode_p (tree func)
+{
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return false;
+
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (func);
+
+  if (!callee_tree)
+    callee_tree = target_option_default_node;
+
+  struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+  int flags = callee_opts->x_target_flags;
+
+  return (TARGET_THUMB_P (flags) != TARGET_THUMB);
+}
 
 /* Like arm_compute_initial_elimination offset.  Simpler because there
    isn't an ABI specified frame pointer for Thumb.  Instead, we set it
@@ -25520,9 +25577,6 @@ arm_file_start (void)
 {
   int val;
 
-  if (TARGET_UNIFIED_ASM)
-    asm_fprintf (asm_out_file, "\t.syntax unified\n");
-
   if (TARGET_BPABI)
     {
       const char *fpu_name;
@@ -29269,9 +29323,196 @@ arm_is_constant_pool_ref (rtx x)
          && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
 }
 
+/* Remember the last target of arm_set_current_function.  */
+static GTY(()) tree arm_previous_fndecl;
+
+/* Invalidate arm_previous_fndecl.  */
+void
+arm_reset_previous_fndecl (void)
+{
+  arm_previous_fndecl = NULL_TREE;
+}
+
+/* Establish appropriate back-end context for processing the function
+   FNDECL.  The argument might be NULL to indicate processing at top
+   level, outside of any function scope.  */
+static void
+arm_set_current_function (tree fndecl)
+{
+  if (!fndecl || fndecl == arm_previous_fndecl)
+    return;
+
+  tree old_tree = (arm_previous_fndecl
+                  ? DECL_FUNCTION_SPECIFIC_TARGET (arm_previous_fndecl)
+                  : NULL_TREE);
+
+  tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
+
+  arm_previous_fndecl = fndecl;
+  if (old_tree == new_tree)
+    ;
+
+  else if (new_tree)
+    {
+      cl_target_option_restore (&global_options,
+                               TREE_TARGET_OPTION (new_tree));
+
+      if (TREE_TARGET_GLOBALS (new_tree))
+       restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
+      else
+       TREE_TARGET_GLOBALS (new_tree)
+         = save_target_globals_default_opts ();
+    }
+
+  else if (old_tree)
+    {
+      new_tree = target_option_current_node;
+
+      cl_target_option_restore (&global_options,
+                               TREE_TARGET_OPTION (new_tree));
+      if (TREE_TARGET_GLOBALS (new_tree))
+       restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
+      else if (new_tree == target_option_default_node)
+       restore_target_globals (&default_target_globals);
+      else
+       TREE_TARGET_GLOBALS (new_tree)
+         = save_target_globals_default_opts ();
+    }
+
+  arm_option_params_internal (&global_options);
+}
+
+/* Hook to determine if one function can safely inline another.  */
+
+static bool
+arm_can_inline_p (tree caller ATTRIBUTE_UNUSED, tree callee ATTRIBUTE_UNUSED)
+{
+  /* Overidde default hook: Always OK to inline between different modes. 
+     Function with mode specific instructions, e.g using asm, must be explicitely 
+     protected with noinline.  */
+  return true;
+}
+
+/* Inner function to process the attribute((target(...))), take an argument and
+   set the current options from the argument.  If we have a list, recursively
+   go over the list.  */
+
+static bool
+arm_valid_target_attribute_rec (tree args,  struct gcc_options *opts)
+{
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      bool ret = true;
+      for (; args; args = TREE_CHAIN (args))
+       if (TREE_VALUE (args)
+           && !arm_valid_target_attribute_rec (TREE_VALUE (args), opts))
+         ret = false;
+      return ret;
+    }
+
+  else if (TREE_CODE (args) != STRING_CST)
+    {
+      error ("attribute %<target%> argument not a string");
+      return false;
+    }
+
+  char *argstr = ASTRDUP (TREE_STRING_POINTER (args));
+  while (argstr && *argstr != '\0')
+    {
+      while (ISSPACE (*argstr))
+       argstr++;
+
+      if (!strcmp (argstr, "thumb"))
+       {
+         opts->x_target_flags |= MASK_THUMB;
+         arm_option_check_internal (opts);
+         return true;
+       }
+
+      if (!strcmp (argstr, "arm"))
+       {
+         opts->x_target_flags &= ~MASK_THUMB;
+         arm_option_check_internal (opts);
+         return true;
+       }
+
+      warning (0, "attribute(target(\"%s\")) is unknown", argstr);
+      return false;
+    }
+
+  return false;
+}
+
+/* Return a TARGET_OPTION_NODE tree of the target options listed or NULL.  */
+
+tree
+arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
+                                struct gcc_options *opts_set)
+{
+  if (!arm_valid_target_attribute_rec (args, opts))
+    return NULL_TREE;
+
+  /* Do any overrides, such as global options arch=xxx.  */
+  arm_option_override_internal (opts, opts_set);
+
+  return build_target_option_node (opts);
+}
+
+/* Hook to validate attribute((target("string"))).  */
+
+static bool
+arm_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
+                             tree args, int ARG_UNUSED (flags))
+{
+  bool ret = true;
+  struct gcc_options func_options;
+  tree cur_tree, new_optimize;
+  gcc_assert ((fndecl != NULL_TREE) && (args != NULL_TREE));
+
+  /* Get the optimization options of the current function.  */
+  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  /* If the function changed the optimization levels as well as setting target
+     options, start with the optimizations specified.  */
+  if (!func_optimize)
+    func_optimize = optimization_default_node;
+
+  /* Init func_options.  */
+  memset (&func_options, 0, sizeof (func_options));
+  init_options_struct (&func_options, NULL);
+  lang_hooks.init_options_struct (&func_options);
+
+  /* Initialize func_options to the defaults.  */
+  cl_optimization_restore (&func_options,
+                          TREE_OPTIMIZATION (func_optimize));
+
+  cl_target_option_restore (&func_options,
+                           TREE_TARGET_OPTION (target_option_default_node));
+
+  /* Set func_options flags with new target mode.  */
+  cur_tree = arm_valid_target_attribute_tree (args, &func_options,
+                                             &global_options_set);
+
+  if (cur_tree == NULL_TREE)
+    ret = false;
+
+  new_optimize = build_optimization_node (&func_options);
+
+  DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = cur_tree;
+
+  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+
+  return ret;
+}
+
 void
 arm_declare_function_name (FILE *stream, const char *name, tree decl)
 {
+  if (TARGET_UNIFIED_ASM)
+    fprintf (stream, "\t.syntax unified\n");
+  else
+    fprintf (stream, "\t.syntax divided\n");
+
   if (TARGET_THUMB)
     {
       if (is_called_in_ARM_mode (decl)
@@ -29283,6 +29524,8 @@ arm_declare_function_name (FILE *stream, const char *name, tree decl)
       else
        fprintf (stream, "\t.thumb\n\t.thumb_func\n");
     }
+  else
+    fprintf (stream, "\t.arm\n");
 
   if (TARGET_POKE_FUNCTION_NAME)
     arm_poke_function_name (stream, (const char *) name);
index df0aeb4a825503cc7f941cc7768ab51a4971d839..b24b4fb7d0a88bfc46e4aa11202ac8b0d649747c 100644 (file)
@@ -2258,4 +2258,8 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 
 #define DRIVER_SELF_SPECS MCPU_MTUNE_NATIVE_SPECS
 #define TARGET_SUPPORTS_WIDE_INT 1
+
+/* For switching between functions with different target attributes.  */
+#define SWITCHABLE_TARGET 1
+
 #endif /* ! GCC_ARM_H */
index 191f5e768276f104970c88c8ea9dc15aa026f99c..1ac8af099ce1e2cef0d1aefae898e96d32f2ef97 100644 (file)
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
   "*
   {
+   rtx op = operands[0];
+
+   /* Switch mode now when possible.  */
+   if (SYMBOL_REF_DECL (op) && !TREE_PUBLIC (SYMBOL_REF_DECL (op))
+        && arm_arch5 && arm_change_mode_p (SYMBOL_REF_DECL (op)))
+      return NEED_PLT_RELOC ? \"blx%?\\t%a0(PLT)\" : \"blx%?\\t(%a0)\";
+
     return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
   }"
   [(set_attr "type" "call")]
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
   "*
   {
+   rtx op = operands[1];
+
+   /* Switch mode now when possible.  */
+   if (SYMBOL_REF_DECL (op) && !TREE_PUBLIC (SYMBOL_REF_DECL (op))
+        && arm_arch5 && arm_change_mode_p (SYMBOL_REF_DECL (op)))
+      return NEED_PLT_RELOC ? \"blx%?\\t%a0(PLT)\" : \"blx%?\\t(%a0)\";
+
     return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
   }"
   [(set_attr "type" "call")]
index d4ff164c7ef43a71a380c20ba431db659ee30761..59e5385803ea09979a07c8589dc416e31ebb9519 100644 (file)
@@ -182,7 +182,7 @@ Target RejectNegative Joined UInteger Var(arm_structure_size_boundary) Init(DEFA
 Specify the minimum bit alignment of structures
 
 mthumb
-Target Report RejectNegative Mask(THUMB)
+Target Report RejectNegative Mask(THUMB) Save
 Generate code for Thumb state
 
 mthumb-interwork
@@ -246,7 +246,7 @@ Target Report Var(target_word_relocations) Init(TARGET_DEFAULT_WORD_RELOCATIONS)
 Only generate absolute relocations on word sized values.
 
 mrestrict-it
-Target Report Var(arm_restrict_it) Init(2)
+Target Report Var(arm_restrict_it) Init(2) Save
 Generate IT blocks appropriate for ARMv8.
 
 mold-rtx-costs
@@ -275,5 +275,5 @@ Target Report Var(target_slow_flash_data) Init(0)
 Assume loading data from flash is slower than fetching instructions.
 
 masm-syntax-unified
-Target Report Var(inline_asm_unified) Init(0)
+Target Report Var(inline_asm_unified) Init(0) Save
 Assume unified syntax for Thumb inline assembly code.
index ecdd3c8023f3fd1c35754f82d9696733bbd9f100..9ad2b680ea51c6a2d47160e311d32e4e08b88fbf 100644 (file)
@@ -3098,8 +3098,9 @@ strings separated by commas to specify multiple options,
 or separate the options with a comma (@samp{,}) within a single string.
 
 The options supported are specific to each target; refer to @ref{x86
-Function Attributes}, @ref{PowerPC Function Attributes}, and
-@ref{Nios II Function Attributes}, for details.
+Function Attributes}, @ref{PowerPC Function Attributes},
+@ref{ARM Function Attributes},and @ref{Nios II Function Attributes},
+for details.
 
 @item unused
 @cindex @code{unused} function attribute
@@ -3448,6 +3449,27 @@ double f2d (float) __attribute__((pcs("aapcs")));
 
 Variadic functions always use the @code{"aapcs"} calling convention and
 the compiler rejects attempts to specify an alternative.
+
+@item target (@var{options})
+@cindex @code{target} function attribute
+As discussed in @ref{Common Function Attributes}, this attribute 
+allows specification of target-specific compilation options.
+
+On ARM, the following options are allowed:
+
+@table @samp
+@item thumb
+@cindex @code{target("thumb")} function attribute, ARM
+Force code generation in the Thumb (T16/T32) ISA, depending on the
+architecture level.
+
+@item arm
+@cindex @code{target("arm")} function attribute, ARM
+Force code generation in the ARM (A32) ISA.
+@end table
+
+Functions from different modes can be inlined in the caller's mode.
+
 @end table
 
 @node AVR Function Attributes
index a954d49cf97e582a172d3f2912692242d3c87b80..5903c751579873da42dbf0901c6b2ae73b988607 100644 (file)
@@ -13512,6 +13512,10 @@ that executes in ARM state, but the default can be changed by
 configuring GCC with the @option{--with-mode=}@var{state}
 configure option.
 
+You can also override the ARM and Thumb mode for each function
+by using the @code{target("thumb")} and @code{target("arm")} function attributes
+(@pxref{ARM Function Attributes}) or pragmas (@pxref{Function Specific Option Pragmas}).
+
 @item -mtpcs-frame
 @opindex mtpcs-frame
 Generate a stack frame that is compliant with the Thumb Procedure Call
index 7ab292f9ec60412f6fa4ee6b79acc16506cd1017..d0527f70e3a84875517adfd30a9f7a772d754a64 100644 (file)
@@ -1,3 +1,11 @@
+2015-06-09  Christian Bruel  <christian.bruel@st.com>
+
+       PR target/52144
+       * gcc.target/arm/attr_arm.c: New test
+       * gcc.target/arm/attr_arm-err.c: New test
+       * gcc.target/arm/attr_thumb.c: New test
+       * gcc.target/arm/attr_thumb-static.c: New test
+
 2015-06-10  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
 
        PR target/66200
diff --git a/gcc/testsuite/gcc.target/arm/attr_arm-err.c b/gcc/testsuite/gcc.target/arm/attr_arm-err.c
new file mode 100644 (file)
index 0000000..630c06a
--- /dev/null
@@ -0,0 +1,13 @@
+/* Check that attribute target arm is rejected for M profile.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arm_ok } */
+/* { dg-skip-if "avoid conflicting multilib options" { *-*-* } { "-march=*" } { "-march=armv6-m" } } */
+/* { dg-add-options arm_arch_v6m } */
+
+int __attribute__((target("arm")))
+foo(int a)
+{  /* { dg-error "does not support" } */
+  return a ? 1 : 5;
+}
+
+
diff --git a/gcc/testsuite/gcc.target/arm/attr_arm.c b/gcc/testsuite/gcc.target/arm/attr_arm.c
new file mode 100644 (file)
index 0000000..7e8d53d
--- /dev/null
@@ -0,0 +1,13 @@
+/* Check that attribute target arm is recogniwed.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_arm_ok } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler ".arm" } } */
+/* { dg-final { scan-assembler-not "ite" } } */
+
+int __attribute__((target("arm")))
+foo(int a)
+{
+  return a ? 1 : 5;
+}
+
diff --git a/gcc/testsuite/gcc.target/arm/attr_thumb-static.c b/gcc/testsuite/gcc.target/arm/attr_thumb-static.c
new file mode 100644 (file)
index 0000000..8dc6451
--- /dev/null
@@ -0,0 +1,24 @@
+/* Check that a change mode to a static function is correctly handled. */
+/* { dg-do run } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+
+static void
+ __attribute__((__noinline__)) 
+foo (void)
+{
+  __asm__ ("");
+}
+
+static void
+__attribute__((__noinline__)) 
+__attribute__((target("thumb")))
+bar (void)
+{
+  __asm__ ("");
+}
+
+int main()
+{
+  foo();
+  bar();
+}
diff --git a/gcc/testsuite/gcc.target/arm/attr_thumb.c b/gcc/testsuite/gcc.target/arm/attr_thumb.c
new file mode 100644 (file)
index 0000000..0134021
--- /dev/null
@@ -0,0 +1,13 @@
+/* Check that attribute target thumb is recogniwed. */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler ".thumb" } } */
+/* { dg-final { scan-assembler "ite" } } */
+
+int __attribute__((target("thumb")))
+foo(int a)
+{
+  return a ? 1 : 5;
+}
+