gcc7/gcc7-flive-patching.patch

663 lines
22 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# The patch is squashed branch:
# https://github.com/marxin/gcc/tree/backport-7-live-patching
# which contains backport of following revisions:
# r270134, r266787, r266627, r265970, r265969
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index ee053885442..8959aee2cc2 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -2335,7 +2335,7 @@ void record_references_in_initializer (tree, bool);
/* In ipa.c */
void cgraph_build_static_cdtor (char which, tree body, int priority);
-bool ipa_discover_readonly_nonaddressable_vars (void);
+bool ipa_discover_variable_flags (void);
/* In varpool.c */
tree ctor_for_folding (tree);
diff --git a/gcc/cif-code.def b/gcc/cif-code.def
index 966c6d6f323..dd9dc422d9f 100644
--- a/gcc/cif-code.def
+++ b/gcc/cif-code.def
@@ -136,6 +136,12 @@ DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
DEFCIFCODE(CILK_SPAWN, CIF_FINAL_ERROR,
N_("caller function contains cilk spawn"))
+/* 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"))
diff --git a/gcc/common.opt b/gcc/common.opt
index 437db8e8615..40d0ecb4fa0 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1645,7 +1645,15 @@ Perform Identical Code Folding for variables.
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
@@ -2055,6 +2063,24 @@ starts and when the destructor finishes.
flifetime-dse=
Common Joined RejectNegative UInteger Var(flag_lifetime_dse) Optimization
+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.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8f279e454b0..36b5ebe439f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -375,8 +375,9 @@ Objective-C and Objective-C++ Dialects}.
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
-finline-small-functions -fipa-cp -fipa-cp-clone @gol
-fipa-bit-cp -fipa-vrp @gol
--fipa-pta -fipa-profile -fipa-pure-const -fipa-reference -fipa-icf @gol
--fira-algorithm=@var{algorithm} @gol
+-fipa-pta -fipa-profile -fipa-pure-const -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
@@ -7038,6 +7039,7 @@ compilation time.
-fipa-pure-const @gol
-fipa-profile @gol
-fipa-reference @gol
+-fipa-reference-addressable @gol
-fmerge-constants @gol
-fmove-loop-invariants @gol
-freorder-blocks @gol
@@ -8068,6 +8070,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
@@ -8128,6 +8140,65 @@ equivalences that are found only by GCC and equivalences found only by Gold.
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
diff --git a/gcc/final.c b/gcc/final.c
index c3023285c21..de728c23ed3 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4722,7 +4722,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 27a38efdc8e..16d70e18f29 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -124,6 +124,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 basic block reordering. */
enum reorder_blocks_algorithm
{
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index b520c6393f4..01a1f59e806 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -381,6 +381,13 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
DECL_ATTRIBUTES (caller->decl))
&& !caller_growth_limits (e))
inlinable = false;
+ else if (callee->externally_visible
+ && !DECL_DISREGARD_INLINE_LIMITS (callee->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. */
@@ -506,7 +513,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
inlinable = false;
}
}
-
}
if (!inlinable && report)
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index ccbfa078deb..69146962d01 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -723,7 +723,7 @@ propagate (void)
if (dump_file)
cgraph_node::dump_cgraph (dump_file);
- remove_p = ipa_discover_readonly_nonaddressable_vars ();
+ remove_p = ipa_discover_variable_flags ();
generate_summary ();
/* Propagate the local information through the call graph to produce
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index da4a22e7329..10a5c0f8b34 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -877,7 +877,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/ipa.c b/gcc/ipa.c
index a74f28c2aa1..110411e9e52 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -782,10 +782,10 @@ clear_addressable_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
return false;
}
-/* Discover variables that have no longer address taken or that are read only
- and update their flags.
+/* Discover variables that have no longer address taken, are read-only or
+ write-only and update their flags.
- Return true when unreachable symbol removan should be done.
+ Return true when unreachable symbol removal should be done.
FIXME: This can not be done in between gimplify and omp_expand since
readonly flag plays role on what is shared and what is not. Currently we do
@@ -794,8 +794,11 @@ clear_addressable_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
make sense to do it before early optimizations. */
bool
-ipa_discover_readonly_nonaddressable_vars (void)
+ipa_discover_variable_flags (void)
{
+ if (!flag_ipa_reference_addressable)
+ return false;
+
bool remove_p = false;
varpool_node *vnode;
if (dump_file)
diff --git a/gcc/opts.c b/gcc/opts.c
index b98a0ca73a8..04dfc137ecd 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -451,6 +451,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_freorder_blocks, NULL, 1 },
@@ -696,6 +697,148 @@ 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_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. */
@@ -1043,6 +1186,18 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
if (opts->x_align_labels > MAX_CODE_ALIGN_VALUE)
error_at (loc, "-falign-labels=%d is not between 0 and %d",
opts->x_align_labels, MAX_CODE_ALIGN_VALUE);
+
+ /* 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..bde3d2ed81c
--- /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-optimized" } */
+
+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" } } */