On Fri, Sep 4, 2026 at 4:57 AM <[email protected]> wrote:
>
> 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.

part of this is PR 127185.

>
> 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