diff mbox

[ARM] Fix PR target/69245 Rewrite arm_set_current_function

Message ID 56A790ED.60603@st.com
State New
Headers show

Commit Message

Christian Bruel Jan. 26, 2016, 3:29 p.m. UTC
On 01/25/2016 05:37 PM, Kyrill Tkachov wrote:


So this is ok for trunk with the testcase changed as discussed above and using -O2
optimisation level and with a couple comment fixes below.

Hi Kyrill,

I realized afterwards that my implementation had a flaw with the 
handling of #pragma GCC reset. What happened is that when both old and 
new TREE_TARGET_OPTION are NULL, we didn't save_restore the globals 
flags, to save compute time. The problem is that with #pragma GCC reset, 
we also fall into this situation, and exit without calling 
target_reeinit :-(

Handling this situation doesn't complicate the code much, because I 
factorized the calls to target_reeinit + restore_target_globals into a 
new function (save_restore_target_globals). This function is called from 
the pragma context when resetting the state arm_reset_previous_fndecl to 
the default, and from arm_set_current_function when setting to a new 
target. This is only done when there is a change of the target flags, so 
no extra computing cost.

Same testing as with previous patch:
     arm-qemu/
     arm-qemu//-mfpu=neon-fp-armv8
     arm-qemu//-mfpu=neon

Still OK ?

Comments

Kyrill Tkachov Jan. 26, 2016, 3:58 p.m. UTC | #1
Hi Christian,

On 26/01/16 15:29, Christian Bruel wrote:
>
>
> On 01/25/2016 05:37 PM, Kyrill Tkachov wrote:
>
>
> So this is ok for trunk with the testcase changed as discussed above and using -O2
> optimisation level and with a couple comment fixes below.
>
> Hi Kyrill,
>
> I realized afterwards that my implementation had a flaw with the handling of #pragma GCC reset. What happened is that when both old and new TREE_TARGET_OPTION are NULL, we didn't save_restore the globals flags, to save compute time. The 
> problem is that with #pragma GCC reset, we also fall into this situation, and exit without calling target_reeinit :-(
>
> Handling this situation doesn't complicate the code much, because I factorized the calls to target_reeinit + restore_target_globals into a new function (save_restore_target_globals). This function is called from the pragma context when 
> resetting the state arm_reset_previous_fndecl to the default, and from arm_set_current_function when setting to a new target. This is only done when there is a change of the target flags, so no extra computing cost.
>
> Same testing as with previous patch:
>     arm-qemu/
>     arm-qemu//-mfpu=neon-fp-armv8
>     arm-qemu//-mfpu=neon
>
> Still OK ?
>

+/* Restore the TREE_TARGET_GLOBALS from previous state, or save it.  */
+static void
+save_restore_target_globals (tree new_tree)
+{
+  /* If we have a previous state, use it.  */
+  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
+    {
+      /* Call target_reinit and save the state for TARGET_GLOBALS.  */
+      TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
+    }
+
+  arm_option_params_internal ();
+}

Space before the function comment and signature. Also, you need to document what is the NEW_TREE
parameter.

  /* Invalidate arm_previous_fndecl.  */
  void
-arm_reset_previous_fndecl (void)
+arm_reset_previous_fndecl (tree new_tree)
  {
+  if (new_tree)
+    save_restore_target_globals (new_tree);
+
    arm_previous_fndecl = NULL_TREE;
  }

I'm a bit wary of complicating this function. Suddenly it doesn't just reset the previous fndecl
but also restores globals and can save stuff into its argument. It's suddenly not clear what it's
purpose is.
I think it would be clearer if you just added save_restore_target_globals to arm_protos.h and called
it explicitly from arm_pragma_target_parse when appropriate.

+
+  /* If nothing to do return. #pragma GCC reset or #pragma GCC pop to
+     the default have been handled by save_restore_target_globals from
+     arm_pragma_target_parse.  */

Two spaces between fullstop and "#pragma GCC".

Thanks,
Kyrill
diff mbox

Patch

2016-01-20  Christian Bruel  <christian.bruel@st.com>

	PR target/69245
	* config/arm/arm-c.c (arm_pragma_target_parse): Add comments.
	Move arm_reset_previous_fndecl and set_target_option_current_node in
	the conditional part. Call save_restore_target_globals.
	* config/arm/arm.c (arm_set_current_function):
	Refactor to better support #pragma target and attribute mix.
	Call save_restore_target_globals.
	* config/arm/arm-protos.h (arm_reset_previous_fndecl): Add parameter.
	(save_restore_target_globals): New function.

2016-01-20  Christian Bruel  <christian.bruel@st.com>

	PR target/69245
	* gcc.target/arm/pr69245.c: New test.

Index: gcc/config/arm/arm-c.c
===================================================================
--- gcc/config/arm/arm-c.c	(revision 232831)
+++ gcc/config/arm/arm-c.c	(working copy)
@@ -221,9 +221,6 @@  arm_pragma_target_parse (tree args, tree pop_targe
 	}
     }
 
-  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);
@@ -259,6 +256,13 @@  arm_pragma_target_parse (tree args, tree pop_targe
       arm_cpu_builtins (parse_in);
 
       cpp_opts->warn_unused_macros = saved_warn_unused_macros;
+
+      /* Make sure that target_reinit is called for next function, since
+	 TREE_TARGET_OPTION might change with the #pragma even if there is
+	 no target attribute attached to the function.  */
+      if (cur_tree != target_option_default_node)
+	cur_tree = NULL;
+      arm_reset_previous_fndecl (cur_tree);
     }
 
   return true;
Index: gcc/config/arm/arm-protos.h
===================================================================
--- gcc/config/arm/arm-protos.h	(revision 232831)
+++ gcc/config/arm/arm-protos.h	(working copy)
@@ -331,7 +331,7 @@  extern bool arm_autoinc_modes_ok_p (machine_mode,
 
 extern void arm_emit_eabi_attribute (const char *, int, int);
 
-extern void arm_reset_previous_fndecl (void);
+extern void arm_reset_previous_fndecl (tree);
 
 /* Defined in gcc/common/config/arm-common.c.  */
 extern const char *arm_rewrite_selected_cpu (const char *name);
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 232831)
+++ gcc/config/arm/arm.c	(working copy)
@@ -3446,8 +3446,7 @@  arm_option_override (void)
 
   /* 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);
+  target_option_default_node = build_target_option_node (&global_options);
 
   /* Init initial mode for testing.  */
   thumb_flipper = TARGET_THUMB;
@@ -29746,10 +29745,31 @@  arm_is_constant_pool_ref (rtx x)
 /* Remember the last target of arm_set_current_function.  */
 static GTY(()) tree arm_previous_fndecl;
 
+/* Restore the TREE_TARGET_GLOBALS from previous state, or save it.  */
+static void
+save_restore_target_globals (tree new_tree)
+{
+  /* If we have a previous state, use it.  */
+  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
+    {
+      /* Call target_reinit and save the state for TARGET_GLOBALS.  */
+      TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
+    }
+
+  arm_option_params_internal ();
+}
+
 /* Invalidate arm_previous_fndecl.  */
 void
-arm_reset_previous_fndecl (void)
+arm_reset_previous_fndecl (tree new_tree)
 {
+  if (new_tree)
+    save_restore_target_globals (new_tree);
+
   arm_previous_fndecl = NULL_TREE;
 }
 
@@ -29768,38 +29788,23 @@  arm_set_current_function (tree fndecl)
 
   tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
 
-  arm_previous_fndecl = fndecl;
+  /* If current function has no attributes but previous one did,
+     use the default node."  */
+  if (! new_tree && old_tree)
+    new_tree = target_option_default_node;
+
+  /* If nothing to do return. #pragma GCC reset or #pragma GCC pop to
+     the default have been handled by save_restore_target_globals from
+     arm_pragma_target_parse.  */
   if (old_tree == new_tree)
     return;
 
-  if (new_tree && new_tree != target_option_default_node)
-    {
-      cl_target_option_restore (&global_options,
-				TREE_TARGET_OPTION (new_tree));
+  arm_previous_fndecl = fndecl;
 
-      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 ();
-    }
+  /* First set the target options.  */
+  cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
 
-  else if (old_tree && old_tree != target_option_default_node)
-    {
-      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 ();
+  save_restore_target_globals (new_tree);
 }
 
 /* Implement TARGET_OPTION_PRINT.  */
Index: gcc/testsuite/gcc.target/arm/pr69245.c
===================================================================
--- gcc/testsuite/gcc.target/arm/pr69245.c	(revision 0)
+++ gcc/testsuite/gcc.target/arm/pr69245.c	(working copy)
@@ -0,0 +1,26 @@ 
+/* PR target/69245 */
+/* Test that pop_options restores the vfp fpu mode.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_fp_ok } */
+/* { dg-options "-O2" } */
+/* { dg-add-options arm_fp } */
+
+#pragma GCC target "fpu=vfp"
+
+#pragma GCC push_options
+#pragma GCC target "fpu=neon-vfpv4"
+int a, c, d;
+float b;
+static int fn1 ()
+{
+  return 0;
+}
+#pragma GCC pop_options
+
+void fn2 ()
+{
+  d = b * c + a;
+}
+
+/* { dg-final { scan-assembler-times "\.fpu vfp" 1 } } */