diff mbox series

[2/3] Add patch_area_size and patch_area_entry to cfun

Message ID 20200205143300.144541-3-hjl.tools@gmail.com
State New
Headers show
Series Update -fpatchable-function-entry implementation | expand

Commit Message

H.J. Lu Feb. 5, 2020, 2:32 p.m. UTC
Currently patchable area is at the wrong place.  It is placed immediately
after function label and before .cfi_startproc.  A backend should be able
to add a pseudo patchable area instruction durectly into RTL.  This patch
adds patch_area_size and patch_area_entry to cfun so that the patchable
area info is available in RTL passes.

It also limits patch_area_size and patch_area_entry to 65535, which is
a reasonable maximum size for patchable area.

gcc/

	PR target/93492
	* function.c (expand_function_start): Set cfun->patch_area_size
	and cfun->patch_area_entry.
	* function.h (function): Add patch_area_size and patch_area_entry.
	* opts.c (common_handle_option): Limit
	function_entry_patch_area_size and function_entry_patch_area_start
	to USHRT_MAX.  Fix a typo in error message.
	* varasm.c (assemble_start_function): Use cfun->patch_area_size
	and cfun->patch_area_entry.
	* doc/invoke.texi: Document the maximum value for
	-fpatchable-function-entry.

gcc/testsuite/

	PR target/93492
	* c-c++-common/patchable_function_entry-error-1.c: New test.
	* c-c++-common/patchable_function_entry-error-2.c: Likewise.
	* c-c++-common/patchable_function_entry-error-3.c: Likewise.
---
 gcc/doc/invoke.texi                           |  1 +
 gcc/function.c                                | 35 +++++++++++++++++++
 gcc/function.h                                |  6 ++++
 gcc/opts.c                                    |  4 ++-
 .../patchable_function_entry-error-1.c        |  9 +++++
 .../patchable_function_entry-error-2.c        |  9 +++++
 .../patchable_function_entry-error-3.c        | 20 +++++++++++
 gcc/varasm.c                                  | 30 ++--------------
 8 files changed, 85 insertions(+), 29 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-1.c
 create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-2.c
 create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-3.c

Comments

Richard Sandiford Feb. 5, 2020, 5 p.m. UTC | #1
"H.J. Lu" <hjl.tools@gmail.com> writes:
> Currently patchable area is at the wrong place.

Agreed :-)

> It is placed immediately
> after function label and before .cfi_startproc.  A backend should be able
> to add a pseudo patchable area instruction durectly into RTL.  This patch
> adds patch_area_size and patch_area_entry to cfun so that the patchable
> area info is available in RTL passes.

It might be better to add it to crtl, since it should only be needed
during rtl generation.

> It also limits patch_area_size and patch_area_entry to 65535, which is
> a reasonable maximum size for patchable area.
>
> gcc/
>
> 	PR target/93492
> 	* function.c (expand_function_start): Set cfun->patch_area_size
> 	and cfun->patch_area_entry.
> 	* function.h (function): Add patch_area_size and patch_area_entry.
> 	* opts.c (common_handle_option): Limit
> 	function_entry_patch_area_size and function_entry_patch_area_start
> 	to USHRT_MAX.  Fix a typo in error message.
> 	* varasm.c (assemble_start_function): Use cfun->patch_area_size
> 	and cfun->patch_area_entry.
> 	* doc/invoke.texi: Document the maximum value for
> 	-fpatchable-function-entry.
>
> gcc/testsuite/
>
> 	PR target/93492
> 	* c-c++-common/patchable_function_entry-error-1.c: New test.
> 	* c-c++-common/patchable_function_entry-error-2.c: Likewise.
> 	* c-c++-common/patchable_function_entry-error-3.c: Likewise.
> ---
>  gcc/doc/invoke.texi                           |  1 +
>  gcc/function.c                                | 35 +++++++++++++++++++
>  gcc/function.h                                |  6 ++++
>  gcc/opts.c                                    |  4 ++-
>  .../patchable_function_entry-error-1.c        |  9 +++++
>  .../patchable_function_entry-error-2.c        |  9 +++++
>  .../patchable_function_entry-error-3.c        | 20 +++++++++++
>  gcc/varasm.c                                  | 30 ++--------------
>  8 files changed, 85 insertions(+), 29 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-2.c
>  create mode 100644 gcc/testsuite/c-c++-common/patchable_function_entry-error-3.c
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 35b341e759f..dd4835199b0 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -13966,6 +13966,7 @@ If @code{N=0}, no pad location is recorded.
>  The NOP instructions are inserted at---and maybe before, depending on
>  @var{M}---the function entry address, even before the prologue.
>  
> +The maximum value of @var{N} and @var{M} is 65535.
>  @end table
>  
>  
> diff --git a/gcc/function.c b/gcc/function.c
> index d8008f60422..badbf538eec 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -5202,6 +5202,41 @@ expand_function_start (tree subr)
>    /* If we are doing generic stack checking, the probe should go here.  */
>    if (flag_stack_check == GENERIC_STACK_CHECK)
>      stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
> +
> +  unsigned HOST_WIDE_INT patch_area_size = function_entry_patch_area_size;
> +  unsigned HOST_WIDE_INT patch_area_entry = function_entry_patch_area_start;
> +
> +  tree patchable_function_entry_attr
> +    = lookup_attribute ("patchable_function_entry",
> +			DECL_ATTRIBUTES (cfun->decl));
> +  if (patchable_function_entry_attr)
> +    {
> +      tree pp_val = TREE_VALUE (patchable_function_entry_attr);
> +      tree patchable_function_entry_value1 = TREE_VALUE (pp_val);
> +
> +      patch_area_size = tree_to_uhwi (patchable_function_entry_value1);
> +      patch_area_entry = 0;
> +      if (TREE_CHAIN (pp_val) != NULL_TREE)
> +	{
> +	  tree patchable_function_entry_value2
> +	    = TREE_VALUE (TREE_CHAIN (pp_val));
> +	  patch_area_entry = tree_to_uhwi (patchable_function_entry_value2);
> +	}
> +      if (patch_area_size > USHRT_MAX || patch_area_size > USHRT_MAX)
> +	error ("invalid values for %<patchable_function_entry%> attribute");

This should probably go in handle_patchable_function_entry_attribute
instead.  It doesn't look like we have a clear policy about whether
errors or warnings are right for unrecognised arguments to known
attribute names, but handle_patchable_function_entry_attribute reports
an OPT_Wattributes warning for arguments that aren't integers.  Doing the
same for out-of-range integers would be more consistent and means that
we wouldn't break existing code if we relaxed/changed the rules in future.

Thanks,
Richard
diff mbox series

Patch

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 35b341e759f..dd4835199b0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -13966,6 +13966,7 @@  If @code{N=0}, no pad location is recorded.
 The NOP instructions are inserted at---and maybe before, depending on
 @var{M}---the function entry address, even before the prologue.
 
+The maximum value of @var{N} and @var{M} is 65535.
 @end table
 
 
diff --git a/gcc/function.c b/gcc/function.c
index d8008f60422..badbf538eec 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -5202,6 +5202,41 @@  expand_function_start (tree subr)
   /* If we are doing generic stack checking, the probe should go here.  */
   if (flag_stack_check == GENERIC_STACK_CHECK)
     stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+
+  unsigned HOST_WIDE_INT patch_area_size = function_entry_patch_area_size;
+  unsigned HOST_WIDE_INT patch_area_entry = function_entry_patch_area_start;
+
+  tree patchable_function_entry_attr
+    = lookup_attribute ("patchable_function_entry",
+			DECL_ATTRIBUTES (cfun->decl));
+  if (patchable_function_entry_attr)
+    {
+      tree pp_val = TREE_VALUE (patchable_function_entry_attr);
+      tree patchable_function_entry_value1 = TREE_VALUE (pp_val);
+
+      patch_area_size = tree_to_uhwi (patchable_function_entry_value1);
+      patch_area_entry = 0;
+      if (TREE_CHAIN (pp_val) != NULL_TREE)
+	{
+	  tree patchable_function_entry_value2
+	    = TREE_VALUE (TREE_CHAIN (pp_val));
+	  patch_area_entry = tree_to_uhwi (patchable_function_entry_value2);
+	}
+      if (patch_area_size > USHRT_MAX || patch_area_size > USHRT_MAX)
+	error ("invalid values for %<patchable_function_entry%> attribute");
+    }
+
+  if (patch_area_entry > patch_area_size)
+    {
+      if (patch_area_size > 0)
+	warning (OPT_Wattributes,
+		 "patchable function entry %wu exceeds size %wu",
+		 patch_area_entry, patch_area_size);
+      patch_area_entry = 0;
+    }
+
+  cfun->patch_area_size = patch_area_size;
+  cfun->patch_area_entry = patch_area_entry;
 }
 
 void
diff --git a/gcc/function.h b/gcc/function.h
index 1ee8ed3de53..1ed7c400f23 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -332,6 +332,12 @@  struct GTY(()) function {
   /* Last assigned dependence info clique.  */
   unsigned short last_clique;
 
+  /* How many NOP insns to place at each function entry by default.  */
+  unsigned short patch_area_size;
+
+  /* How far the real asm entry point is into this area.  */
+  unsigned short patch_area_entry;
+
   /* Collected bit flags.  */
 
   /* Number of units of general registers that need saving in stdarg
diff --git a/gcc/opts.c b/gcc/opts.c
index 7affeb41a96..c6011f1f9b7 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2598,10 +2598,12 @@  common_handle_option (struct gcc_options *opts,
 	    function_entry_patch_area_start = 0;
 	  }
 	if (function_entry_patch_area_size < 0
+	    || function_entry_patch_area_size > USHRT_MAX
 	    || function_entry_patch_area_start < 0
+	    || function_entry_patch_area_start > USHRT_MAX
 	    || function_entry_patch_area_size 
 		< function_entry_patch_area_start)
-	  error ("invalid arguments for %<-fpatchable_function_entry%>");
+	  error ("invalid arguments for %<-fpatchable-function-entry%>");
 	free (patch_area_arg);
       }
       break;
diff --git a/gcc/testsuite/c-c++-common/patchable_function_entry-error-1.c b/gcc/testsuite/c-c++-common/patchable_function_entry-error-1.c
new file mode 100644
index 00000000000..f60bf46cfe3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/patchable_function_entry-error-1.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
+/* { dg-options "-O2 -fpatchable-function-entry=65536,1" } */
+/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
+/* { dg-error "invalid arguments for '-fpatchable-function-entry'" "" { target *-*-* } 0 } */
+
+void
+foo (void)
+{
+}
diff --git a/gcc/testsuite/c-c++-common/patchable_function_entry-error-2.c b/gcc/testsuite/c-c++-common/patchable_function_entry-error-2.c
new file mode 100644
index 00000000000..90f88c78be7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/patchable_function_entry-error-2.c
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
+/* { dg-options "-O2 -fpatchable-function-entry=1,65536" } */
+/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
+/* { dg-error "invalid arguments for '-fpatchable-function-entry'" "" { target *-*-* } 0 } */
+
+void
+foo (void)
+{
+}
diff --git a/gcc/testsuite/c-c++-common/patchable_function_entry-error-3.c b/gcc/testsuite/c-c++-common/patchable_function_entry-error-3.c
new file mode 100644
index 00000000000..b6e449425d2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/patchable_function_entry-error-3.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
+/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
+
+void
+ __attribute__((patchable_function_entry(65536)))
+foo1 (void) /* { dg-error "invalid values for 'patchable_function_entry'" } */
+{
+}
+
+void
+ __attribute__((patchable_function_entry(65536,1)))
+foo2 (void) /* { dg-error "invalid values for 'patchable_function_entry'" } */
+{
+}
+
+void
+ __attribute__((patchable_function_entry(65536,65536)))
+foo3 (void) /* { dg-error "invalid values for 'patchable_function_entry'" } */
+{
+}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index dc6da6c0b5b..93251f07d6e 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -1857,34 +1857,8 @@  assemble_start_function (tree decl, const char *fnname)
   if (DECL_PRESERVE_P (decl))
     targetm.asm_out.mark_decl_preserved (fnname);
 
-  unsigned HOST_WIDE_INT patch_area_size = function_entry_patch_area_size;
-  unsigned HOST_WIDE_INT patch_area_entry = function_entry_patch_area_start;
-
-  tree patchable_function_entry_attr
-    = lookup_attribute ("patchable_function_entry", DECL_ATTRIBUTES (decl));
-  if (patchable_function_entry_attr)
-    {
-      tree pp_val = TREE_VALUE (patchable_function_entry_attr);
-      tree patchable_function_entry_value1 = TREE_VALUE (pp_val);
-
-      patch_area_size = tree_to_uhwi (patchable_function_entry_value1);
-      patch_area_entry = 0;
-      if (TREE_CHAIN (pp_val) != NULL_TREE)
-	{
-	  tree patchable_function_entry_value2
-	    = TREE_VALUE (TREE_CHAIN (pp_val));
-	  patch_area_entry = tree_to_uhwi (patchable_function_entry_value2);
-	}
-    }
-
-  if (patch_area_entry > patch_area_size)
-    {
-      if (patch_area_size > 0)
-	warning (OPT_Wattributes,
-		 "patchable function entry %wu exceeds size %wu",
-		 patch_area_entry, patch_area_size);
-      patch_area_entry = 0;
-    }
+  unsigned short patch_area_size = cfun->patch_area_size;
+  unsigned short patch_area_entry = cfun->patch_area_entry;
 
   /* Emit the patching area before the entry label, if any.  */
   if (patch_area_entry > 0)