2014-12-14  Christian Bruel  <christian.bruel@st.com>

	* config/arm/arm.c (arm_option_override_internal): add opts_set param. Use it to set 
	restrict_it. Handle flag_ipa_ra and inline_asm_unified.
	(arm_valid_target_attribute_tree): Add opts_set param.
	Initialize init_optimize.
	(init_optimize): New static variable.
	(thumb_flipper): Set.
	( arm_valid_target_attribute_p): Rewrite.
	config/arm/arm-protos.h	(arm_valid_target_attribute_tree): New opts_set param
	* config/arm/arm-c.c (arm_pragma_target_parse): Likewiese.
	* config/arm/arm.opt (inline_asm_unified): Save.

2014-12-14  Christian Bruel  <christian.bruel@st.com>

        * gcc.target/arm/attr_arm-err.c: Check conflicting -march options.

diff '--exclude=*~' '--exclude=.svn' -ru a/gcc/gcc/config/arm/arm.c b/gcc/gcc/config/arm/arm.c
--- a/gcc/gcc/config/arm/arm.c	2014-12-18 14:36:06.000000000 +0100
+++ b/gcc/gcc/config/arm/arm.c	2014-12-18 14:35:12.000000000 +0100
@@ -2625,9 +2625,16 @@
     }
 }
 
+/* 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;
+
+static GTY(()) tree init_optimize;
+
 /* Reset options between modes that the user has specified.  */
 static void
-arm_option_override_internal (struct gcc_options *opts)
+arm_option_override_internal (struct gcc_options *opts,
+			      struct gcc_options *opts_set)
 {
   if (TREE_TARGET_THUMB (opts) && !(insn_flags & FL_THUMB))
     {
@@ -2646,13 +2653,13 @@
   if (TREE_TARGET_THUMB (opts) && TARGET_CALLEE_INTERWORKING)
     opts->x_target_flags |= MASK_INTERWORK;
 
-  if (restrict_default)
+  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) && opts->x_flag_schedule_insns)
+  if (TREE_TARGET_THUMB1 (opts))
     {
       /* Don't warn since it's on by default in -O2.  */
       opts->x_flag_schedule_insns = 0;
@@ -2663,9 +2670,21 @@
   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);
+  if (TREE_TARGET_THUMB2 (opts))
+      opts->x_inline_asm_unified = 1;
 }
 
 /* Fix up any incompatible options that the user has specified.  */
@@ -3127,27 +3146,17 @@
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
-  /* Override flags, but not the user's one.  */
-  restrict_default = (arm_restrict_it == 2);
-
   /* 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;
+  /* Need to remember initial options before they are overriden
+     for default mode.  */
+  init_optimize = build_optimization_node (&global_options);
 
-  arm_option_override_internal (&global_options);
+  arm_option_override_internal (&global_options, &global_options_set);
   arm_option_check_internal (&global_options);
   arm_option_params_internal (&global_options);
 
@@ -3158,6 +3167,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
@@ -29398,25 +29410,22 @@
 /* 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)
+arm_valid_target_attribute_tree (tree args, struct gcc_options *opts,
+				 struct gcc_options *opts_set)
 {
   tree t = NULL_TREE;
 
   if (!arm_valid_target_attribute_rec (args, opts))
     return NULL_TREE;
 
- t = build_target_option_node (opts);
-
   /* Do any overrides, such as global options arch=xxx.  */
-  arm_option_override_internal (opts);
+  arm_option_override_internal (opts, opts_set);
+
+  t = build_target_option_node (opts);
 
   return t;
 }
 
-/* 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 = TARGET_THUMB;
-
 static void 
 add_attribute  (const char * mode, tree *attributes)
 {
@@ -29438,6 +29447,9 @@
 {
   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;
@@ -29450,9 +29462,6 @@
      return;
    }
 
-  if (! TARGET_FLIP_THUMB)
-    return;
-
   /* If there is already a setting don't change it.  */
   if (lookup_attribute ("target", *attributes) != NULL)
     return;
@@ -29469,17 +29478,18 @@
 arm_valid_target_attribute_p (tree fndecl, tree ARG_UNUSED (name),
 			      tree args, int ARG_UNUSED (flags))
 {
-  tree cur_tree, new_optimize;
+  bool ret = true;
   struct gcc_options func_options;
+  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 = old_optimize;
+    func_optimize = init_optimize;
 
   /* Init func_options.  */
   memset (&func_options, 0, sizeof (func_options));
@@ -29490,26 +29500,20 @@
   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);
+  cur_tree = arm_valid_target_attribute_tree (args, &func_options,
+					      &global_options_set);
 
   if (cur_tree == NULL_TREE)
-    return false;
+    ret = false;
 
   new_optimize = build_optimization_node (&func_options);
 
-  if (fndecl)
-    {
-      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = cur_tree;
+  DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = cur_tree;
 
-      if (old_optimize != new_optimize)
-	DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
-    }
+  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
 
-  return true;
+  return ret;
 }
 
 void
diff '--exclude=*~' '--exclude=.svn' -ru a/gcc/gcc/config/arm/arm-c.c b/gcc/gcc/config/arm/arm-c.c
--- a/gcc/gcc/config/arm/arm-c.c	2014-12-18 14:36:01.000000000 +0100
+++ b/gcc/gcc/config/arm/arm-c.c	2014-12-18 09:02:52.000000000 +0100
@@ -135,7 +135,8 @@
     }
   else
     {
-      cur_tree = arm_valid_target_attribute_tree (args,  &global_options);
+      cur_tree = arm_valid_target_attribute_tree (args,  &global_options,
+						  &global_options_set);
       if (cur_tree == NULL_TREE)
 	{
 	  cl_target_option_restore (&global_options,
diff '--exclude=*~' '--exclude=.svn' -ru a/gcc/gcc/config/arm/arm.opt b/gcc/gcc/config/arm/arm.opt
--- a/gcc/gcc/config/arm/arm.opt	2014-12-18 14:36:06.000000000 +0100
+++ b/gcc/gcc/config/arm/arm.opt	2014-12-18 14:19:16.000000000 +0100
@@ -277,5 +277,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 '--exclude=*~' '--exclude=.svn' -ru a/gcc/gcc/config/arm/arm-protos.h b/gcc/gcc/config/arm/arm-protos.h
--- a/gcc/gcc/config/arm/arm-protos.h	2014-12-18 14:36:01.000000000 +0100
+++ b/gcc/gcc/config/arm/arm-protos.h	2014-12-18 08:57:42.000000000 +0100
@@ -215,7 +215,8 @@
 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 *);
+extern tree arm_valid_target_attribute_tree (tree, struct gcc_options *,
+					     struct gcc_options *);
 #endif
 
 extern void arm_pr_long_calls (struct cpp_reader *);
diff '--exclude=*~' '--exclude=.svn' -ru a/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c b/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c
--- a/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c	2014-12-18 14:35:58.000000000 +0100
+++ b/gcc/gcc/testsuite/gcc.target/arm/attr_arm-err.c	2014-12-18 14:45:10.000000000 +0100
@@ -1,6 +1,7 @@
 /* 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")))
