This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ping: [PATCH, ARM] attribute target (thumb,arm) [0-6]


Hello Ramana

>>
> 
> Can you respin this now that we are in stage1 again ?
> 
> Ramana
> 

Attached the rebased, rechecked set of patches. Original with comments
posted in

https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02455.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02458.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02460.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02461.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02463.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02467.html
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02468.html

many thanks,

Christian
2014-09-23  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm.h (arm_option_override): Reoganized and split.
	(arm_option_params_internal); New function.
	(arm_option_check_internal): New function.
	(arm_option_override_internal): New function.
	(restrict_default): New boolean.
	(thumb_code, thumb1_code): Remove.
	* config/arm/arm.h (TREE_TARGET_THUMB, TREE_TARGET_THUMB1): New macros.
	(TREE_TARGET_THUM2, TREE_TARGET_ARM): Likewise.
	(thumb_code, thumb1_code): Remove.
	* config/arm/arm.md (is_thumb, is_thumb1): Check TARGET flag.

diff -ruN '--exclude=.svn' a/gcc/gcc/config/arm/arm.c a1/gcc/gcc/config/arm/arm.c
--- a/gcc/gcc/config/arm/arm.c	2015-02-04 09:14:26.120602737 +0100
+++ a1/gcc/gcc/config/arm/arm.c	2015-02-05 09:19:32.853338616 +0100
@@ -846,12 +846,6 @@
 /* Nonzero if tuning for Cortex-A9.  */
 int arm_tune_cortex_a9 = 0;
 
-/* Nonzero if generating Thumb instructions.  */
-int thumb_code = 0;
-
-/* Nonzero if generating Thumb-1 instructions.  */
-int thumb1_code = 0;
-
 /* Nonzero if we should define __THUMB_INTERWORK__ in the
    preprocessor.
    XXX This is a bit of a hack, it's intended to help work around
@@ -2623,6 +2617,148 @@
   return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
 }
 
+/* Check any incompatible options that the user has specified.  */
+static void
+arm_option_check_internal (struct gcc_options *opts)
+{
+  /* Make sure that the processor choice does not conflict with any of the
+     other command line choices.  */
+  if (TREE_TARGET_ARM (opts) && !(insn_flags & FL_NOTM))
+    error ("target CPU does not support ARM mode");
+
+  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
+     from here where no function is being compiled currently.  */
+  if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TREE_TARGET_ARM (opts))
+    warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
+
+  if (TREE_TARGET_ARM (opts) && TARGET_CALLEE_INTERWORKING)
+    warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
+
+  /* If this target is normally configured to use APCS frames, warn if they
+     are turned off and debugging is turned on.  */
+  if (TREE_TARGET_ARM (opts)
+      && write_symbols != NO_DEBUG
+      && !TARGET_APCS_FRAME
+      && (TARGET_DEFAULT & MASK_APCS_FRAME))
+    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
+
+  /* iWMMXt unsupported under Thumb mode.  */
+  if (TREE_TARGET_THUMB (opts) && TARGET_IWMMXT)
+    error ("iWMMXt unsupported under Thumb mode");
+
+  if (TARGET_HARD_TP && TREE_TARGET_THUMB1 (opts))
+    error ("can not use -mtp=cp15 with 16-bit Thumb");
+
+  if (TREE_TARGET_THUMB (opts) && TARGET_VXWORKS_RTP && flag_pic)
+    {
+      error ("RTP PIC is incompatible with Thumb");
+      flag_pic = 0;
+    }
+
+  /* We only support -mslow-flash-data on armv7-m targets.  */
+  if (target_slow_flash_data
+      && ((!(arm_arch7 && !arm_arch_notm) && !arm_arch7em)
+	  || (TREE_TARGET_THUMB1 (opts) || flag_pic || TARGET_NEON)))
+    error ("-mslow-flash-data only supports non-pic code on armv7-m targets");
+}
+
+/* Check any params depending on attributes that the user has specified.  */
+static void
+arm_option_params_internal (struct gcc_options *opts)
+{
+ /* If we are not using the default (ARM mode) section anchor offset
+     ranges, then set the correct ranges now.  */
+  if (TREE_TARGET_THUMB1 (opts))
+    {
+      /* Thumb-1 LDR instructions cannot have negative offsets.
+         Permissible positive offset ranges are 5-bit (for byte loads),
+         6-bit (for halfword loads), or 7-bit (for word loads).
+         Empirical results suggest a 7-bit anchor range gives the best
+         overall code size.  */
+      targetm.min_anchor_offset = 0;
+      targetm.max_anchor_offset = 127;
+    }
+  else if (TREE_TARGET_THUMB2 (opts))
+    {
+      /* The minimum is set such that the total size of the block
+         for a particular anchor is 248 + 1 + 4095 bytes, which is
+         divisible by eight, ensuring natural spacing of anchors.  */
+      targetm.min_anchor_offset = -248;
+      targetm.max_anchor_offset = 4095;
+    }
+  else
+    {
+      targetm.min_anchor_offset = TARGET_MIN_ANCHOR_OFFSET;
+      targetm.max_anchor_offset = TARGET_MAX_ANCHOR_OFFSET;
+    }
+
+  if (optimize_size)
+    {
+      /* If optimizing for size, bump the number of instructions that we
+         are prepared to conditionally execute (even on a StrongARM).  */
+      max_insns_skipped = 6;
+
+      /* For THUMB2, we limit the conditional sequence to one IT block.  */
+      if (TREE_TARGET_THUMB2 (opts))
+	max_insns_skipped = opts->x_arm_restrict_it ? 1 : 4;
+    }
+}
+
+/* Reset options between modes that the user has specified.  */
+static void
+arm_option_override_internal (struct gcc_options *opts,
+			      struct gcc_options *opts_set)
+{
+  if (TREE_TARGET_THUMB (opts) && !(insn_flags & FL_THUMB))
+    {
+      warning (0, "target CPU does not support THUMB instructions");
+      opts->x_target_flags &= ~MASK_THUMB;
+    }
+
+  if (TARGET_APCS_FRAME && TREE_TARGET_THUMB (opts))
+    {
+      /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
+      opts->x_target_flags &= ~MASK_APCS_FRAME;
+    }
+
+  /* Callee super interworking implies thumb interworking.  Adding
+     this to the flags here simplifies the logic elsewhere.  */
+  if (TREE_TARGET_THUMB (opts) && TARGET_CALLEE_INTERWORKING)
+    opts->x_target_flags |= MASK_INTERWORK;
+
+  if (! opts_set->x_arm_restrict_it)
+    opts->x_arm_restrict_it = arm_arch8;
+
+  if (!TREE_TARGET_THUMB2 (opts))
+    opts->x_arm_restrict_it = 0;
+
+  if (TREE_TARGET_THUMB1 (opts))
+    {
+      /* Don't warn since it's on by default in -O2.  */
+      opts->x_flag_schedule_insns = 0;
+    }
+
+  /* Disable shrink-wrap when optimizing function for size, since it tends to
+     generate additional returns.  */
+  if (optimize_function_for_size_p (cfun) && TREE_TARGET_THUMB2 (opts))
+    opts->x_flag_shrink_wrap = false;
+
+  /* In Thumb1 mode, we emit the epilogue in RTL, but the last insn
+     - epilogue_insns - does not accurately model the corresponding insns
+     emitted in the asm file.  In particular, see the comment in thumb_exit
+     'Find out how many of the (return) argument registers we can corrupt'.
+     As a consequence, the epilogue may clobber registers without fipa-ra
+     finding out about it.  Therefore, disable fipa-ra in Thumb1 mode.
+     TODO: Accurately model clobbers for epilogue_insns and reenable
+     fipa-ra.  */
+  if (TREE_TARGET_THUMB1 (opts))
+    opts->x_flag_ipa_ra = 0;
+
+  /* Thumb2 inline assembly code should always use unified syntax.
+     This will apply to ARM and Thumb1 eventually.  */
+  opts->x_inline_asm_unified = TREE_TARGET_THUMB2 (opts);
+}
+
 /* Fix up any incompatible options that the user has specified.  */
 static void
 arm_option_override (void)
@@ -2769,10 +2905,9 @@
   tune_flags = arm_selected_tune->flags;
   current_tune = arm_selected_tune->tune;
 
-  /* Make sure that the processor choice does not conflict with any of the
-     other command line choices.  */
-  if (TARGET_ARM && !(insn_flags & FL_NOTM))
-    error ("target CPU does not support ARM mode");
+  /* TBD: Dwarf info for apcs frame is not handled yet.  */
+  if (TARGET_APCS_FRAME)
+    flag_shrink_wrap = false;
 
   /* BPABI targets use linker tricks to allow interworking on cores
      without thumb support.  */
@@ -2782,31 +2917,6 @@
       target_flags &= ~MASK_INTERWORK;
     }
 
-  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
-    {
-      warning (0, "target CPU does not support THUMB instructions");
-      target_flags &= ~MASK_THUMB;
-    }
-
-  if (TARGET_APCS_FRAME && TARGET_THUMB)
-    {
-      /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
-      target_flags &= ~MASK_APCS_FRAME;
-    }
-
-  /* Callee super interworking implies thumb interworking.  Adding
-     this to the flags here simplifies the logic elsewhere.  */
-  if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
-    target_flags |= MASK_INTERWORK;
-
-  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
-     from here where no function is being compiled currently.  */
-  if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
-    warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
-
-  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
-    warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
-
   if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
     {
       warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
@@ -2822,14 +2932,6 @@
   if (TARGET_APCS_REENT)
     warning (0, "APCS reentrant code not supported.  Ignored");
 
-  /* If this target is normally configured to use APCS frames, warn if they
-     are turned off and debugging is turned on.  */
-  if (TARGET_ARM
-      && write_symbols != NO_DEBUG
-      && !TARGET_APCS_FRAME
-      && (TARGET_DEFAULT & MASK_APCS_FRAME))
-    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
-
   if (TARGET_APCS_FLOAT)
     warning (0, "passing floating point arguments in fp regs not yet supported");
 
@@ -2851,8 +2953,6 @@
 
   arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
   arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
-  thumb_code = TARGET_ARM == 0;
-  thumb1_code = TARGET_THUMB1 != 0;
   arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
   arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
   arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
@@ -2862,32 +2962,6 @@
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = (insn_flags & FL_CRC32) != 0;
   arm_m_profile_small_mul = (insn_flags & FL_SMALLMUL) != 0;
-  if (arm_restrict_it == 2)
-    arm_restrict_it = arm_arch8 && TARGET_THUMB2;
-
-  if (!TARGET_THUMB2)
-    arm_restrict_it = 0;
-
-  /* If we are not using the default (ARM mode) section anchor offset
-     ranges, then set the correct ranges now.  */
-  if (TARGET_THUMB1)
-    {
-      /* Thumb-1 LDR instructions cannot have negative offsets.
-         Permissible positive offset ranges are 5-bit (for byte loads),
-         6-bit (for halfword loads), or 7-bit (for word loads).
-         Empirical results suggest a 7-bit anchor range gives the best
-         overall code size.  */
-      targetm.min_anchor_offset = 0;
-      targetm.max_anchor_offset = 127;
-    }
-  else if (TARGET_THUMB2)
-    {
-      /* The minimum is set such that the total size of the block
-         for a particular anchor is 248 + 1 + 4095 bytes, which is
-         divisible by eight, ensuring natural spacing of anchors.  */
-      targetm.min_anchor_offset = -248;
-      targetm.max_anchor_offset = 4095;
-    }
 
   /* V5 code we generate is completely interworking capable, so we turn off
      TARGET_INTERWORK here to avoid many tests later on.  */
@@ -2906,6 +2980,9 @@
   if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
     error ("iwmmxt abi requires an iwmmxt capable cpu");
 
+  if (! optimize_size)
+    max_insns_skipped = current_tune->max_insns_skipped;
+
   if (!global_options_set.x_arm_fpu_index)
     {
       const char *target_fpu_name;
@@ -2947,10 +3024,6 @@
   if (TARGET_IWMMXT && TARGET_NEON)
     error ("iWMMXt and NEON are incompatible");
 
-  /* iWMMXt unsupported under Thumb mode.  */
-  if (TARGET_THUMB && TARGET_IWMMXT)
-    error ("iWMMXt unsupported under Thumb mode");
-
   /* __fp16 support currently assumes the core has ldrh.  */
   if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE)
     sorry ("__fp16 and no ldrh");
@@ -2995,9 +3068,6 @@
 	target_thread_pointer = TP_SOFT;
     }
 
-  if (TARGET_HARD_TP && TARGET_THUMB1)
-    error ("can not use -mtp=cp15 with 16-bit Thumb");
-
   /* Override the default structure alignment for AAPCS ABI.  */
   if (!global_options_set.x_arm_structure_size_boundary)
     {
@@ -3020,12 +3090,6 @@
 	}
     }
 
-  if (!TARGET_ARM && TARGET_VXWORKS_RTP && flag_pic)
-    {
-      error ("RTP PIC is incompatible with Thumb");
-      flag_pic = 0;
-    }
-
   /* If stack checking is disabled, we can use r10 as the PIC register,
      which keeps r9 available.  The EABI specifies r9 as the PIC register.  */
   if (flag_pic && TARGET_SINGLE_PIC_BASE)
@@ -3093,25 +3157,6 @@
       unaligned_access = 0;
     }
 
-  if (TARGET_THUMB1 && flag_schedule_insns)
-    {
-      /* Don't warn since it's on by default in -O2.  */
-      flag_schedule_insns = 0;
-    }
-
-  if (optimize_size)
-    {
-      /* If optimizing for size, bump the number of instructions that we
-         are prepared to conditionally execute (even on a StrongARM).  */
-      max_insns_skipped = 6;
-
-      /* For THUMB2, we limit the conditional sequence to one IT block.  */
-      if (TARGET_THUMB2)
-	max_insns_skipped = MAX_INSN_PER_IT_BLOCK;
-    }
-  else
-    max_insns_skipped = current_tune->max_insns_skipped;
-
   /* Hot/Cold partitioning is not currently supported, since we can't
      handle literal pool placement in that case.  */
   if (flag_reorder_blocks_and_partition)
@@ -3189,45 +3234,19 @@
                          global_options.x_param_values,
                          global_options_set.x_param_values);
 
-  /* Disable shrink-wrap when optimizing function for size, since it tends to
-     generate additional returns.  */
-  if (optimize_function_for_size_p (cfun) && TARGET_THUMB2)
-    flag_shrink_wrap = false;
-  /* TBD: Dwarf info for apcs frame is not handled yet.  */
-  if (TARGET_APCS_FRAME)
-    flag_shrink_wrap = false;
-
-  /* We only support -mslow-flash-data on armv7-m targets.  */
-  if (target_slow_flash_data
-      && ((!(arm_arch7 && !arm_arch_notm) && !arm_arch7em)
-	  || (TARGET_THUMB1 || flag_pic || TARGET_NEON)))
-    error ("-mslow-flash-data only supports non-pic code on armv7-m targets");
-
   /* Currently, for slow flash data, we just disable literal pools.  */
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
-  /* Thumb2 inline assembly code should always use unified syntax.
-     This will apply to ARM and Thumb1 eventually.  */
-  if (TARGET_THUMB2)
-    inline_asm_unified = 1;
-
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
       && (!arm_arch7 || !current_tune->prefer_ldrd_strd))
     flag_schedule_fusion = 0;
 
-  /* In Thumb1 mode, we emit the epilogue in RTL, but the last insn
-     - epilogue_insns - does not accurately model the corresponding insns
-     emitted in the asm file.  In particular, see the comment in thumb_exit
-     'Find out how many of the (return) argument registers we can corrupt'.
-     As a consequence, the epilogue may clobber registers without fipa-ra
-     finding out about it.  Therefore, disable fipa-ra in Thumb1 mode.
-     TODO: Accurately model clobbers for epilogue_insns and reenable
-     fipa-ra.  */
-  if (TARGET_THUMB1)
-    flag_ipa_ra = 0;
+  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 ();
diff -ruN '--exclude=.svn' a/gcc/gcc/config/arm/arm.h a1/gcc/gcc/config/arm/arm.h
--- a/gcc/gcc/config/arm/arm.h	2015-01-20 15:58:49.230503992 +0100
+++ a1/gcc/gcc/config/arm/arm.h	2015-01-22 13:48:29.338437070 +0100
@@ -252,5 +252,12 @@
 #define SUBTARGET_CPP_SPEC      ""
 #endif
 
+/* Tree Target Specification.  */
+#define TREE_TARGET_THUMB(opts)  (TARGET_THUMB_P (opts->x_target_flags))
+#define TREE_TARGET_ARM(opts)    (!TARGET_THUMB_P (opts->x_target_flags))
+#define TREE_TARGET_THUMB1(opts) (TARGET_THUMB_P (opts->x_target_flags) \
+				  && !arm_arch_thumb2)
+#define TREE_TARGET_THUMB2(opts) (TARGET_THUMB_P (opts->x_target_flags) \
+				  && arm_arch_thumb2)
 /* Run-time Target Specification.  */
 #define TARGET_SOFT_FLOAT		(arm_float_abi == ARM_FLOAT_ABI_SOFT)


 /* Use hardware floating point instructions. */
@@ -525,12 +532,6 @@
 /* Nonzero if this chip can benefit from load scheduling.  */
 extern int arm_ld_sched;
 
-/* Nonzero if generating Thumb code, either Thumb-1 or Thumb-2.  */
-extern int thumb_code;
-
-/* Nonzero if generating Thumb-1 code.  */
-extern int thumb1_code;
-
 /* Nonzero if this chip is a StrongARM.  */
 extern int arm_tune_strongarm;
 
diff -ruN '--exclude=.svn' a/gcc/gcc/config/arm/arm.md a1/gcc/gcc/config/arm/arm.md
--- a/gcc/gcc/config/arm/arm.md	2015-01-26 11:04:05.937275841 +0100
+++ a1/gcc/gcc/config/arm/arm.md	2015-02-05 09:19:32.857338621 +0100
@@ -69,13 +69,17 @@
 ; IS_THUMB is set to 'yes' when we are generating Thumb code, and 'no' when
 ; generating ARM code.  This is used to control the length of some insn
 ; patterns that share the same RTL in both ARM and Thumb code.
-(define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code")))
+(define_attr "is_thumb" "yes,no"
+  (const (if_then_else (symbol_ref "TARGET_THUMB")
+		       (const_string "yes") (const_string "no"))))
 
 ; IS_ARCH6 is set to 'yes' when we are generating code form ARMv6.
 (define_attr "is_arch6" "no,yes" (const (symbol_ref "arm_arch6")))
 
 ; IS_THUMB1 is set to 'yes' iff we are generating Thumb-1 code.
-(define_attr "is_thumb1" "no,yes" (const (symbol_ref "thumb1_code")))
+(define_attr "is_thumb1" "yes,no"
+  (const (if_then_else (symbol_ref "TARGET_THUMB1")
+		       (const_string "yes") (const_string "no"))))
 
 ; We use this attribute to disable alternatives that can produce 32-bit
 ; instructions inside an IT-block in Thumb2 state.  ARMv8 deprecates IT blocks
Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm-c.c (cpp_def_or_undef): New functions.
	(arm_cpp_builtins): Likewise.
	* config/arm/arm.h (TARGET_CPU_CPP_BUILTINS): Move mode dependant 
	macros to arm_cpp_builtins.
	* config/arm/arm-protos.h (arm_cpp_builtins): Declare.

diff -ruN '--exclude=.svn' a1/gcc/gcc/config/arm/arm-c.c a2/gcc/gcc/config/arm/arm-c.c
--- a1/gcc/gcc/config/arm/arm-c.c	2015-01-13 12:34:38.910459998 +0100
+++ a2/gcc/gcc/config/arm/arm-c.c	2015-01-15 13:32:30.683013516 +0100
@@ -51,3 +51,73 @@
 {
   arm_lang_output_object_attributes_hook = arm_output_c_attributes;
 }
+
+/* Define or undefine macro.  */
+
+static void
+cpp_def_or_undef (struct cpp_reader *in, const char *str, bool def_p)
+{
+  if (def_p)
+    cpp_define (in, str);
+  else
+    cpp_undef (in, str);
+}
+
+/* Define or undefine macros based on the current target.  If the user does
+   #pragma GCC target, we need to adjust the macros dynamically.  */
+
+void
+arm_cpp_builtins (struct cpp_reader *in, bool thumb_p)
+{
+  bool target_32bit_p = !thumb_p || arm_arch_thumb2;
+  bool thumb2_p = thumb_p && arm_arch_thumb2;
+  bool have_ldrex_p = (arm_arch6 && !thumb_p) || arm_arch7;
+  bool have_ldrexbh_p = (arm_arch6k && !thumb_p) || arm_arch7;
+  bool have_ldrexd_p = ((arm_arch6k && !thumb_p) || arm_arch7)
+    && arm_arch_notm;
+
+  int arm_feature_ldrex = (have_ldrex_p ? 4 : 0)
+    | (have_ldrexbh_p ? 3 : 0) | (have_ldrexd_p ? 8 : 0);
+
+  cpp_def_or_undef (in, "__thumb__", thumb_p);
+  if (arm_arch_thumb2)
+    cpp_def_or_undef (in, "__thumb2__", thumb_p);
+  if (TARGET_BIG_END)
+    cpp_def_or_undef (in, "__THUMBEB__", thumb_p);
+  else
+    cpp_def_or_undef (in, "__THUMBEL__", thumb_p);
+
+  cpp_def_or_undef (in, "__ARM_32BIT_STATE", target_32bit_p); /* TARGET_32BIT  */
+
+  if (arm_arch5e && (arm_arch_notm || arm_arch7))   /* TARGET_ARM_QBIT  */
+    cpp_def_or_undef (in, "__ARM_FEATURE_QBIT", target_32bit_p);
+
+  if (arm_arch6 && (arm_arch_notm || arm_arch7))    /* TARGET_ARM_SAT  */
+    cpp_def_or_undef (in, "__ARM_FEATURE_SAT", target_32bit_p);
+
+  if (arm_arch5e && (arm_arch_notm || arm_arch7em)) /* TARGET_DSP_MULTIPLY  */
+    cpp_def_or_undef (in, "__ARM_FEATURE_DSP", target_32bit_p);
+
+  if (arm_arch6 && (arm_arch_notm || arm_arch7em))  /* TARGET_INT_SIMD  */
+    cpp_def_or_undef (in, "__ARM_FEATURE_SIMD32", target_32bit_p);
+
+ /* TARGET_IDIV  */
+  cpp_def_or_undef (in, "__ARM_ARCH_EXT_IDIV__",
+		    ((!thumb_p && arm_arch_arm_hwdiv)
+		     || (thumb2_p && arm_arch_thumb_hwdiv)));
+
+  cpp_def_or_undef (in, "__ARM_FEATURE_IDIV",
+		    ((!thumb_p && arm_arch_arm_hwdiv)
+		     || (thumb2_p && arm_arch_thumb_hwdiv)));
+
+ if (arm_feature_ldrex)
+   cpp_define_formatted (in, "__ARM_FEATURE_LDREX=%d", arm_feature_ldrex);
+ else
+   cpp_undef (in, "__ARM_FEATURE_LDREX");
+
+ cpp_def_or_undef (in, "__ARM_FEATURE_CLZ",
+		   ((TARGET_ARM_ARCH >= 5 && !thumb_p) || TARGET_ARM_ARCH_ISA_THUMB >=2));
+
+ cpp_def_or_undef (in, "__ARM_ASM_SYNTAX_UNIFIED__", inline_asm_unified);
+}
+
diff -ruN '--exclude=.svn' a1/gcc/gcc/config/arm/arm.h a2/gcc/gcc/config/arm/arm.h
--- a1/gcc/gcc/config/arm/arm.h	2015-01-22 13:48:29.338437070 +0100
+++ a2/gcc/gcc/config/arm/arm.h	2015-01-22 13:52:58.062879846 +0100
@@ -48,29 +48,12 @@
 #define TARGET_CPU_CPP_BUILTINS()			\
   do							\
     {							\
-	if (TARGET_DSP_MULTIPLY)			\
-	   builtin_define ("__ARM_FEATURE_DSP");	\
-        if (TARGET_ARM_QBIT)				\
-           builtin_define ("__ARM_FEATURE_QBIT");	\
-        if (TARGET_ARM_SAT)				\
-           builtin_define ("__ARM_FEATURE_SAT");	\
         if (TARGET_CRYPTO)				\
 	   builtin_define ("__ARM_FEATURE_CRYPTO");	\
 	if (unaligned_access)				\
 	  builtin_define ("__ARM_FEATURE_UNALIGNED");	\
 	if (TARGET_CRC32)				\
 	  builtin_define ("__ARM_FEATURE_CRC32");	\
-	if (TARGET_32BIT)				\
-	  builtin_define ("__ARM_32BIT_STATE");		\
-	if (TARGET_ARM_FEATURE_LDREX)				\
-	  builtin_define_with_int_value (			\
-	    "__ARM_FEATURE_LDREX", TARGET_ARM_FEATURE_LDREX);	\
-	if ((TARGET_ARM_ARCH >= 5 && !TARGET_THUMB)		\
-	     || TARGET_ARM_ARCH_ISA_THUMB >=2)			\
-	  builtin_define ("__ARM_FEATURE_CLZ");			\
-	if (TARGET_INT_SIMD)					\
-	  builtin_define ("__ARM_FEATURE_SIMD32");		\
-								\
 	builtin_define_with_int_value (				\
 	  "__ARM_SIZEOF_MINIMAL_ENUM",				\
 	  flag_short_enums ? 1 : 4);				\
@@ -89,10 +72,6 @@
 	if (arm_arch_notm)				\
 	  builtin_define ("__ARM_ARCH_ISA_ARM");	\
 	builtin_define ("__APCS_32__");			\
-	if (TARGET_THUMB)				\
-	  builtin_define ("__thumb__");			\
-	if (TARGET_THUMB2)				\
-	  builtin_define ("__thumb2__");		\
 	if (TARGET_ARM_ARCH_ISA_THUMB)			\
 	  builtin_define_with_int_value (		\
 	    "__ARM_ARCH_ISA_THUMB",			\
@@ -102,15 +81,9 @@
 	  {						\
 	    builtin_define ("__ARMEB__");		\
 	    builtin_define ("__ARM_BIG_ENDIAN");	\
-	    if (TARGET_THUMB)				\
-	      builtin_define ("__THUMBEB__");		\
 	  }						\
         else						\
-	  {						\
 	    builtin_define ("__ARMEL__");		\
-	    if (TARGET_THUMB)				\
-	      builtin_define ("__THUMBEL__");		\
-	  }						\
 							\
 	if (TARGET_SOFT_FLOAT)				\
 	  builtin_define ("__SOFTFP__");		\
@@ -163,13 +136,8 @@
 	      builtin_define ("__ARM_PCS");		\
 	    builtin_define ("__ARM_EABI__");		\
 	  }						\
-	if (TARGET_IDIV)				\
-         {						\
-            builtin_define ("__ARM_ARCH_EXT_IDIV__");	\
-            builtin_define ("__ARM_FEATURE_IDIV");	\
-         }						\
-	if (inline_asm_unified)				\
-	  builtin_define ("__ARM_ASM_SYNTAX_UNIFIED__");\
+	/* Remaining macros depends on TARGET_THUMB.  */\
+        arm_cpp_builtins (pfile, TARGET_THUMB);		\
     } while (0)
 
 #include "config/arm/arm-opts.h"
diff -ruN '--exclude=.svn' a1/gcc/gcc/config/arm/arm-protos.h a2/gcc/gcc/config/arm/arm-protos.h
--- a1/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:48:29.342437077 +0100
+++ a2/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:52:58.098879905 +0100
@@ -222,8 +222,6 @@
 extern void arm_pr_no_long_calls (struct cpp_reader *);
 extern void arm_pr_long_calls_off (struct cpp_reader *);
 
-extern void arm_lang_object_attributes_init(void);
-
 extern const char *arm_mangle_type (const_tree);
 extern const char *arm_mangle_builtin_type (const_tree);
 
@@ -323,6 +321,10 @@
 /* Defined in gcc/common/config/arm-common.c.  */
 extern const char *arm_rewrite_selected_cpu (const char *name);
 
+/* Defined in gcc/common/config/arm-c.c.  */
+extern void arm_lang_object_attributes_init(void);
+extern void arm_cpp_builtins (struct cpp_reader *, bool);
+
 extern bool arm_is_constant_pool_ref (rtx);
 
 /* Flags used to identify the presence of processor capabilities.  */
2014-09-23  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm-protos.h (arm_declare_function_name): Declare.
	(is_called_in_ARM_mode): Remove.
	* config/arm/arm.c (is_called_in_ARM_mode): Declare static bool.
	(arm_declare_function_name): Moved from from ARM_DECLARE_FUNCTION_NAME.
	* config/arm/arm.h (ARM_DECLARE_FUNCTION_NAME): Call
	 arm_declare_function_name.

diff -ruN '--exclude=.svn' a2/gcc/gcc/config/arm/arm.c a3/gcc/gcc/config/arm/arm.c
--- a2/gcc/gcc/config/arm/arm.c	2015-02-05 09:20:13.225397216 +0100
+++ a3/gcc/gcc/config/arm/arm.c	2015-02-05 09:20:12.653396291 +0100
@@ -23645,6 +23645,23 @@
   fprintf (f, "}\n");
 }
 
+/* Return nonzero if FUNC must be entered in ARM mode.  */
+static bool
+is_called_in_ARM_mode (tree func)
+{
+  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
+
+  /* Ignore the problem about functions whose address is taken.  */
+  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
+    return true;
+
+#ifdef ARM_PE
+  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
+#else
+  return false;
+#endif
+}
+
 /* Generate code to return from a thumb function.
    If 'reg_containing_return_addr' is -1, then the return address is
    actually on the stack, at the stack pointer.  */
@@ -24080,22 +24097,6 @@
   return 0;
 }
 
-/* Return nonzero if FUNC must be entered in ARM mode.  */
-int
-is_called_in_ARM_mode (tree func)
-{
-  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
-
-  /* Ignore the problem about functions whose address is taken.  */
-  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
-    return TRUE;
-
-#ifdef ARM_PE
-  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
-#else
-  return FALSE;
-#endif
-}
 
 /* Given the stack offsets and register mask in OFFSETS, decide how
    many additional registers to push instead of subtracting a constant
@@ -29435,6 +29436,25 @@
 	  && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
 }
 
+void
+arm_declare_function_name (FILE *stream, const char *name, tree decl)
+{
+  if (TARGET_THUMB)
+    {
+      if (is_called_in_ARM_mode (decl)
+	  || (TARGET_THUMB1 && !TARGET_THUMB1_ONLY
+	      && cfun->is_thunk))
+	fprintf (stream, "\t.code 32\n");
+      else if (TARGET_THUMB1)
+	fprintf (stream, "\t.code\t16\n\t.thumb_func\n");
+      else
+	fprintf (stream, "\t.thumb\n\t.thumb_func\n");
+    }
+
+  if (TARGET_POKE_FUNCTION_NAME)
+    arm_poke_function_name (stream, (const char *) name);
+}
+
 /* If MEM is in the form of [base+offset], extract the two parts
    of address and set to BASE and OFFSET, otherwise return false
    after clearing BASE and OFFSET.  */
@@ -29555,4 +29575,5 @@
   *pri = tmp;
   return;
 }
+
 #include "gt-arm.h"
diff -ruN '--exclude=.svn' a2/gcc/gcc/config/arm/arm.h a3/gcc/gcc/config/arm/arm.h
--- a2/gcc/gcc/config/arm/arm.h	2015-01-22 13:52:58.062879846 +0100
+++ a3/gcc/gcc/config/arm/arm.h	2015-01-22 13:53:11.218901428 +0100
@@ -2185,23 +2185,7 @@
    ? 1 : 0)
 
 #define ARM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) 	\
-  do							\
-    {							\
-      if (TARGET_THUMB) 				\
-        {						\
-          if (is_called_in_ARM_mode (DECL)		\
-	      || (TARGET_THUMB1 && !TARGET_THUMB1_ONLY	\
-		  && cfun->is_thunk))	\
-            fprintf (STREAM, "\t.code 32\n") ;		\
-          else if (TARGET_THUMB1)			\
-           fprintf (STREAM, "\t.code\t16\n\t.thumb_func\n") ;	\
-          else						\
-           fprintf (STREAM, "\t.thumb\n\t.thumb_func\n") ;	\
-        }						\
-      if (TARGET_POKE_FUNCTION_NAME)			\
-        arm_poke_function_name (STREAM, (const char *) NAME);	\
-    }							\
-  while (0)
+  arm_declare_function_name ((STREAM), (NAME), (DECL));
 
 /* For aliases of functions we use .thumb_set instead.  */
 #define ASM_OUTPUT_DEF_FROM_DECLS(FILE, DECL1, DECL2)		\
diff -ruN '--exclude=.svn' a2/gcc/gcc/config/arm/arm-protos.h a3/gcc/gcc/config/arm/arm-protos.h
--- a2/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:52:58.098879905 +0100
+++ a3/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:53:11.222901435 +0100
@@ -30,6 +30,7 @@
 extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
+extern void arm_declare_function_name (FILE *, const char *, tree);
 extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
@@ -185,9 +186,6 @@
 extern void thumb1_expand_prologue (void);
 extern void thumb1_expand_epilogue (void);
 extern const char *thumb1_output_interwork (void);
-#ifdef TREE_CODE
-extern int is_called_in_ARM_mode (tree);
-#endif
 extern int thumb_shiftable_const (unsigned HOST_WIDE_INT);
 #ifdef RTX_CODE
 extern enum arm_cond_code maybe_get_arm_condition_code (rtx);
2014-09-23  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm.opt (THUMB, arm_restrict_it, inline_asm_unified): Save.
	* config/arm/arm.h (arm_valid_target_attribute_tree): Declare.
	(arm_reset_previous_fndecl, arm_change_mode_p): Likewise.
	(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 target and pragma attribute.
	* doc/invoke.texi: Likewise.

diff -ruN '--exclude=.svn' a3/gcc/gcc/config/arm/arm.c a4/gcc/gcc/config/arm/arm.c
--- a3/gcc/gcc/config/arm/arm.c	2015-02-05 09:20:12.653396291 +0100
+++ a4/gcc/gcc/config/arm/arm.c	2015-02-05 09:20:12.193395549 +0100
@@ -94,6 +94,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"
@@ -264,6 +265,9 @@
 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 *);
@@ -412,6 +416,9 @@
 #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
 
@@ -430,6 +437,12 @@
 #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
 
@@ -2704,6 +2717,9 @@
     }
 }
 
+/* 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,
@@ -2726,6 +2742,10 @@
   if (TREE_TARGET_THUMB (opts) && 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;
 
@@ -2733,15 +2753,17 @@
     opts->x_arm_restrict_it = 0;
 
   if (TREE_TARGET_THUMB1 (opts))
-    {
-      /* Don't warn since it's on by default in -O2.  */
-      opts->x_flag_schedule_insns = 0;
-    }
+    /* Don't warn since it's on by default in -O2.  */
+    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) && TREE_TARGET_THUMB2 (opts))
     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
@@ -2753,6 +2775,8 @@
      fipa-ra.  */
   if (TREE_TARGET_THUMB1 (opts))
     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.  */
@@ -3244,12 +3268,20 @@
       && (!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
@@ -3403,13 +3435,20 @@
 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",
@@ -24097,6 +24136,23 @@
   return 0;
 }
 
+/* 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);
+
+  return (TREE_TARGET_THUMB (callee_opts) != TARGET_THUMB);
+}
 
 /* Given the stack offsets and register mask in OFFSETS, decide how
    many additional registers to push instead of subtracting a constant
@@ -25659,9 +25715,6 @@
 {
   int val;
 
-  if (TARGET_UNIFIED_ASM)
-    asm_fprintf (asm_out_file, "\t.syntax unified\n");
-
   if (TARGET_BPABI)
     {
       const char *fpu_name;
@@ -29436,9 +29489,196 @@
 	  && 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 (!strncmp (argstr, "thumb", 5))
+	{
+	  opts->x_target_flags |= MASK_THUMB;
+	  arm_option_check_internal (opts);
+	  return true;
+	}
+
+      if (!strncmp (argstr, "arm", 3))
+	{
+	  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)
@@ -29450,6 +29690,8 @@
       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);
diff -ruN '--exclude=.svn' a3/gcc/gcc/config/arm/arm.h a4/gcc/gcc/config/arm/arm.h
--- a3/gcc/gcc/config/arm/arm.h	2015-01-22 13:53:11.218901428 +0100
+++ a4/gcc/gcc/config/arm/arm.h	2015-01-22 13:56:30.235226925 +0100
@@ -2360,4 +2360,8 @@
 
 #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 */
diff -ruN '--exclude=.svn' a3/gcc/gcc/config/arm/arm.md a4/gcc/gcc/config/arm/arm.md
--- a3/gcc/gcc/config/arm/arm.md	2015-02-05 09:20:12.657396298 +0100
+++ a4/gcc/gcc/config/arm/arm.md	2015-02-05 09:20:12.233395613 +0100
@@ -7722,6 +7722,13 @@
    && !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")]
@@ -7739,6 +7746,13 @@
    && !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")]
diff -ruN '--exclude=.svn' a3/gcc/gcc/config/arm/arm.opt a4/gcc/gcc/config/arm/arm.opt
--- a3/gcc/gcc/config/arm/arm.opt	2015-01-22 13:53:11.222901435 +0100
+++ a4/gcc/gcc/config/arm/arm.opt	2015-02-09 12:34:43.188559954 +0100
@@ -182,7 +182,7 @@
 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
@@ -240,7 +240,7 @@
 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
@@ -269,5 +269,5 @@
 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.
diff -ruN '--exclude=.svn' a3/gcc/gcc/config/arm/arm-protos.h a4/gcc/gcc/config/arm/arm-protos.h
--- a3/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:53:11.222901435 +0100
+++ a4/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:56:30.239226931 +0100
@@ -214,6 +214,9 @@
 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 *);
@@ -316,6 +319,8 @@
 
 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);
 
diff -ruN '--exclude=.svn' a3/gcc/gcc/doc/extend.texi a4/gcc/gcc/doc/extend.texi
--- a3/gcc/gcc/doc/extend.texi	2015-02-05 09:18:12.909233395 +0100
+++ a4/gcc/gcc/doc/extend.texi	2015-02-05 09:21:38.749534626 +0100
@@ -3996,10 +3996,25 @@
 strings to specify multiple options, or separate the options
 with a comma (@samp{,}).
 
-The @code{target} attribute is presently implemented for
-x86, PowerPC, and Nios II targets only.
+The @code{target} attribute is implemented for
+ARM, x86, PowerPC, and Nios II targets.
+
 The options supported are specific to each target.
 
+for ARM, the following options are allowed:
+
+@table @samp
+@item thumb
+@cindex @code{target("thumb")} attribute
+Force Thumb1 Thumb2 code generation depending on the architecture.
+
+@item arm
+@cindex @code{target("arm")} attribute
+Force ARM code generation.
+@end table
+
+Functions from different modes can be inlined , unless the callee has asm statements.
+
 On the x86, the following options are allowed:
 
 @table @samp
@@ -17795,8 +17810,9 @@
 @xref{Function Attributes}, for more information about the
 @code{target} attribute and the attribute syntax.
 
-The @code{#pragma GCC target} pragma is presently implemented for
-x86, PowerPC, and Nios II targets only.
+The @code{#pragma GCC target} pragma is implemented for
+ARM, x86, PowerPC, and Nios II targets.
+
 @end table
 
 @table @code
diff -ruN '--exclude=.svn' a3/gcc/gcc/doc/invoke.texi a4/gcc/gcc/doc/invoke.texi
--- a3/gcc/gcc/doc/invoke.texi	2015-02-05 09:18:12.913233401 +0100
+++ a4/gcc/gcc/doc/invoke.texi	2015-02-05 09:18:24.465248626 +0100
@@ -13149,6 +13149,10 @@
 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{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
diff -ruN '--exclude=.svn' a3/gcc/gcc/testsuite/gcc.target/arm/attr_arm.c a4/gcc/gcc/testsuite/gcc.target/arm/attr_arm.c
--- a3/gcc/gcc/testsuite/gcc.target/arm/attr_arm.c	1970-01-01 01:00:00.000000000 +0100
+++ a4/gcc/gcc/testsuite/gcc.target/arm/attr_arm.c	2015-01-15 13:35:12.135273352 +0100
@@ -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 -ruN '--exclude=.svn' a3/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c a4/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c
--- a3/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c	1970-01-01 01:00:00.000000000 +0100
+++ a4/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c	2015-01-15 13:35:12.139273358 +0100
@@ -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 -ruN '--exclude=.svn' a3/gcc/gcc/testsuite/gcc.target/arm/attr_thumb.c a4/gcc/gcc/testsuite/gcc.target/arm/attr_thumb.c
--- a3/gcc/gcc/testsuite/gcc.target/arm/attr_thumb.c	1970-01-01 01:00:00.000000000 +0100
+++ a4/gcc/gcc/testsuite/gcc.target/arm/attr_thumb.c	2015-01-15 13:35:12.139273358 +0100
@@ -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;
+}
+
diff -ruN '--exclude=.svn' a3/gcc/gcc/testsuite/gcc.target/arm/attr_thumb-static.c a4/gcc/gcc/testsuite/gcc.target/arm/attr_thumb-static.c
--- a3/gcc/gcc/testsuite/gcc.target/arm/attr_thumb-static.c	1970-01-01 01:00:00.000000000 +0100
+++ a4/gcc/gcc/testsuite/gcc.target/arm/attr_thumb-static.c	2015-01-15 13:35:12.139273358 +0100
@@ -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();
+}
2014-09-23  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm.h (REGISTER_TARGET_PRAGMAS):
	 Call arm_register_target_pragmas.
	* config/arm/arm-protos.h (arm_register_target_pragmas): Declare.
	* config/arm/arm-c.c (arm_register_target_pragmas): New function.
	(arm_pragma_target_parse): Likewise.

diff -ruN '--exclude=.svn' a4/gcc/gcc/config/arm/arm-c.c a5/gcc/gcc/config/arm/arm-c.c
--- a4/gcc/gcc/config/arm/arm-c.c	2015-01-15 13:35:07.195265398 +0100
+++ a5/gcc/gcc/config/arm/arm-c.c	2015-01-15 13:36:28.935397056 +0100
@@ -20,7 +20,6 @@
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "tm_p.h"
 #include "hash-set.h"
 #include "machmode.h"
 #include "vec.h"
@@ -31,7 +30,11 @@
 #include "wide-int.h"
 #include "inchash.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "c-family/c-common.h"
+#include "target.h"
+#include "target-def.h"
+#include "c-family/c-pragma.h"
 
 /* Output C specific EABI object attributes.  These can not be done in
    arm.c because they require information from the C frontend.  */
@@ -121,3 +124,79 @@
  cpp_def_or_undef (in, "__ARM_ASM_SYNTAX_UNIFIED__", inline_asm_unified);
 }
 
+/* Hook to validate the current #pragma GCC target and set the arch custom
+   mode state.  If ARGS is NULL, then POP_TARGET is used to reset
+   the options.  */
+static bool
+arm_pragma_target_parse (tree args, tree pop_target)
+{
+  tree prev_tree = build_target_option_node (&global_options);
+  tree cur_tree;
+  struct cl_target_option *prev_opt;
+  struct cl_target_option *cur_opt;
+  bool cur_mode, prev_mode;
+
+  if (! args)
+    {
+      cur_tree = ((pop_target) ? pop_target : target_option_default_node);
+      cl_target_option_restore (&global_options,
+				TREE_TARGET_OPTION (cur_tree));
+    }
+  else
+    {
+      cur_tree = arm_valid_target_attribute_tree (args, &global_options,
+						  &global_options_set);
+      if (cur_tree == NULL_TREE)
+	{
+	  cl_target_option_restore (&global_options,
+				    TREE_TARGET_OPTION (prev_tree));
+	  return false;
+	}
+    }
+
+  target_option_current_node = cur_tree;
+  arm_reset_previous_fndecl ();
+
+  /* Figure out the previous mode.  */
+  prev_opt  = TREE_TARGET_OPTION (prev_tree);
+  cur_opt   = TREE_TARGET_OPTION (cur_tree);
+
+  gcc_assert (prev_opt);
+  gcc_assert (cur_opt);
+
+  cur_mode = TARGET_THUMB_P (cur_opt->x_target_flags);
+  prev_mode = TARGET_THUMB_P (prev_opt->x_target_flags);
+
+  if (prev_mode != cur_mode)
+    {
+      /* For the definitions, ensure all newly defined macros are considered
+	 as used for -Wunused-macros.  There is no point warning about the
+	 compiler predefined macros.  */
+      cpp_options *cpp_opts = cpp_get_options (parse_in);
+      unsigned char saved_warn_unused_macros = cpp_opts->warn_unused_macros;
+      cpp_opts->warn_unused_macros = 0;
+
+      /* Update macros.  */
+      arm_cpp_builtins (parse_in, cur_mode);
+
+      cpp_opts->warn_unused_macros = saved_warn_unused_macros;
+    }
+
+  return true;
+}
+
+/* Register target pragmas.  We need to add the hook for parsing #pragma GCC
+   option here rather than in arm.c since it will pull in various preprocessor
+   functions, and those are not present in languages like fortran without a
+   preprocessor.  */
+
+void
+arm_register_target_pragmas (void)
+{
+  /* Update pragma hook to allow parsing #pragma GCC target.  */
+  targetm.target_option.pragma_parse = arm_pragma_target_parse;
+
+#ifdef REGISTER_SUBTARGET_PRAGMAS
+  REGISTER_SUBTARGET_PRAGMAS ();
+#endif
+}
diff -ruN '--exclude=.svn' a4/gcc/gcc/config/arm/arm.h a5/gcc/gcc/config/arm/arm.h
--- a4/gcc/gcc/config/arm/arm.h	2015-01-22 13:56:30.235226925 +0100
+++ a5/gcc/gcc/config/arm/arm.h	2015-01-22 13:56:45.251251411 +0100
@@ -2098,7 +2098,8 @@
   c_register_pragma (0, "long_calls", arm_pr_long_calls);		\
   c_register_pragma (0, "no_long_calls", arm_pr_no_long_calls);		\
   c_register_pragma (0, "long_calls_off", arm_pr_long_calls_off);	\
-  arm_lang_object_attributes_init(); \
+  arm_lang_object_attributes_init();					\
+  arm_register_target_pragmas();                                       \
 } while (0)
 
 /* Condition code information.  */
diff -ruN '--exclude=.svn' a4/gcc/gcc/config/arm/arm-protos.h a5/gcc/gcc/config/arm/arm-protos.h
--- a4/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:56:30.239226931 +0100
+++ a5/gcc/gcc/config/arm/arm-protos.h	2015-01-22 13:56:45.255251418 +0100
@@ -326,6 +326,7 @@
 
 /* Defined in gcc/common/config/arm-c.c.  */
 extern void arm_lang_object_attributes_init(void);
+extern void arm_register_target_pragmas (void);
 extern void arm_cpp_builtins (struct cpp_reader *, bool);
 
 extern bool arm_is_constant_pool_ref (rtx);
diff -ruN '--exclude=.svn' a4/gcc/gcc/testsuite/gcc.target/arm/pragma_attribute.c a5/gcc/gcc/testsuite/gcc.target/arm/pragma_attribute.c
--- a4/gcc/gcc/testsuite/gcc.target/arm/pragma_attribute.c	1970-01-01 01:00:00.000000000 +0100
+++ a5/gcc/gcc/testsuite/gcc.target/arm/pragma_attribute.c	2015-01-15 13:36:28.935397056 +0100
@@ -0,0 +1,35 @@
+/* Test for #prama target macros.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+
+#pragma GCC target ("thumb")
+
+#ifndef __thumb__
+#error "__thumb__ is not defined"
+#endif
+
+#ifdef __thumb2__
+#ifndef __ARM_32BIT_STATE
+#error  "__ARM_32BIT_STATE is not defined"
+#endif
+#else /* thumb1 */
+#ifdef __ARM_32BIT_STATE
+#error  "__ARM_32BIT_STATE is defined"
+#endif
+#endif /* thumb1 */
+
+#pragma GCC target ("arm")
+
+#ifdef __thumb__
+#error "__thumb__ is defined"
+#endif
+
+#if defined (__thumb2__) || defined (__thumb1__)
+#error "thumb is defined"
+#endif 
+
+#ifndef __ARM_32BIT_STATE
+#error  "__ARM_32BIT_STATE is not defined"
+#endif
+
+#pragma GCC reset_options
2014-09-23  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm.c (add_attribute, arm_insert_attributes): New functions
	(TARGET_INSERT_ATTRIBUTES): Define.
	(thumb_flipper): New var.
	* config/arm/arm.opt (-mflip-thumb): New switch.

diff -ruN '--exclude=.svn' gnu_trunk.devs5/gcc/gcc/config/arm/arm.c gnu_trunk.devs6/gcc/gcc/config/arm/arm.c
--- gnu_trunk.devs5/gcc/gcc/config/arm/arm.c	2015-02-05 09:21:44.449543733 +0100
+++ gnu_trunk.devs6/gcc/gcc/config/arm/arm.c	2015-02-05 09:21:56.821563455 +0100
@@ -99,6 +99,7 @@
 #include "tm-constrs.h"
 #include "rtl-iter.h"
 #include "sched-int.h"
+#include "tree.h"
 
 /* Forward definitions of types.  */
 typedef struct minipool_node    Mnode;
@@ -232,6 +233,7 @@
 
 static void arm_file_end (void);
 static void arm_file_start (void);
+static void arm_insert_attributes (tree, tree *);
 
 static void arm_setup_incoming_varargs (cumulative_args_t, machine_mode,
 					tree, int *, int);
@@ -390,6 +392,9 @@
 #undef  TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
 
+#undef  TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES arm_insert_attributes
+
 #undef TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START arm_file_start
 #undef TARGET_ASM_FILE_END
@@ -2717,6 +2722,10 @@
     }
 }
 
+/* True if -mflip-thumb should next add an attribute for the default
+   mode, false if it should next add an attribute for the opposite mode.  */
+static GTY(()) bool thumb_flipper;
+
 /* Options after initial target override.  */
 static GTY(()) tree init_optimize;
 
@@ -3282,6 +3291,9 @@
      options.  */
   target_option_default_node = target_option_current_node
     = build_target_option_node (&global_options);
+
+  /* Init initial mode for testing.  */
+  thumb_flipper = TARGET_THUMB;
 }
 
 static void
@@ -29624,6 +29636,52 @@
   return build_target_option_node (opts);
 }
 
+static void 
+add_attribute  (const char * mode, tree *attributes)
+{
+  size_t len = strlen (mode);
+  tree value = build_string (len, mode);
+
+  TREE_TYPE (value) = build_array_type (char_type_node,
+					build_index_type (size_int (len)));
+
+  *attributes = tree_cons (get_identifier ("target"),
+			   build_tree_list (NULL_TREE, value),
+			   *attributes);
+}
+
+/* For testing. Insert thumb or arm modes alternatively on functions.  */
+
+static void
+arm_insert_attributes (tree fndecl, tree * attributes)
+{
+  const char *mode;
+
+  if (! TARGET_FLIP_THUMB)
+    return;
+
+  if (TREE_CODE (fndecl) != FUNCTION_DECL || DECL_EXTERNAL(fndecl)
+      || DECL_BUILT_IN (fndecl) || DECL_ARTIFICIAL (fndecl))
+   return;
+
+  /* Nested definitions must inherit mode.  */
+  if (current_function_decl)
+   {
+     mode = TARGET_THUMB ? "thumb" : "arm";      
+     add_attribute (mode, attributes);
+     return;
+   }
+
+  /* If there is already a setting don't change it.  */
+  if (lookup_attribute ("target", *attributes) != NULL)
+    return;
+
+  mode = thumb_flipper ? "thumb" : "arm";
+  add_attribute (mode, attributes);
+
+  thumb_flipper = !thumb_flipper;
+}
+
 /* Hook to validate attribute((target("string"))).  */
 
 static bool
@@ -29635,13 +29693,15 @@
   tree cur_tree, new_optimize;
   gcc_assert ((fndecl != NULL_TREE) && (args != NULL_TREE));
 
+  tree old_optimize = build_optimization_node (&global_options);
+
   /* 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;
+    func_optimize = old_optimize;
 
   /* Init func_options.  */
   memset (&func_options, 0, sizeof (func_options));
@@ -29659,14 +29719,17 @@
   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;
+  if (cur_tree == NULL_TREE)
+    ret = false;
+  else
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = cur_tree;
 
-  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+      if (old_optimize != new_optimize)
+	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+    }
 
   return ret;
 }
diff -ruN '--exclude=.svn' gnu_trunk.devs5/gcc/gcc/config/arm/arm.opt gnu_trunk.devs6/gcc/gcc/config/arm/arm.opt
--- gnu_trunk.devs5/gcc/gcc/config/arm/arm.opt	2015-01-22 13:56:45.255251418 +0100
+++ gnu_trunk.devs6/gcc/gcc/config/arm/arm.opt	2015-01-21 18:18:16.166984018 +0100
@@ -122,6 +122,10 @@
 EnumValue
 Enum(float_abi_type) String(hard) Value(ARM_FLOAT_ABI_HARD)
 
+mflip-thumb
+Target Report Var(TARGET_FLIP_THUMB)
+Switch ARM/Thumb modes on alternating functions for compiler testing
+
 mfp16-format=
 Target RejectNegative Joined Enum(arm_fp16_format_type) Var(arm_fp16_format) Init(ARM_FP16_FORMAT_NONE)
 Specify the __fp16 floating-point format

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]