From: Kyrylo Tkachov <[email protected]>
set_mem_attributes derives MEM_NOTRAP from tree_could_trap_p. That
predicate describes a load. A store to readonly or otherwise unwritable
memory can therefore be marked as nontrapping. RTL exception analysis can
then omit an edge for a store that can raise a non-call exception.
For example, the asm output in the test was marked nontrapping:
(set (mem/u/c:SI (...) [ output+0 ]) ...)
Use store trap semantics for it instead:
(set (mem/u:SI (...) [ output+0 ]) ...)
Add MAY_STORE_P to the memory attribute setters and use
lhs_could_trap_p when it is true. Default MAY_STORE_P to true so that an
unclassified caller cannot create an unsafe nontrapping claim.
EXPAND_NORMAL is the only expand modifier that guarantees that a memory
reference describes a load. Treat the other modifiers conservatively.
This includes EXPAND_STACK_PARM and the direction-neutral EXPAND_MEMORY.
Recompute MEM_NOTRAP on copied declaration RTL so that a normal load keeps
the nontrapping form:
(mem/u/c:SI (...) [ output+0 ])
This can lose MEM_NOTRAP precision for loads expanded with a
direction-neutral modifier. A separate patch restores that precision where
get_memory_rtx knows the access direction.
Bootstrapped and tested on aarch64-unknown-linux-gnu. Tested on
x86_64-pc-linux-gnu.
PR middle-end/127185
gcc/ChangeLog:
* emit-rtl.cc (set_mem_attributes_minus_bitpos): Add MAY_STORE_P.
Use lhs_could_trap_p when it is true.
(set_mem_attributes): Add MAY_STORE_P and pass it through.
* emit-rtl.h (set_mem_attributes): Add MAY_STORE_P with a
conservative default.
(set_mem_attributes_minus_bitpos): Likewise.
* expr.cc (expand_assignment): Mark the destination as a store.
(expand_expr_real_1): Treat only EXPAND_NORMAL as a known load.
Set MEM_NOTRAP from the access direction.
gcc/testsuite/ChangeLog:
* g++.dg/eh/noncall-store-2.C: New test.
* g++.dg/opt/mem-notrap-store-asm.C: New test.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/emit-rtl.cc | 12 +++---
gcc/emit-rtl.h | 11 ++++--
gcc/expr.cc | 20 +++++++---
gcc/testsuite/g++.dg/eh/noncall-store-2.C | 39 +++++++++++++++++++
.../g++.dg/opt/mem-notrap-store-asm.C | 23 +++++++++++
5 files changed, 91 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/eh/noncall-store-2.C
create mode 100644 gcc/testsuite/g++.dg/opt/mem-notrap-store-asm.C
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index 4a23eaefe02..87e13685867 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -1959,11 +1959,12 @@ get_mem_align_offset (rtx mem, unsigned int align)
/* Given REF (a MEM) and T, either the type of X or the expression
corresponding to REF, set the memory attributes. OBJECTP is nonzero
if we are making a new object of this type. BITPOS is nonzero if
- there is an offset outstanding on T that will be applied later. */
+ there is an offset outstanding on T that will be applied later.
+ MAY_STORE_P is true when REF can be the destination of a store. */
void
set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
- poly_int64 bitpos)
+ poly_int64 bitpos, bool may_store_p)
{
poly_int64 apply_bitpos = 0;
tree type;
@@ -2059,7 +2060,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int
objectp,
t = TREE_OPERAND (t, 0);
/* Note whether this expression can trap. */
- MEM_NOTRAP_P (ref) = !tree_could_trap_p (t);
+ MEM_NOTRAP_P (ref)
+ = !(may_store_p ? lhs_could_trap_p (t) : tree_could_trap_p (t));
base = get_base_address (t);
if (base)
@@ -2191,9 +2193,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int
objectp,
}
void
-set_mem_attributes (rtx ref, tree t, int objectp)
+set_mem_attributes (rtx ref, tree t, int objectp, bool may_store_p)
{
- set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
+ set_mem_attributes_minus_bitpos (ref, t, objectp, 0, may_store_p);
}
/* Set the alias set of MEM to SET. */
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 0b572580a98..5fae3264cb5 100644
--- a/gcc/emit-rtl.h
+++ b/gcc/emit-rtl.h
@@ -552,13 +552,16 @@ extern rtx offset_address (rtx, rtx, unsigned
HOST_WIDE_INT);
/* Given REF, a MEM, and T, either the type of X or the expression
corresponding to REF, set the memory attributes. OBJECTP is nonzero
- if we are making a new object of this type. */
-extern void set_mem_attributes (rtx, tree, int);
+ if we are making a new object of this type. MAY_STORE_P is true when REF
+ can be the destination of a store. */
+extern void set_mem_attributes (rtx, tree, int, bool = true);
/* Similar, except that BITPOS has not yet been applied to REF, so if
we alter MEM_OFFSET according to T then we should subtract BITPOS
- expecting that it'll be added back in later. */
-extern void set_mem_attributes_minus_bitpos (rtx, tree, int, poly_int64);
+ expecting that it'll be added back in later. MAY_STORE_P is true when REF
+ can be the destination of a store. */
+extern void set_mem_attributes_minus_bitpos (rtx, tree, int, poly_int64,
+ bool = true);
/* Return OFFSET if XEXP (MEM, 0) - OFFSET is known to be ALIGN
bits aligned for 0 <= OFFSET < ALIGN / BITS_PER_UNIT, or
diff --git a/gcc/expr.cc b/gcc/expr.cc
index e09dab95953..ff4aea8922a 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -64,6 +64,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "rtx-vector-builder.h"
#include "tree-pretty-print.h"
+#include "tree-eh.h"
#include "flags.h"
#include "internal-fn.h"
#include "gimple-range.h"
@@ -6328,7 +6329,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
/* If the field is at offset zero, we could have been given the
DECL_RTX of the parent struct. Don't munge it. */
to_rtx = shallow_copy_rtx (to_rtx);
- set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
+ set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos, true);
if (volatilep)
MEM_VOLATILE_P (to_rtx) = 1;
}
@@ -11522,6 +11523,10 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
tree ssa_name = NULL_TREE;
gimple *g;
+ /* EXPAND_NORMAL is the only modifier that guarantees that a memory
+ reference describes a load. Use store semantics otherwise. */
+ const bool may_store_p = modifier != EXPAND_NORMAL;
+
/* Some ABIs define padding bits in _BitInt uninitialized. Normally, RTL
expansion sign/zero extends integral types with less than mode precision
when reading from bit-fields and after arithmetic operations (see
@@ -11759,6 +11764,11 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
else
decl_rtl = copy_rtx (decl_rtl);
+ if (exp && MEM_P (decl_rtl))
+ MEM_NOTRAP_P (decl_rtl)
+ = !(may_store_p
+ ? lhs_could_trap_p (exp) : tree_could_trap_p (exp));
+
/* Record writes to register variables. */
if (modifier == EXPAND_WRITE
&& REG_P (decl_rtl)
@@ -12077,7 +12087,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
op0 = addr_for_mem_ref (exp, as, true);
op0 = memory_address_addr_space (mode, op0, as);
temp = gen_rtx_MEM (mode, op0);
- set_mem_attributes (temp, exp, 0);
+ set_mem_attributes (temp, exp, 0, may_store_p);
set_mem_addr_space (temp, as);
align = get_object_alignment (exp);
if (modifier != EXPAND_WRITE
@@ -12164,7 +12174,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
op0 = memory_address_addr_space (mode, op0, as);
}
temp = gen_rtx_MEM (mode, op0);
- set_mem_attributes (temp, exp, 0);
+ set_mem_attributes (temp, exp, 0, may_store_p);
set_mem_addr_space (temp, as);
if (TREE_THIS_VOLATILE (exp))
MEM_VOLATILE_P (temp) = 1;
@@ -12733,7 +12743,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
we should just honor its original memory attributes. */
if (!(TREE_CODE (tem) == SSA_NAME
&& (MEM_P (orig_op0) || CONSTANT_P (orig_op0))))
- set_mem_attributes (op0, exp, 0);
+ set_mem_attributes (op0, exp, 0, may_store_p);
if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
@@ -12865,7 +12875,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode
tmode,
if (op0 == orig_op0)
op0 = copy_rtx (op0);
- set_mem_attributes (op0, treeop0, 0);
+ set_mem_attributes (op0, treeop0, 0, may_store_p);
if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
diff --git a/gcc/testsuite/g++.dg/eh/noncall-store-2.C
b/gcc/testsuite/g++.dg/eh/noncall-store-2.C
new file mode 100644
index 00000000000..c095c71ca93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/noncall-store-2.C
@@ -0,0 +1,39 @@
+// Direct stores through reference and this parameters can throw non-call
+// exceptions.
+
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions -fdump-rtl-expand" }
+
+void
+store_ref (int &value)
+{
+ try
+ {
+ value = 1;
+ }
+ catch (...)
+ {
+ __builtin_trap ();
+ }
+}
+
+struct S
+{
+ int value;
+ void store ();
+};
+
+void
+S::store ()
+{
+ try
+ {
+ value = 1;
+ }
+ catch (...)
+ {
+ __builtin_trap ();
+ }
+}
+
+// { dg-final { scan-rtl-dump-times {REG_EH_REGION \(const_int [1-9][0-9]*} 2
"expand" } }
diff --git a/gcc/testsuite/g++.dg/opt/mem-notrap-store-asm.C
b/gcc/testsuite/g++.dg/opt/mem-notrap-store-asm.C
new file mode 100644
index 00000000000..ef26e228331
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/mem-notrap-store-asm.C
@@ -0,0 +1,23 @@
+// Keep a normal load nontrapping. A memory asm output is a store even when
+// expansion must return a MEM.
+
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions -fdump-rtl-expand" }
+
+extern const int output;
+
+int
+load ()
+{
+ return output;
+}
+
+void
+store ()
+{
+ asm volatile ("" : "=m" (const_cast<int &> (output)));
+}
+
+// { dg-final { scan-rtl-dump {\(mem(?:/[a-z])*/c(?:/[a-z])*:[^\n\r]*\[[0-9]+
output\+0} "expand" } }
+// { dg-final { scan-rtl-dump {\(set[ \t\n]+\(mem(?:/[a-z])*:[^\n\r]*\[[0-9]+
output\+0} "expand" } }
+// { dg-final { scan-rtl-dump-not {\(set[
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:[^\n\r]*\[[0-9]+ output\+0} "expand" } }
--
2.50.1 (Apple Git-155)