aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index fa3d10ea2d7..c31eba65542 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -5021,14 +5021,27 @@ store_constructor (exp, target, cleared, size)
{
rtx xtarget = target;
- if (readonly_fields_p (type))
+ if (RTX_UNCHANGING_P (target))
{
- xtarget = copy_rtx (xtarget);
- RTX_UNCHANGING_P (xtarget) = 1;
+ xtarget = copy_rtx (target);
+ RTX_UNCHANGING_P (xtarget) = 0;
}
clear_storage (xtarget, GEN_INT (size));
cleared = 1;
+ if (RTX_UNCHANGING_P (target) || readonly_fields_p (type))
+ {
+ /* ??? Emit a blockage to prevent the scheduler from swapping
+ the memory write issued above without the /u flag and
+ memory writes that will be issued later with it.
+ Note that the clearing above cannot be simply disabled
+ in the unsafe cases because the C front-end relies on
+ it to implement the semantics of constructors for
+ automatic objects. However, not all machine descriptions
+ define a blockage insn, so emit an ASM_INPUT to
+ act as one. */
+ emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+ }
}
if (! cleared)
@@ -5242,9 +5255,28 @@ store_constructor (exp, target, cleared, size)
if (! cleared)
{
if (REG_P (target))
- emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
else
- clear_storage (target, GEN_INT (size));
+ {
+ rtx xtarget = target;
+
+ if (RTX_UNCHANGING_P (target))
+ {
+ xtarget = copy_rtx (target);
+ RTX_UNCHANGING_P (xtarget) = 0;
+ }
+
+ clear_storage (xtarget, GEN_INT (size));
+
+ if (RTX_UNCHANGING_P (target))
+ {
+ /* ??? Emit a blockage to prevent the scheduler from
+ swapping the memory write issued above without the
+ /u flag and memory writes that will be issued later
+ with it. */
+ emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+ }
+ }
}
cleared = 1;
}