to support live patching in GCC.
2018-11-29 qing zhao <qing.zhao@oracle.com>
gcc/ChangeLog:
* cif-code.def (EXTERN_LIVE_ONLY_STATIC): New CIF code.
* common.opt: Add -flive-patching flag.
* doc/invoke.texi: Document -flive-patching.
* flag-types.h (enum live_patching_level): New enum.
* ipa-inline.c (can_inline_edge_p): Disable external functions from
inlining when flag_live_patching is LIVE_PATCHING_INLINE_ONLY_STATIC.
* opts.c (control_options_for_live_patching): New function.
(finish_options): Make flag_live_patching incompatible with flag_lto.
Control IPA optimizations based on different levels of
flag_live_patching.
gcc/testsuite/ChangeLog:
* gcc.dg/live-patching-1.c: New test.
* gcc.dg/live-patching-2.c: New test.
* gcc.dg/live-patching-3.c: New test.
* gcc.dg/tree-ssa/writeonly-3.c: New test.
* gcc.target/i386/ipa-stack-alignment-2.c: New test.
From-SVN: r266627
+2018-11-29 qing zhao <qing.zhao@oracle.com>
+
+ * cif-code.def (EXTERN_LIVE_ONLY_STATIC): New CIF code.
+ * common.opt: Add -flive-patching flag.
+ * doc/invoke.texi: Document -flive-patching.
+ * flag-types.h (enum live_patching_level): New enum.
+ * ipa-inline.c (can_inline_edge_p): Disable external functions from
+ inlining when flag_live_patching is LIVE_PATCHING_INLINE_ONLY_STATIC.
+ * opts.c (control_options_for_live_patching): New function.
+ (finish_options): Make flag_live_patching incompatible with flag_lto.
+ Control IPA optimizations based on different levels of
+ flag_live_patching.
+
2018-11-29 Giuliano Belinassi <giuliano.belinassi@usp.br>
* match.pd (sinh (atanh (x))): New simplification rules.
DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
N_("function attribute mismatch"))
+/* 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, CIF_FINAL_ERROR,
+ N_("function has external linkage when the user requests only"
+ " inlining static for live patching"))
+
/* We proved that the call is unreachable. */
DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
N_("unreachable"))
flifetime-dse=
Common Joined RejectNegative UInteger Var(flag_lifetime_dse) Optimization IntegerRange(0, 2)
+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)
+
flive-range-shrinkage
Common Report Var(flag_live_range_shrinkage) Init(0) Optimization
Relief of register pressure through live range shrinkage.
-fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const @gol
-fipa-reference -fipa-reference-addressable @gol
-fipa-stack-alignment -fipa-icf -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 @gol
This flag is enabled by default at @option{-O2} and @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 -fisolate-erroneous-paths-dereference
@opindex fisolate-erroneous-paths-dereference
Detect paths that trigger erroneous or undefined behavior due to
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 basic block reordering. */
enum reorder_blocks_algorithm
{
e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
inlinable = false;
}
+ else if (callee->externally_visible
+ && flag_live_patching == LIVE_PATCHING_INLINE_ONLY_STATIC)
+ {
+ e->inline_failed = CIF_EXTERN_LIVE_ONLY_STATIC;
+ inlinable = false;
+ }
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
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_ra && opts->x_flag_ipa_ra)
+ error_at (loc,
+ "%<-fipa-ra%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_ra = 0;
+
+ if (opts_set->x_flag_ipa_icf && opts->x_flag_ipa_icf)
+ error_at (loc,
+ "%<-fipa-icf%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_icf = 0;
+
+ if (opts_set->x_flag_ipa_icf_functions && opts->x_flag_ipa_icf_functions)
+ error_at (loc,
+ "%<-fipa-icf-functions%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_icf_functions = 0;
+
+ if (opts_set->x_flag_ipa_icf_variables && opts->x_flag_ipa_icf_variables)
+ error_at (loc,
+ "%<-fipa-icf-variables%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_icf_variables = 0;
+
+ if (opts_set->x_flag_ipa_bit_cp && opts->x_flag_ipa_bit_cp)
+ error_at (loc,
+ "%<-fipa-bit-cp%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_bit_cp = 0;
+
+ if (opts_set->x_flag_ipa_vrp && opts->x_flag_ipa_vrp)
+ error_at (loc,
+ "%<-fipa-vrp%> is incompatible with "
+ "%<-flive-patching=inline-only-static|inline-clone%>");
+ else
+ opts->x_flag_ipa_vrp = 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. */
if ((opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS) && opts->x_flag_tm)
sorry ("transactional memory is not supported with "
"%<-fsanitize=kernel-address%>");
+
+ /* 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
+2018-11-29 qing zhao <qing.zhao@oracle.com>
+
+ * gcc.dg/live-patching-1.c: New test.
+ * gcc.dg/live-patching-2.c: New test.
+ * gcc.dg/live-patching-3.c: New test.
+ * gcc.dg/tree-ssa/writeonly-3.c: New test.
+ * gcc.target/i386/ipa-stack-alignment-2.c: New test.
+
2018-11-29 Giuliano Belinassi <giuliano.belinassi@usp.br>
* gcc.dg/sinhatanh-1.c: New test.
--- /dev/null
+/* { 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" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { 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 } */
--- /dev/null
+/* { 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 } */
--- /dev/null
+/* { 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"} } */
+
--- /dev/null
+/* { 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" } } */