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.

Pass the access direction through set_mem_attributes and use
lhs_could_trap_p for stores.  Propagate store semantics from EXPAND_WRITE,
assignment destinations, and built-in string destinations.  Make every
get_memory_rtx caller state its access direction.

Some expanders use EXPAND_MEMORY because they require a MEM result.  Apply
store semantics explicitly to asm outputs and to destination copies of strub
watermarks.  The partial-load expander instead used EXPAND_WRITE for a load,
so use EXPAND_MEMORY there.

Bootstrapped and tested on aarch64-unknown-linux-gnu.  Tested on
x86_64-pc-linux-gnu.

gcc/ChangeLog:

        * builtins.cc (get_memory_rtx): Add STORE_P.  Pass it to
        set_mem_attributes.
        (expand_builtin_memory_copy_args): Mark destination memory as a store
        and source memory as a load.
        (expand_movstr): Likewise.
        (expand_builtin_strncpy): Likewise.
        (expand_builtin_memset_args): Likewise.
        (expand_builtin_memcmp): Mark both memory operands as loads.
        (expand_builtin_strcmp): Likewise.
        (expand_builtin_strncmp): Likewise.
        (expand_builtin_strub_enter): Expand the watermark as a store.
        (expand_builtin_strub_update): Apply store semantics to destination
        copies of the watermark.
        (inline_string_cmp): Mark the memory operand as a load.
        * builtins.h (get_memory_rtx): Add STORE_P.
        * cfgexpand.cc (expand_asm_stmt): Apply store semantics to memory
        outputs.
        * emit-rtl.cc (set_mem_attributes_minus_bitpos): Add STORE_P.  Use
        lhs_could_trap_p for stores.
        (set_mem_attributes): Add STORE_P and pass it through.
        * emit-rtl.h (set_mem_attributes): Add STORE_P.
        (set_mem_attributes_minus_bitpos): Likewise.
        * expr.cc (expand_assignment): Mark destination memory as a store.
        (expand_expr_real_1): Use lhs_could_trap_p for store MEMs.  Pass the
        access direction to memory attribute generation.
        * internal-fn.cc (expand_partial_load_optab_fn): Expand the source as
        memory, not as a store.
        (expand_RAWMEMCHR): Mark the memory operand as a load.

gcc/testsuite/ChangeLog:

        * g++.dg/eh/noncall-store-2.C: New test.
        * g++.dg/opt/mem-notrap-store-asm.C: New test.
        * g++.dg/opt/mem-notrap-store-builtin.C: New test.
        * gcc.target/i386/mem-notrap-mask-load.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/builtins.cc                               | 46 +++++++++++--------
 gcc/builtins.h                                |  2 +-
 gcc/cfgexpand.cc                              |  5 +-
 gcc/emit-rtl.cc                               | 12 +++--
 gcc/emit-rtl.h                                | 11 +++--
 gcc/expr.cc                                   | 15 ++++--
 gcc/internal-fn.cc                            |  4 +-
 gcc/testsuite/g++.dg/eh/noncall-store-2.C     | 39 ++++++++++++++++
 .../g++.dg/opt/mem-notrap-store-asm.C         | 15 ++++++
 .../g++.dg/opt/mem-notrap-store-builtin.C     | 22 +++++++++
 .../gcc.target/i386/mem-notrap-mask-load.c    | 23 ++++++++++
 11 files changed, 156 insertions(+), 38 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
 create mode 100644 gcc/testsuite/g++.dg/opt/mem-notrap-store-builtin.C
 create mode 100644 gcc/testsuite/gcc.target/i386/mem-notrap-mask-load.c

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 056fd20c4c6..d9471340e30 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "memmodel.h"
 #include "gimple.h"
+#include "tree-eh.h"
 #include "predict.h"
 #include "tm_p.h"
 #include "stringpool.h"
@@ -1364,10 +1365,10 @@ expand_builtin_prefetch (tree exp)
 /* Get a MEM rtx for expression EXP which is the address of an operand
    to be used in a string instruction (cmpstrsi, cpymemsi, ..).  LEN is
    the maximum length of the block of memory that might be accessed or
-   NULL if unknown.  */
+   NULL if unknown.  STORE_P is true when EXP is the destination.  */
 
 rtx
-get_memory_rtx (tree exp, tree len)
+get_memory_rtx (tree exp, tree len, bool store_p)
 {
   tree orig_exp = exp, base;
   rtx addr, mem;
@@ -1401,7 +1402,7 @@ get_memory_rtx (tree exp, tree len)
      from the original address we got, and build an all-aliasing
      unknown-sized access to that one.  */
   if (is_gimple_mem_ref_addr (TREE_OPERAND (exp, 0)))
-    set_mem_attributes (mem, exp, 0);
+    set_mem_attributes (mem, exp, 0, store_p);
   else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
           && (base = get_base_address (TREE_OPERAND (TREE_OPERAND (exp, 0),
                                                      0))))
@@ -1414,7 +1415,7 @@ get_memory_rtx (tree exp, tree len)
                                                             size_zero_node,
                                                             NULL)),
                         exp, build_int_cst (ptr_type_node, 0));
-      set_mem_attributes (mem, exp, 0);
+      set_mem_attributes (mem, exp, 0, store_p);
       /* Since we stripped parts make sure the offset is unknown and the
         alignment is computed from the original address.  */
       clear_mem_offset (mem);
@@ -3770,7 +3771,7 @@ expand_builtin_memory_copy_args (tree dest, tree src, 
tree len,
 
   if (expected_align < dest_align)
     expected_align = dest_align;
-  dest_mem = get_memory_rtx (dest, len);
+  dest_mem = get_memory_rtx (dest, len, true);
   set_mem_align (dest_mem, dest_align);
   len_rtx = expand_normal (len);
   determine_block_size (len, len_rtx, &min_size, &max_size,
@@ -3804,7 +3805,7 @@ expand_builtin_memory_copy_args (tree dest, tree src, 
tree len,
       return dest_mem;
     }
 
-  src_mem = get_memory_rtx (src, len);
+  src_mem = get_memory_rtx (src, len, false);
   set_mem_align (src_mem, src_align);
 
   /* Copy word part most expediently.  */
@@ -3873,8 +3874,8 @@ expand_movstr (tree dest, tree src, rtx target, memop_ret 
retmode)
   if (!targetm.have_movstr ())
     return NULL_RTX;
 
-  dest_mem = get_memory_rtx (dest, NULL);
-  src_mem = get_memory_rtx (src, NULL);
+  dest_mem = get_memory_rtx (dest, NULL, true);
+  src_mem = get_memory_rtx (src, NULL, false);
   if (retmode == RETURN_BEGIN)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
@@ -4150,7 +4151,7 @@ expand_builtin_strncpy (tree exp, rtx target)
                                   dest_align, false))
        return NULL_RTX;
 
-      dest_mem = get_memory_rtx (dest, len);
+      dest_mem = get_memory_rtx (dest, len, true);
       store_by_pieces (dest_mem, tree_to_uhwi (len),
                       builtin_strncpy_read_str,
                       const_cast<char *> (p), dest_align, false,
@@ -4709,7 +4710,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   len_rtx = expand_normal (len);
   determine_block_size (len, len_rtx, &min_size, &max_size,
                        &probable_max_size);
-  dest_mem = get_memory_rtx (dest, len);
+  dest_mem = get_memory_rtx (dest, len, true);
   val_mode = TYPE_MODE (unsigned_char_type_node);
 
   if (TREE_CODE (val) != INTEGER_CST
@@ -4893,8 +4894,8 @@ expand_builtin_memcmp (tree exp, rtx target, bool 
result_eq)
   if (arg1_align == 0 || arg2_align == 0)
     return NULL_RTX;
 
-  rtx arg1_rtx = get_memory_rtx (arg1, len);
-  rtx arg2_rtx = get_memory_rtx (arg2, len);
+  rtx arg1_rtx = get_memory_rtx (arg1, len, false);
+  rtx arg2_rtx = get_memory_rtx (arg2, len, false);
   rtx len_rtx = expand_normal (fold_convert_loc (loc, sizetype, len));
 
   /* Set MEM_SIZE as appropriate.  */
@@ -4987,8 +4988,8 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx 
target)
   arg1 = builtin_save_expr (arg1);
   arg2 = builtin_save_expr (arg2);
 
-  rtx arg1_rtx = get_memory_rtx (arg1, NULL);
-  rtx arg2_rtx = get_memory_rtx (arg2, NULL);
+  rtx arg1_rtx = get_memory_rtx (arg1, NULL, false);
+  rtx arg2_rtx = get_memory_rtx (arg2, NULL, false);
 
   /* Try to call cmpstrsi.  */
   if (cmpstr_icode != CODE_FOR_nothing)
@@ -5144,8 +5145,8 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx 
target,
       len = fold_convert_loc (loc, sizetype, len);
       len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
     }
-  rtx arg1_rtx = get_memory_rtx (arg1, len);
-  rtx arg2_rtx = get_memory_rtx (arg2, len);
+  rtx arg1_rtx = get_memory_rtx (arg1, len, false);
+  rtx arg2_rtx = get_memory_rtx (arg2, len, false);
   rtx arg3_rtx = expand_normal (len);
   result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
                                     arg2_rtx, TREE_TYPE (len), arg3_rtx,
@@ -5545,7 +5546,7 @@ expand_builtin_strub_enter (tree exp)
   tree wmtype = TREE_TYPE (TREE_TYPE (wmptr));
   tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr,
                             build_int_cst (TREE_TYPE (wmptr), 0));
-  rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY);
+  rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_WRITE);
 
   emit_move_insn (wmark, stktop);
 
@@ -5623,7 +5624,9 @@ expand_builtin_strub_update (tree exp)
   do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
                           ptr_mode, NULL_RTX, lab, NULL,
                           profile_probability::very_likely ());
-  emit_move_insn (wmark, stktop);
+  rtx wmark_store = shallow_copy_rtx (wmark);
+  MEM_NOTRAP_P (wmark_store) = !lhs_could_trap_p (wmtree);
+  emit_move_insn (wmark_store, stktop);
 
   /* If this is an inlined strub function, also bump the watermark for the
      enclosing function.  This avoids a problem with the following scenario: A
@@ -5647,7 +5650,9 @@ expand_builtin_strub_update (tree exp)
       do_compare_rtx_and_jump (stktop, wmarkr, STACK_TOPS, STACK_UNSIGNED,
                               ptr_mode, NULL_RTX, lab, NULL,
                               profile_probability::very_likely ());
-      emit_move_insn (wmark, stktop);
+      wmark_store = shallow_copy_rtx (wmark);
+      MEM_NOTRAP_P (wmark_store) = !lhs_could_trap_p (wmtree);
+      emit_move_insn (wmark_store, stktop);
     }
 
   emit_label (lab);
@@ -7602,7 +7607,8 @@ inline_string_cmp (rtx target, tree var_str, const char 
*const_str,
 {
   HOST_WIDE_INT offset = 0;
   rtx var_rtx_array
-    = get_memory_rtx (var_str, build_int_cst (unsigned_type_node,length));
+    = get_memory_rtx (var_str, build_int_cst (unsigned_type_node, length),
+                     false);
   rtx var_rtx = NULL_RTX;
   rtx const_rtx = NULL_RTX;
   rtx result = target ? target : gen_reg_rtx (mode);
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 9cca88c647c..97b79908d0d 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -162,7 +162,7 @@ extern char target_percent_s[3];
 extern char target_percent_c[3];
 extern char target_percent_s_newline[4];
 extern bool target_char_cst_p (tree t, char *p);
-extern rtx get_memory_rtx (tree exp, tree len);
+extern rtx get_memory_rtx (tree exp, tree len, bool store_p);
 
 extern internal_fn associated_internal_fn (combined_fn, tree);
 extern internal_fn associated_internal_fn (tree);
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 245ba357b5e..7256c5235aa 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -3688,7 +3688,10 @@ expand_asm_stmt (gasm *stmt)
          op = expand_expr (val, NULL_RTX, VOIDmode,
                            !allows_reg ? EXPAND_MEMORY : EXPAND_WRITE);
          if (MEM_P (op))
-           op = validize_mem (op);
+           {
+             op = validize_mem (op);
+             MEM_NOTRAP_P (op) = !lhs_could_trap_p (val);
+           }
 
          if (! allows_reg && !MEM_P (op))
            {
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index 4a23eaefe02..8eb42c4facc 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.  STORE_P
+   is true when REF is the destination of a store.  */
 
 void
 set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
-                                poly_int64 bitpos)
+                                poly_int64 bitpos, bool 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)
+       = !(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 store_p)
 {
-  set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
+  set_mem_attributes_minus_bitpos (ref, t, objectp, 0, store_p);
 }
 
 /* Set the alias set of MEM to SET.  */
diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h
index 0b572580a98..f50db283657 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.  STORE_P is true when REF is
+   the destination of a store.  */
+extern void set_mem_attributes (rtx, tree, int, bool = false);
 
 /* 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.  STORE_P is true when REF is
+   the destination of a store.  */
+extern void set_mem_attributes_minus_bitpos (rtx, tree, int, poly_int64,
+                                    bool = false);
 
 /* 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 feaa8e90470..fd735ac8f93 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;
            }
@@ -11759,6 +11760,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode 
tmode,
       else
        decl_rtl = copy_rtx (decl_rtl);
 
+      if (exp && MEM_P (decl_rtl) && modifier == EXPAND_WRITE)
+       MEM_NOTRAP_P (decl_rtl) = !lhs_could_trap_p (exp);
+
       /* Record writes to register variables.  */
       if (modifier == EXPAND_WRITE
          && REG_P (decl_rtl)
@@ -12077,7 +12081,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, modifier == EXPAND_WRITE);
        set_mem_addr_space (temp, as);
        align = get_object_alignment (exp);
        if (modifier != EXPAND_WRITE
@@ -12164,7 +12168,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, modifier == EXPAND_WRITE);
        set_mem_addr_space (temp, as);
        if (TREE_THIS_VOLATILE (exp))
          MEM_VOLATILE_P (temp) = 1;
@@ -12733,7 +12737,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, modifier == EXPAND_WRITE);
 
        if (REG_P (XEXP (op0, 0)))
          mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
@@ -12865,7 +12869,8 @@ 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,
+                                   modifier == EXPAND_WRITE);
                if (REG_P (XEXP (op0, 0)))
                  mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 0138c6f7ef0..ceddc3787c0 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -3144,7 +3144,7 @@ expand_partial_load_optab_fn (internal_fn ifn, gcall 
*stmt, convert_optab optab)
     icode = convert_optab_handler (optab, TYPE_MODE (type),
                                   TYPE_MODE (TREE_TYPE (maskt)));
 
-  mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+  mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_MEMORY);
   gcc_assert (MEM_P (mem));
   /* The built MEM_REF does not accurately reflect that the load
      is only partial.  Clear it.  */
@@ -3404,7 +3404,7 @@ expand_RAWMEMCHR (internal_fn, gcall *stmt)
   create_call_lhs_operand (&ops[0], lhs_rtx, lhs_mode);
 
   tree mem = gimple_call_arg (stmt, 0);
-  rtx mem_rtx = get_memory_rtx (mem, NULL);
+  rtx mem_rtx = get_memory_rtx (mem, NULL, false);
   create_fixed_operand (&ops[1], mem_rtx);
 
   tree pattern = gimple_call_arg (stmt, 1);
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..9fcd13e9f61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/mem-notrap-store-asm.C
@@ -0,0 +1,15 @@
+// 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;
+
+void
+store ()
+{
+  asm volatile ("" : "=m" (const_cast<int &> (output)));
+}
+
+// { dg-final { scan-rtl-dump {\(set[ \t\n]+\(mem(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-rtl-dump-not {\(set[ 
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:} "expand" } }
diff --git a/gcc/testsuite/g++.dg/opt/mem-notrap-store-builtin.C 
b/gcc/testsuite/g++.dg/opt/mem-notrap-store-builtin.C
new file mode 100644
index 00000000000..a048648784a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/mem-notrap-store-builtin.C
@@ -0,0 +1,22 @@
+// Keep an inline memcpy source nontrapping, but not its destination.
+
+// { dg-do compile }
+// { dg-options "-O2 -fnon-call-exceptions -finline-stringops=memcpy 
-fdump-rtl-expand" }
+// { dg-require-effective-target ptr32plus }
+
+typedef unsigned char block[16384];
+
+extern const block destination;
+extern block source;
+
+void
+copy ()
+{
+  __builtin_memcpy (const_cast<unsigned char *> (destination), source,
+                   sizeof (block));
+}
+
+// { dg-final { scan-rtl-dump {\(mem(?:/[a-z])*/c(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-rtl-dump {\(set[ \t\n]+\(mem(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-rtl-dump-not {\(set[ 
\t\n]+\(mem(?:/[a-z])*/c(?:/[a-z])*:} "expand" } }
+// { dg-final { scan-assembler-not {\mmemcpy\M} } }
diff --git a/gcc/testsuite/gcc.target/i386/mem-notrap-mask-load.c 
b/gcc/testsuite/gcc.target/i386/mem-notrap-mask-load.c
new file mode 100644
index 00000000000..bc510e6ad4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mem-notrap-mask-load.c
@@ -0,0 +1,23 @@
+/* A masked load is a read even though its expander requires a MEM.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -fgimple -mavx2 -mno-avx512f -fnon-call-exceptions 
-fdump-tree-optimized -fdump-rtl-expand" } */
+
+typedef int v4si __attribute__ ((vector_size (16)));
+
+extern const v4si values;
+
+v4si __GIMPLE (ssa)
+load (v4si mask)
+{
+  v4si result;
+
+  __BB(2):
+  result_2 = .MASK_LOAD (&values, _Literal (v4si *) 128,
+                       mask_1(D),
+                       _Literal (v4si) { 0, 0, 0, 0 });
+  return result_2;
+}
+
+/* { dg-final { scan-tree-dump {\.MASK_LOAD} "optimized" } } */
+/* { dg-final { scan-rtl-dump-times {\(mem/u/c:V4SI} 1 "expand" } } */
-- 
2.50.1 (Apple Git-155)

Reply via email to