File gcc48-flive-patching.patch of Package libffi48

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 8ab7ae18102..6cede317c17 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -724,7 +724,7 @@ void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
 void dump_varpool_node_set (FILE *, varpool_node_set);
 void debug_varpool_node_set (varpool_node_set);
 void free_varpool_node_set (varpool_node_set);
-void ipa_discover_readonly_nonaddressable_vars (void);
+void ipa_discover_variable_flags (void);
 bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *);
 bool varpool_externally_visible_p (struct varpool_node *, bool);
 
diff --git a/gcc/cif-code.def b/gcc/cif-code.def
index 55e0ef45b3b..75e5b4d8bbe 100644
--- a/gcc/cif-code.def
+++ b/gcc/cif-code.def
@@ -106,3 +106,9 @@
 
 /* We know that the call will be optimized out.  */
 DEFCIFCODE(NEVER_EXECUTED, N_("never executed"))
+
+/* We can't inline because the user requests only static functions
+   but the function has external linkage for live patching purpose.  */
+DEFCIFCODE(EXTERN_LIVE_ONLY_STATIC,
+	   N_("function has external linkage when the user requests only"
+	      " inlining static for live patching"))
diff --git a/gcc/common.opt b/gcc/common.opt
index ec4cafc448b..816e10e7a9d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1206,6 +1206,24 @@ Common Report Var(flag_hoist_adjacent_loads) Optimization
 Enable hoisting adjacent loads to encourage generating conditional move
 instructions
 
+flive-patching
+Common RejectNegative Alias(flive-patching=,inline-clone) Optimization
+
+flive-patching=
+Common Report Joined RejectNegative Enum(live_patching_level) Var(flag_live_patching) Init(LIVE_PATCHING_NONE) Optimization
+-flive-patching=[inline-only-static|inline-clone]	Control IPA
+optimizations to provide a safe compilation for live-patching.  At the same
+time, provides multiple-level control on the enabled IPA optimizations.
+
+Enum
+Name(live_patching_level) Type(enum live_patching_level) UnknownError(unknown Live-Patching Level %qs)
+
+EnumValue
+Enum(live_patching_level) String(inline-only-static) Value(LIVE_PATCHING_INLINE_ONLY_STATIC)
+
+EnumValue
+Enum(live_patching_level) String(inline-clone) Value(LIVE_PATCHING_INLINE_CLONE)
+
 floop-parallelize-all
 Common Report Var(flag_loop_parallelize_all) Optimization
 Mark all loops as parallel
@@ -1361,7 +1379,15 @@ Discover pure and const functions
 
 fipa-reference
 Common Report Var(flag_ipa_reference) Init(0) Optimization
-Discover readonly and non addressable static variables
+Discover read-only and non addressable static variables.
+
+fipa-reference-addressable
+Common Report Var(flag_ipa_reference_addressable) Init(0) Optimization
+Discover read-only, write-only and non-addressable static variables.
+
+fipa-stack-alignment
+Common Report Var(flag_ipa_stack_alignment) Init(1) Optimization
+Reduce stack alignment on call sites if possible.
 
 fipa-matrix-reorg
 Common Ignore
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index caf06c82d1d..4e8867ebf30 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -370,8 +370,9 @@ Objective-C and Objective-C++ Dialects}.
 -fif-conversion2 -findirect-inlining @gol
 -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
 -finline-small-functions -fipa-cp -fipa-cp-clone @gol
--fipa-pta -fipa-profile -fipa-pure-const -fipa-reference @gol
--fira-algorithm=@var{algorithm} @gol
+-fipa-pta -fipa-profile -fipa-pure-const -fipa-reference -fipa-reference-addressable @gol
+-fipa-stack-alignment -fira-algorithm=@var{algorithm} @gol
+-flive-patching=@var{level} @gol
 -fira-region=@var{region} -fira-hoist-pressure @gol
 -fira-loop-pressure -fno-ira-share-save-slots @gol
 -fno-ira-share-spill-slots -fira-verbose=@var{n} @gol
@@ -6522,6 +6523,7 @@ compilation time.
 -fipa-pure-const @gol
 -fipa-profile @gol
 -fipa-reference @gol
+-fipa-reference-addressable @gol
 -fmerge-constants
 -fsplit-wide-types @gol
 -ftree-bit-ccp @gol
@@ -7111,6 +7113,65 @@ Perform a number of minor optimizations that are relatively expensive.
 
 Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
 
+@item -flive-patching=@var{level}
+@opindex flive-patching
+Control GCC's optimizations to provide a safe compilation for live-patching.
+
+If the compiler's optimization uses a function's body or information extracted
+from its body to optimize/change another function, the latter is called an
+impacted function of the former.  If a function is patched, its impacted
+functions should be patched too.
+
+The impacted functions are decided by the compiler's interprocedural
+optimizations.  For example, inlining a function into its caller, cloning
+a function and changing its caller to call this new clone, or extracting
+a function's pureness/constness information to optimize its direct or
+indirect callers, etc.
+
+Usually, the more IPA optimizations enabled, the larger the number of
+impacted functions for each function.  In order to control the number of
+impacted functions and computed the list of impacted function easily,
+we provide control to partially enable IPA optimizations on two different
+levels.
+
+The @var{level} argument should be one of the following:
+
+@table @samp
+
+@item inline-clone
+
+Only enable inlining and cloning optimizations, which includes inlining,
+cloning, interprocedural scalar replacement of aggregates and partial inlining.
+As a result, when patching a function, all its callers and its clones'
+callers need to be patched as well.
+
+@option{-flive-patching=inline-clone} disables the following optimization flags:
+@gccoptlist{-fwhole-program  -fipa-pta  -fipa-reference  -fipa-ra @gol
+-fipa-icf  -fipa-icf-functions  -fipa-icf-variables @gol
+-fipa-bit-cp  -fipa-vrp  -fipa-pure-const  -fipa-reference-addressable @gol
+-fipa-stack-alignment}
+
+@item inline-only-static
+
+Only enable inlining of static functions.
+As a result, when patching a static function, all its callers need to be
+patches as well.
+
+In addition to all the flags that -flive-patching=inline-clone disables,
+@option{-flive-patching=inline-only-static} disables the following additional
+optimization flags:
+@gccoptlist{-fipa-cp-clone  -fipa-sra  -fpartial-inlining  -fipa-cp}
+
+@end table
+
+When -flive-patching specified without any value, the default value
+is "inline-clone".
+
+This flag is disabled by default.
+
+Note that -flive-patching is not supported with link-time optimizer.
+(@option{-flto}).
+
 @item -free
 @opindex free
 Attempt to remove redundant extension instructions.  This is especially
@@ -7459,6 +7520,16 @@ Discover which static variables do not escape the
 compilation unit.
 Enabled by default at @option{-O} and higher.
 
+@item -fipa-reference-addressable
+@opindex fipa-reference-addressable
+Discover read-only, write-only and non-addressable static variables.
+Enabled by default at @option{-O} and higher.
+
+@item -fipa-stack-alignment
+@opindex fipa-stack-alignment
+Reduce stack alignment on call sites if possible.
+Enabled by default.
+
 @item -fipa-pta
 @opindex fipa-pta
 Perform interprocedural pointer analysis and interprocedural modification
diff --git a/gcc/final.c b/gcc/final.c
index d25b8e0b7e4..cf22d390945 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4540,7 +4540,8 @@ rest_of_clean_state (void)
   /* We can reduce stack alignment on call site only when we are sure that
      the function body just produced will be actually used in the final
      executable.  */
-  if (decl_binds_to_current_def_p (current_function_decl))
+  if (flag_ipa_stack_alignment
+      && decl_binds_to_current_def_p (current_function_decl))
     {
       unsigned int pref = crtl->preferred_stack_boundary;
       if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 4fc5d33348e..590071f99ba 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -112,6 +112,14 @@ enum stack_reuse_level
   SR_ALL
 };
 
+/* The live patching level.  */
+enum live_patching_level
+{
+  LIVE_PATCHING_NONE = 0,
+  LIVE_PATCHING_INLINE_ONLY_STATIC,
+  LIVE_PATCHING_INLINE_CLONE
+};
+
 /* The algorithm used for the integrated register allocator (IRA).  */
 enum ira_algorithm
 {
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 90b2a13fce9..33589cfab16 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -316,6 +316,13 @@ can_inline_edge_p (struct cgraph_edge *e, bool report)
 				    : e->caller->symbol.decl))
            && !caller_growth_limits (e))
     inlinable = false;
+  else if (callee->symbol.externally_visible
+	   && !DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)
+	   && flag_live_patching == LIVE_PATCHING_INLINE_ONLY_STATIC)
+    {
+      e->inline_failed = CIF_EXTERN_LIVE_ONLY_STATIC;
+      inlinable = false;
+    }
   /* Don't inline a function with a higher optimization level than the
      caller.  FIXME: this is really just tip of iceberg of handling
      optimization attribute.  */
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index f3c483f67f9..3463b7655e9 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -675,7 +675,7 @@ propagate (void)
   if (dump_file)
     dump_cgraph (dump_file);
 
-  ipa_discover_readonly_nonaddressable_vars ();
+  ipa_discover_variable_flags ();
   generate_summary ();
 
   /* Now we know what vars are really statics; prune out those that aren't.  */
diff --git a/gcc/ipa.c b/gcc/ipa.c
index be377a70e1d..6bd215f35e6 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -474,7 +474,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
    make sense to do it before early optimizations.  */
 
 void
-ipa_discover_readonly_nonaddressable_vars (void)
+ipa_discover_variable_flags (void)
 {
   struct varpool_node *vnode;
   if (dump_file)
@@ -1018,7 +1018,7 @@ whole_program_function_and_variable_visibility (void)
 {
   function_and_variable_visibility (flag_whole_program);
   if (optimize)
-    ipa_discover_readonly_nonaddressable_vars ();
+    ipa_discover_variable_flags ();
   return 0;
 }
 
diff --git a/gcc/opts.c b/gcc/opts.c
index 55cd965282d..78a79daa6dc 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -429,6 +429,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_1_PLUS_NOT_DEBUG, OPT_fif_conversion2, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fipa_pure_const, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fipa_reference, NULL, 1 },
+    { OPT_LEVELS_1_PLUS, OPT_fipa_reference_addressable, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fipa_profile, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fmerge_constants, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fshrink_wrap, NULL, 1 },
@@ -623,6 +624,106 @@ default_options_optimization (struct gcc_options *opts,
 			 lang_mask, handlers, loc, dc);
 }
 
+/* Control IPA optimizations based on different live patching LEVEL.  */
+static void
+control_options_for_live_patching (struct gcc_options *opts,
+				   struct gcc_options *opts_set,
+				   enum live_patching_level level,
+				   location_t loc)
+{
+  gcc_assert (level > LIVE_PATCHING_NONE);
+
+  switch (level)
+    {
+    case LIVE_PATCHING_INLINE_ONLY_STATIC:
+      if (opts_set->x_flag_ipa_cp_clone && opts->x_flag_ipa_cp_clone)
+	error_at (loc,
+		  "%<-fipa-cp-clone%> is incompatible with "
+		  "%<-flive-patching=inline-only-static%>");
+      else
+	opts->x_flag_ipa_cp_clone = 0;
+
+      if (opts_set->x_flag_ipa_sra && opts->x_flag_ipa_sra)
+	error_at (loc,
+		  "%<-fipa-sra%> is incompatible with "
+		  "%<-flive-patching=inline-only-static%>");
+      else
+	opts->x_flag_ipa_sra = 0;
+
+      if (opts_set->x_flag_partial_inlining && opts->x_flag_partial_inlining)
+	error_at (loc,
+		  "%<-fpartial-inlining%> is incompatible with "
+		  "%<-flive-patching=inline-only-static%>");
+      else
+	opts->x_flag_partial_inlining = 0;
+
+      if (opts_set->x_flag_ipa_cp && opts->x_flag_ipa_cp)
+	error_at (loc,
+		  "%<-fipa-cp%> is incompatible with "
+		  "%<-flive-patching=inline-only-static%>");
+      else
+	opts->x_flag_ipa_cp = 0;
+
+      /* FALLTHROUGH.  */
+    case LIVE_PATCHING_INLINE_CLONE:
+      /* live patching should disable whole-program optimization.  */
+      if (opts_set->x_flag_whole_program && opts->x_flag_whole_program)
+	error_at (loc,
+		  "%<-fwhole-program%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_whole_program = 0;
+
+      /* visibility change should be excluded by !flag_whole_program
+	 && !in_lto_p && !flag_ipa_cp_clone && !flag_ipa_sra
+	 && !flag_partial_inlining.  */
+
+      if (opts_set->x_flag_ipa_pta && opts->x_flag_ipa_pta)
+	error_at (loc,
+		  "%<-fipa-pta%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_ipa_pta = 0;
+
+      if (opts_set->x_flag_ipa_reference && opts->x_flag_ipa_reference)
+	error_at (loc,
+		  "%<-fipa-reference%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_ipa_reference = 0;
+
+      if (opts_set->x_flag_ipa_pure_const && opts->x_flag_ipa_pure_const)
+	error_at (loc,
+		  "%<-fipa-pure-const%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_ipa_pure_const = 0;
+
+      /* FIXME: disable unreachable code removal.  */
+
+      /* discovery of functions/variables with no address taken.  */
+      if (opts_set->x_flag_ipa_reference_addressable
+	  && opts->x_flag_ipa_reference_addressable)
+	error_at (loc,
+		  "%<-fipa-reference-addressable%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_ipa_reference_addressable = 0;
+
+      /* ipa stack alignment propagation.  */
+      if (opts_set->x_flag_ipa_stack_alignment
+	  && opts->x_flag_ipa_stack_alignment)
+	error_at (loc,
+		  "%<-fipa-stack-alignment%> is incompatible with "
+		  "%<-flive-patching=inline-only-static|inline-clone%>");
+      else
+	opts->x_flag_ipa_stack_alignment = 0;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* After all options at LOC have been read into OPTS and OPTS_SET,
    finalize settings of those options and diagnose incompatible
    combinations.  */
@@ -831,6 +932,18 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   /* The -gsplit-dwarf option requires -gpubnames.  */
   if (opts->x_dwarf_split_debug_info)
     opts->x_debug_generate_pub_sections = 1;
+
+  /* Currently live patching is not support for LTO.  */
+  if (opts->x_flag_live_patching && opts->x_flag_lto)
+    sorry ("live patching is not supported with LTO");
+
+  /* Control IPA optimizations based on different -flive-patching level.  */
+  if (opts->x_flag_live_patching)
+    {
+      control_options_for_live_patching (opts, opts_set,
+					 opts->x_flag_live_patching,
+					 loc);
+    }
 }
 
 #define LEFT_COLUMN	27
diff --git a/gcc/testsuite/gcc.dg/live-patching-1.c b/gcc/testsuite/gcc.dg/live-patching-1.c
new file mode 100644
index 00000000000..ab4738119b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/live-patching-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -flive-patching=inline-only-static -fdump-ipa-inline" } */
+
+extern int sum, n, m;
+
+int foo (int a)
+{
+  return a + n;
+}
+
+static int bar (int b)
+{
+  return b * m;
+}
+
+int main()
+{
+  sum = foo (m) + bar (n);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "foo/0 function has external linkage when the user requests only inlining static for live patching"  "inline" } } */
diff --git a/gcc/testsuite/gcc.dg/live-patching-2.c b/gcc/testsuite/gcc.dg/live-patching-2.c
new file mode 100644
index 00000000000..0dde4e9e0c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/live-patching-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target lto } */
+/* { dg-options "-O2 -flive-patching -flto" } */
+
+int main()
+{
+  return 0;
+}
+
+/* { dg-message "sorry, unimplemented: live patching is not supported with LTO" "-flive-patching and -flto together" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/live-patching-3.c b/gcc/testsuite/gcc.dg/live-patching-3.c
new file mode 100644
index 00000000000..b86f3c6e08a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/live-patching-3.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -flive-patching -fwhole-program" } */
+
+int main()
+{
+  return 0;
+}
+
+/* { dg-message "'-fwhole-program' is incompatible with '-flive-patching=inline-only-static|inline-clone’" "" {target "*-*-*"} 0 } */
diff --git a/gcc/testsuite/gcc.dg/live-patching-4.c b/gcc/testsuite/gcc.dg/live-patching-4.c
new file mode 100644
index 00000000000..c3862a5bd7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/live-patching-4.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -flive-patching=inline-only-static -fdump-tree-einline" } */
+
+extern int sum, n, m;
+
+extern inline __attribute__((always_inline)) int foo (int a);
+inline __attribute__((always_inline)) int foo (int a)
+{
+  return a + n;
+}
+
+static int bar (int b)
+{
+  return b * m;
+}
+
+int main()
+{
+  sum = foo (m) + bar (n);
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump "Inlining foo into main"  "einline" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/writeonly-2.c b/gcc/testsuite/gcc.dg/tree-ssa/writeonly-2.c
new file mode 100644
index 00000000000..78893bd7fb8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/writeonly-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized -fno-ipa-reference-addressable" } */
+static struct a {int magic1,b;} a;
+volatile int magic2;
+static struct b {int a,b,c,d,e,f;} magic3;
+
+struct b foo();
+
+void
+t()
+{
+ a.magic1 = 1;
+ magic2 = 1;
+ magic3 = foo();
+}
+/* { dg-final { scan-tree-dump "magic1" "optimized"} } */
+/* { dg-final { scan-tree-dump "magic3" "optimized"} } */
+/* { dg-final { scan-tree-dump "magic2" "optimized"} } */
+/* { dg-final { scan-tree-dump "foo" "optimized"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/writeonly-3.c b/gcc/testsuite/gcc.dg/tree-ssa/writeonly-3.c
new file mode 100644
index 00000000000..b42d9374fe9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/writeonly-3.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized -flive-patching" } */
+static struct a {int magic1,b;} a;
+volatile int magic2;
+static struct b {int a,b,c,d,e,f;} magic3;
+
+struct b foo();
+
+void
+t()
+{
+ a.magic1 = 1;
+ magic2 = 1;
+ magic3 = foo();
+}
+/* { dg-final { scan-tree-dump "magic1" "optimized"} } */
+/* { dg-final { scan-tree-dump "magic3" "optimized"} } */
+/* { dg-final { scan-tree-dump "magic2" "optimized"} } */
+/* { dg-final { scan-tree-dump "foo" "optimized"} } */
+
diff --git a/gcc/testsuite/gcc.target/i386/ipa-stack-alignment-2.c b/gcc/testsuite/gcc.target/i386/ipa-stack-alignment-2.c
new file mode 100644
index 00000000000..8ba70000b7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ipa-stack-alignment-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-flive-patching -O" } */
+
+typedef struct {
+  long a;
+  long b[];
+} c;
+
+c *d;
+void e() { d->b[0] = 5; }
+void f() { e(); }
+
+/* { dg-final { scan-assembler "sub.*%.sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/ipa-stack-alignment.c b/gcc/testsuite/gcc.target/i386/ipa-stack-alignment.c
new file mode 100644
index 00000000000..1176b59aa5f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/ipa-stack-alignment.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fno-ipa-stack-alignment -O" } */
+
+typedef struct {
+  long a;
+  long b[];
+} c;
+
+c *d;
+void e() { d->b[0] = 5; }
+void f() { e(); }
+
+/* { dg-final { scan-assembler "sub.*%.sp" } } */
openSUSE Build Service is sponsored by