Hi!

I've backported from trunk, bootstrapped/regtested on x86_64-linux and
i686-linux and committed to gcc-8-branch the following 6 patches.

        Jakub
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2018-10-19  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/85488
        PR middle-end/87649
        * omp-low.c (check_omp_nesting_restrictions): Diagnose ordered without
        depend closely nested inside of loop with ordered clause with
        a parameter.

        * c-c++-common/gomp/doacross-2.c: New test.
        * c-c++-common/gomp/sink-3.c: Expect another error during error
        recovery.

--- gcc/omp-low.c       (revision 265334)
+++ gcc/omp-low.c       (revision 265335)
@@ -2762,14 +2762,25 @@ check_omp_nesting_restrictions (gimple *
          case GIMPLE_OMP_FOR:
            if (gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_TASKLOOP)
              goto ordered_in_taskloop;
-           if (omp_find_clause (gimple_omp_for_clauses (ctx->stmt),
-                                OMP_CLAUSE_ORDERED) == NULL)
+           tree o;
+           o = omp_find_clause (gimple_omp_for_clauses (ctx->stmt),
+                                OMP_CLAUSE_ORDERED);
+           if (o == NULL)
              {
                error_at (gimple_location (stmt),
                          "%<ordered%> region must be closely nested inside "
                          "a loop region with an %<ordered%> clause");
                return false;
              }
+           if (OMP_CLAUSE_ORDERED_EXPR (o) != NULL_TREE
+               && omp_find_clause (c, OMP_CLAUSE_DEPEND) == NULL_TREE)
+             {
+               error_at (gimple_location (stmt),
+                         "%<ordered%> region without %<depend%> clause may "
+                         "not be closely nested inside a loop region with "
+                         "an %<ordered%> clause with a parameter");
+               return false;
+             }
            return true;
          case GIMPLE_OMP_TARGET:
            if (gimple_omp_target_kind (ctx->stmt)
--- gcc/testsuite/c-c++-common/gomp/sink-3.c    (revision 265334)
+++ gcc/testsuite/c-c++-common/gomp/sink-3.c    (revision 265335)
@@ -14,7 +14,7 @@ foo ()
   for (i=0; i < 100; ++i)
     {
 #pragma omp ordered depend(sink:poo-1,paa+1) /* { dg-error 
"poo.*declared.*paa.*declared" } */
-    bar(&i);
+    bar(&i);                                /* { dg-error "may not be closely 
nested" "" { target *-*-* } .-1 } */
 #pragma omp ordered depend(source)
     }
 }
--- gcc/testsuite/c-c++-common/gomp/doacross-2.c        (nonexistent)
+++ gcc/testsuite/c-c++-common/gomp/doacross-2.c        (revision 265335)
@@ -0,0 +1,49 @@
+/* PR middle-end/87649 */
+
+void
+foo (void)
+{
+  int i;
+  #pragma omp for ordered(1)
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered                      /* { dg-error "'ordered' region 
without 'depend' clause may not be closely nested inside a loop region with an 
'ordered' clause with a parameter" } */
+      ;
+    }
+  #pragma omp for ordered(1)
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered threads              /* { dg-error "'ordered' region 
without 'depend' clause may not be closely nested inside a loop region with an 
'ordered' clause with a parameter" } */
+      ;
+    }
+}
+
+void
+bar (void)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered depend(source)       /* { dg-error "'ordered' 
construct with 'depend' clause must be closely nested inside a loop with 
'ordered' clause with a parameter" } */
+      #pragma omp ordered depend(sink: i - 1)  /* { dg-error "'ordered' 
construct with 'depend' clause must be closely nested inside a loop with 
'ordered' clause with a parameter" } */
+    }
+  #pragma omp for
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered depend(source)       /* { dg-error "'ordered' 
construct with 'depend' clause must be closely nested inside a loop with 
'ordered' clause with a parameter" } */
+      #pragma omp ordered depend(sink: i - 1)  /* { dg-error "'ordered' 
construct with 'depend' clause must be closely nested inside a loop with 
'ordered' clause with a parameter" } */
+    }
+  #pragma omp for
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered                      /* { dg-error "'ordered' region 
must be closely nested inside a loop region with an 'ordered' clause" } */
+      ;
+    }
+  #pragma omp for
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered threads              /* { dg-error "'ordered' region 
must be closely nested inside a loop region with an 'ordered' clause" } */
+      ;
+    }
+}
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2018-10-20  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/87647
        * varasm.c (decode_addr_const): Handle COMPOUND_LITERAL_EXPR.

        * gcc.c-torture/compile/pr87647.c: New test.

--- gcc/varasm.c        (revision 265340)
+++ gcc/varasm.c        (revision 265341)
@@ -2953,6 +2953,11 @@ decode_addr_const (tree exp, struct addr
                       gen_rtx_SYMBOL_REF (Pmode, "origin of addresses"));
       break;
 
+    case COMPOUND_LITERAL_EXPR:
+      gcc_assert (COMPOUND_LITERAL_EXPR_DECL (target));
+      x = DECL_RTL (COMPOUND_LITERAL_EXPR_DECL (target));
+      break;
+
     default:
       gcc_unreachable ();
     }
--- gcc/testsuite/gcc.c-torture/compile/pr87647.c       (nonexistent)
+++ gcc/testsuite/gcc.c-torture/compile/pr87647.c       (revision 265341)
@@ -0,0 +1,15 @@
+/* PR middle-end/87647 */
+
+struct A {};
+struct A *const b = &(struct A) {};
+struct B { char *s; struct A *t; };
+void bar (struct B *);
+
+void
+foo (void)
+{
+  struct B a[] = { "", b, "", b, "", b, "", b, "", b, "", b, "", b, "", b,
+                  "", b, "", b, "", b, "", b, "", b, "", b, "", b, "", b,
+                  "", b };
+  bar (a);
+}
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2018-10-24  Jakub Jelinek  <ja...@redhat.com>

        PR c++/86288
        * parser.c (cp_parser_std_attribute): Canonicalize attr_ns, and when
        :: is not present and attr_ns non-NULL, canonicalize also attr_id.
        (cp_parser_attribute_spec): Fix comment typo.

        * g++.dg/cpp0x/gen-attrs-66.C: New test.

--- gcc/cp/parser.c     (revision 265469)
+++ gcc/cp/parser.c     (revision 265470)
@@ -25327,14 +25327,19 @@ cp_parser_std_attribute (cp_parser *pars
          return error_mark_node;
        }
 
+      attr_ns = canonicalize_attr_name (attr_ns);
       attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
                                   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
     }
   else if (attr_ns)
-    attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
-                                NULL_TREE);
+    {
+      attr_ns = canonicalize_attr_name (attr_ns);
+      attr_id = canonicalize_attr_name (attr_id);
+      attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
+                                  NULL_TREE);
+    }
   else
     {
       attr_id = canonicalize_attr_name (attr_id);
@@ -25526,7 +25531,7 @@ cp_parser_std_attribute_spec (cp_parser
          || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE))
        cp_parser_skip_to_end_of_statement (parser);
       else
-       /* Warn about parsing c++11 attribute in non-c++1 mode, only
+       /* Warn about parsing c++11 attribute in non-c++11 mode, only
           when we are sure that we have actually parsed them.  */
        maybe_warn_cpp0x (CPP0X_ATTRIBUTES);
     }
--- gcc/testsuite/g++.dg/cpp0x/gen-attrs-66.C   (nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-66.C   (revision 265470)
@@ -0,0 +1,12 @@
+// PR c++/86288
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wattributes" }
+
+int a [[gnu::aligned(alignof(int))]];
+int b [[gnu::__aligned__(alignof(int))]];
+int c [[__gnu__::aligned(alignof(int))]];
+int d [[__gnu__::__aligned__(alignof(int))]];
+int e [[using gnu : aligned(alignof(int))]];           // { dg-warning 
"attribute using prefix only available" "" { target c++14_down } }
+int f [[using gnu : __aligned__(alignof(int))]];       // { dg-warning 
"attribute using prefix only available" "" { target c++14_down } }
+int g [[using __gnu__ : aligned(alignof(int))]];       // { dg-warning 
"attribute using prefix only available" "" { target c++14_down } }
+int h [[using __gnu__ : __aligned__(alignof(int))]];   // { dg-warning 
"attribute using prefix only available" "" { target c++14_down } }
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2018-10-25  Jakub Jelinek  <ja...@redhat.com>

        PR fortran/87725
        * openmp.c (gfc_match_omp_clauses): Parse simd, monotonic and
        nonmonotonic modifiers regardless of if they have been parsed
        already or if the opposite one has.  Fix up check whether
        comma after modifier should be parsed.
        (resolve_omp_clauses): Diagnose schedule modifier restrictions.

        * c-c++-common/gomp/schedule-modifiers-1.c (bar): Separate modifier
        from kind with a colon rather than comma.
        * gfortran.dg/gomp/schedule-modifiers-1.f90: New test.
        * gfortran.dg/gomp/schedule-modifiers-2.f90: New test.

--- gcc/fortran/openmp.c        (revision 265478)
+++ gcc/fortran/openmp.c        (revision 265479)
@@ -1710,22 +1710,17 @@ gfc_match_omp_clauses (gfc_omp_clauses *
              locus old_loc2 = gfc_current_locus;
              do
                {
-                 if (!c->sched_simd
-                     && gfc_match ("simd") == MATCH_YES)
+                 if (gfc_match ("simd") == MATCH_YES)
                    {
                      c->sched_simd = true;
                      nmodifiers++;
                    }
-                 else if (!c->sched_monotonic
-                          && !c->sched_nonmonotonic
-                          && gfc_match ("monotonic") == MATCH_YES)
+                 else if (gfc_match ("monotonic") == MATCH_YES)
                    {
                      c->sched_monotonic = true;
                      nmodifiers++;
                    }
-                 else if (!c->sched_monotonic
-                          && !c->sched_nonmonotonic
-                          && gfc_match ("nonmonotonic") == MATCH_YES)
+                 else if (gfc_match ("nonmonotonic") == MATCH_YES)
                    {
                      c->sched_nonmonotonic = true;
                      nmodifiers++;
@@ -1736,7 +1731,7 @@ gfc_match_omp_clauses (gfc_omp_clauses *
                        gfc_current_locus = old_loc2;
                      break;
                    }
-                 if (nmodifiers == 0
+                 if (nmodifiers == 1
                      && gfc_match (" , ") == MATCH_YES)
                    continue;
                  else if (gfc_match (" : ") == MATCH_YES)
@@ -4075,6 +4070,30 @@ resolve_omp_clauses (gfc_code *code, gfc
        gfc_warning (0, "INTEGER expression of SCHEDULE clause's chunk_size "
                     "at %L must be positive", &expr->where);
     }
+  if (omp_clauses->sched_kind != OMP_SCHED_NONE
+      && omp_clauses->sched_nonmonotonic)
+    {
+      if (omp_clauses->sched_kind != OMP_SCHED_DYNAMIC
+         && omp_clauses->sched_kind != OMP_SCHED_GUIDED)
+       {
+         const char *p;
+         switch (omp_clauses->sched_kind)
+           {
+           case OMP_SCHED_STATIC: p = "STATIC"; break;
+           case OMP_SCHED_RUNTIME: p = "RUNTIME"; break;
+           case OMP_SCHED_AUTO: p = "AUTO"; break;
+           default: gcc_unreachable ();
+           }
+         gfc_error ("NONMONOTONIC modifier specified for %s schedule kind "
+                    "at %L", p, &code->loc);
+       }
+      else if (omp_clauses->sched_monotonic)
+       gfc_error ("Both MONOTONIC and NONMONOTONIC schedule modifiers "
+                  "specified at %L", &code->loc);
+      else if (omp_clauses->ordered)
+       gfc_error ("NONMONOTONIC schedule modifier specified with ORDERED "
+                  "clause at %L", &code->loc);
+    }
 
   /* Check that no symbol appears on multiple clauses, except that
      a symbol can appear on both firstprivate and lastprivate.  */
--- gcc/testsuite/c-c++-common/gomp/schedule-modifiers-1.c      (revision 
265478)
+++ gcc/testsuite/c-c++-common/gomp/schedule-modifiers-1.c      (revision 
265479)
@@ -80,21 +80,21 @@ bar (void)
   #pragma omp for schedule (nonmonotonic : auto)       /* { dg-error 
".nonmonotonic. modifier specified for .auto. schedule kind" } */
   for (i = 0; i < 64; i++)
     ;
-  #pragma omp for schedule (nonmonotonic, dynamic) ordered     /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
+  #pragma omp for schedule (nonmonotonic : dynamic) ordered    /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
   for (i = 0; i < 64; i++)
     #pragma omp ordered
       ;
-  #pragma omp for ordered schedule(nonmonotonic, dynamic, 5)   /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
+  #pragma omp for ordered schedule(nonmonotonic : dynamic, 5)  /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
   for (i = 0; i < 64; i++)
     #pragma omp ordered
       ;
-  #pragma omp for schedule (nonmonotonic, guided) ordered(1)   /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
+  #pragma omp for schedule (nonmonotonic : guided) ordered(1)  /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
   for (i = 0; i < 64; i++)
     {
       #pragma omp ordered depend(sink: i - 1)
       #pragma omp ordered depend(source)
     }
-  #pragma omp for ordered(1) schedule(nonmonotonic, guided, 2) /* { dg-error 
".nonmonotonic. schedule modifier specified together with .ordered. clause" } */
+  #pragma omp for ordered(1) schedule(nonmonotonic : guided, 2)        /* { 
dg-error ".nonmonotonic. schedule modifier specified together with .ordered. 
clause" } */
   for (i = 0; i < 64; i++)
     {
       #pragma omp ordered depend(source)
--- gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-1.f90     (nonexistent)
+++ gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-1.f90     (revision 
265479)
@@ -0,0 +1,63 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+subroutine foo
+  integer :: i
+  !$omp do simd schedule (simd, simd: static, 5)
+  do i = 0, 64
+  end do
+  !$omp do simd schedule (monotonic, simd: static)
+  do i = 0, 64
+  end do
+  !$omp do simd schedule (simd , monotonic : static, 6)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic, monotonic : static, 7)
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic, nonmonotonic : dynamic)
+  do i = 0, 64
+  end do
+  !$omp do simd schedule (nonmonotonic , simd : dynamic, 3)
+  do i = 0, 64
+  end do
+  !$omp do simd schedule (nonmonotonic,simd:guided,4)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic: static, 2)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : static)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : dynamic)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : dynamic, 3)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : guided)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : guided, 7)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : runtime)
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic : auto)
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : dynamic)
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : dynamic, 3)
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : guided)
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : guided, 7)
+  do i = 0, 64
+  end do
+end subroutine foo
--- gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90     (nonexistent)
+++ gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90     (revision 
265479)
@@ -0,0 +1,44 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+subroutine foo
+  integer :: i
+  !$omp do schedule (nonmonotonic: static, 2)  ! { dg-error "NONMONOTONIC 
modifier specified for STATIC schedule kind" }
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : static)    ! { dg-error "NONMONOTONIC 
modifier specified for STATIC schedule kind" }
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : runtime)   ! { dg-error "NONMONOTONIC 
modifier specified for RUNTIME schedule kind" }
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : auto)      ! { dg-error "NONMONOTONIC 
modifier specified for AUTO schedule kind" }
+  do i = 0, 64
+  end do
+  !$omp do schedule (nonmonotonic : dynamic) ordered   ! { dg-error 
"NONMONOTONIC schedule modifier specified with ORDERED clause" }
+  do i = 0, 64
+    !$omp ordered
+    !$omp end ordered
+  end do
+  !$omp do ordered schedule(nonmonotonic : dynamic, 5) ! { dg-error 
"NONMONOTONIC schedule modifier specified with ORDERED clause" }
+  do i = 0, 64
+    !$omp ordered
+    !$omp end ordered
+  end do
+  !$omp do schedule (nonmonotonic : guided) ordered(1) ! { dg-error 
"NONMONOTONIC schedule modifier specified with ORDERED clause" }
+  do i = 0, 64
+    !$omp ordered depend(sink: i - 1)
+    !$omp ordered depend(source)
+  end do
+  !$omp do ordered(1) schedule(nonmonotonic : guided, 2)       ! { dg-error 
"NONMONOTONIC schedule modifier specified with ORDERED clause" }
+  do i = 0, 64
+    !$omp ordered depend(source)
+    !$ordered depend(sink: i - 1)
+  end do
+  !$omp do schedule (nonmonotonic , monotonic : dynamic)       ! { dg-error 
"Both MONOTONIC and NONMONOTONIC schedule modifiers specified" }
+  do i = 0, 64
+  end do
+  !$omp do schedule (monotonic,nonmonotonic:dynamic)   ! { dg-error "Both 
MONOTONIC and NONMONOTONIC schedule modifiers specified" }
+  do i = 0, 64
+  end do
+end subroutine foo
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        PR sanitizer/87837
        * match.pd (X + Y < X): Don't optimize if TYPE_OVERFLOW_SANITIZED.

        * c-c++-common/ubsan/pr87837.c: New test.

--- gcc/match.pd        (revision 265792)
+++ gcc/match.pd        (revision 265793)
@@ -1572,6 +1572,7 @@ (define_operator_list COND_TERNARY
   (op:c (plus:c@2 @0 @1) @1)
   (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
        && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+       && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))
        && (CONSTANT_CLASS_P (@0) || single_use (@2)))
    (op @0 { build_zero_cst (TREE_TYPE (@0)); }))))
 /* For equality, this is also true with wrapping overflow.  */
--- gcc/testsuite/c-c++-common/ubsan/pr87837.c  (nonexistent)
+++ gcc/testsuite/c-c++-common/ubsan/pr87837.c  (revision 265793)
@@ -0,0 +1,18 @@
+/* PR sanitizer/87837 */
+/* { dg-do run } */
+/* { dg-options "-fsanitize=signed-integer-overflow -Wno-unused-variable" } */
+
+int
+foo (int n)
+{
+  return n + __INT_MAX__ < n;
+}
+
+int
+main ()
+{
+  volatile int a = foo (1);
+  return 0;
+}
+
+/* { dg-output "signed integer overflow: 1 \\+ 2147483647 cannot be 
represented in type 'int'" } */
2018-11-05  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/87859
        * gimple-ssa-store-merging.c (struct merged_store_group): Add
        first_nonmergeable_order member.
        (merged_store_group::merged_store_group): Initialize them.
        (imm_store_chain_info::coalesce_immediate_stores): Don't merge
        stores with order >= first_nonmergeable_order.
        Set merged_store->first_nonmergeable_order if we've skipped any
        stores.  Attempt to merge overlapping INTEGER_CST stores that
        we would otherwise skip.

        * gcc.dg/store_merging_24.c: New test.
        * gcc.dg/store_merging_25.c: New test.

--- gcc/gimple-ssa-store-merging.c      (revision 265793)
+++ gcc/gimple-ssa-store-merging.c      (revision 265794)
@@ -1416,6 +1416,7 @@ struct merged_store_group
   unsigned int load_align[2];
   unsigned int first_order;
   unsigned int last_order;
+  unsigned int first_nonmergeable_order;
 
   auto_vec<store_immediate_info *> stores;
   /* We record the first and last original statements in the sequence because
@@ -1806,6 +1807,7 @@ merged_store_group::merged_store_group (
      width has been finalized.  */
   val = NULL;
   mask = NULL;
+  first_nonmergeable_order = ~0U;
   unsigned HOST_WIDE_INT align_bitpos = 0;
   get_object_alignment_1 (gimple_assign_lhs (info->stmt),
                          &align, &align_bitpos);
@@ -2640,11 +2642,14 @@ imm_store_chain_info::coalesce_immediate
            }
        }
 
+      if (info->order >= merged_store->first_nonmergeable_order)
+       ;
+
       /* |---store 1---|
               |---store 2---|
         Overlapping stores.  */
-      if (IN_RANGE (info->bitpos, merged_store->start,
-                   merged_store->start + merged_store->width - 1))
+      else if (IN_RANGE (info->bitpos, merged_store->start,
+                        merged_store->start + merged_store->width - 1))
        {
          /* Only allow overlapping stores of constants.  */
          if (info->rhs_code == INTEGER_CST
@@ -2676,36 +2681,97 @@ imm_store_chain_info::coalesce_immediate
                     store_by_bitpos order it comes after the last store that
                     we can't merge with them.  We can merge the first 3 stores
                     and keep the last store as is though.  */
-                 unsigned int len = m_store_info.length (), k = i;
-                 for (unsigned int j = i + 1; j < len; ++j)
+                 unsigned int len = m_store_info.length ();
+                 unsigned int try_order = last_order;
+                 unsigned int first_nonmergeable_order;
+                 unsigned int k;
+                 bool last_iter = false;
+                 int attempts = 0;
+                 do
                    {
-                     store_immediate_info *info2 = m_store_info[j];
-                     if (info2->bitpos >= end)
-                       break;
-                     if (info2->order < last_order)
+                     unsigned int max_order = 0;
+                     unsigned first_nonmergeable_int_order = ~0U;
+                     unsigned HOST_WIDE_INT this_end = end;
+                     k = i;
+                     first_nonmergeable_order = ~0U;
+                     for (unsigned int j = i + 1; j < len; ++j)
                        {
-                         if (info2->rhs_code != INTEGER_CST)
+                         store_immediate_info *info2 = m_store_info[j];
+                         if (info2->bitpos >= this_end)
+                           break;
+                         if (info2->order < try_order)
                            {
-                             /* Normally check_no_overlap makes sure this
-                                doesn't happen, but if end grows below, then
-                                we need to process more stores than
-                                check_no_overlap verified.  Example:
-                                   MEM[(int *)p_5] = 0;
-                                   MEM[(short *)p_5 + 3B] = 1;
-                                   MEM[(char *)p_5 + 4B] = _9;
-                                   MEM[(char *)p_5 + 2B] = 2;  */
-                             k = 0;
-                             break;
+                             if (info2->rhs_code != INTEGER_CST)
+                               {
+                                 /* Normally check_no_overlap makes sure this
+                                    doesn't happen, but if end grows below,
+                                    then we need to process more stores than
+                                    check_no_overlap verified.  Example:
+                                     MEM[(int *)p_5] = 0;
+                                     MEM[(short *)p_5 + 3B] = 1;
+                                     MEM[(char *)p_5 + 4B] = _9;
+                                     MEM[(char *)p_5 + 2B] = 2;  */
+                                 k = 0;
+                                 break;
+                               }
+                             k = j;
+                             this_end = MAX (this_end,
+                                             info2->bitpos + info2->bitsize);
                            }
-                         k = j;
-                         end = MAX (end, info2->bitpos + info2->bitsize);
+                         else if (info2->rhs_code == INTEGER_CST
+                                  && !last_iter)
+                           {
+                             max_order = MAX (max_order, info2->order + 1);
+                             first_nonmergeable_int_order
+                               = MIN (first_nonmergeable_int_order,
+                                      info2->order);
+                           }
+                         else
+                           first_nonmergeable_order
+                             = MIN (first_nonmergeable_order, info2->order);
                        }
+                     if (k == 0)
+                       {
+                         if (last_order == try_order)
+                           break;
+                         /* If this failed, but only because we grew
+                            try_order, retry with the last working one,
+                            so that we merge at least something.  */
+                         try_order = last_order;
+                         last_iter = true;
+                         continue;
+                       }
+                     last_order = try_order;
+                     /* Retry with a larger try_order to see if we could
+                        merge some further INTEGER_CST stores.  */
+                     if (max_order
+                         && (first_nonmergeable_int_order
+                             < first_nonmergeable_order))
+                       {
+                         try_order = MIN (max_order,
+                                          first_nonmergeable_order);
+                         try_order
+                           = MIN (try_order,
+                                  merged_store->first_nonmergeable_order);
+                         if (try_order > last_order && ++attempts < 16)
+                           continue;
+                       }
+                     first_nonmergeable_order
+                       = MIN (first_nonmergeable_order,
+                              first_nonmergeable_int_order);
+                     end = this_end;
+                     break;
                    }
+                 while (1);
 
                  if (k != 0)
                    {
                      merged_store->merge_overlapping (info);
 
+                     merged_store->first_nonmergeable_order
+                       = MIN (merged_store->first_nonmergeable_order,
+                              first_nonmergeable_order);
+
                      for (unsigned int j = i + 1; j <= k; j++)
                        {
                          store_immediate_info *info2 = m_store_info[j];
@@ -2713,7 +2779,8 @@ imm_store_chain_info::coalesce_immediate
                          if (info2->order < last_order)
                            {
                              gcc_assert (info2->rhs_code == INTEGER_CST);
-                             merged_store->merge_overlapping (info2);
+                             if (info != info2)
+                               merged_store->merge_overlapping (info2);
                            }
                          /* Other stores are kept and not merged in any
                             way.  */
--- gcc/testsuite/gcc.dg/store_merging_24.c     (nonexistent)
+++ gcc/testsuite/gcc.dg/store_merging_24.c     (revision 265794)
@@ -0,0 +1,75 @@
+/* PR tree-optimization/87859 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-store-merging-details" } */
+/* { dg-final { scan-tree-dump "New sequence of \[23] stmts to replace old one 
of 19 stmts" "store-merging" { target i?86-*-* x86_64-*-* } } } */
+/* { dg-final { scan-tree-dump "New sequence of 1 stmts to replace old one of 
6 stmts" "store-merging" { target i?86-*-* x86_64-*-* } } } */
+
+struct S {
+  union F {
+    struct T {
+#define A(n) unsigned n:1;
+#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \
+            A(n##5) A(n##6) A(n##7) A(n##8) A(n##9)
+      B(f) B(f1) B(f2) B(f3) B(f4) B(f5)
+      A(f60) A(f61) A(f62) A(f63) A(f64) A(f65) A(f66)
+    } q;
+    unsigned int i[3];
+  } f;
+};
+
+struct S s = {
+  .f.q.f0 = 1, .f.q.f1 = 1, .f.q.f2 = 1, .f.q.f5 = 1, .f.q.f6 = 1,
+  .f.q.f7 = 1, .f.q.f8 = 1, .f.q.f9 = 1, .f.q.f13 = 1, .f.q.f14 = 1,
+  .f.q.f15 = 1, .f.q.f16 = 1, .f.q.f17 = 1, .f.q.f19 = 1, .f.q.f21 = 1,
+  .f.q.f66 = 1
+};
+
+__attribute__((noipa)) void
+bar (unsigned *x)
+{
+  if (x[0] != s.f.i[0] || x[1] != s.f.i[1] || x[2] != s.f.i[2])
+    __builtin_abort ();
+}
+
+__attribute__((noipa)) void
+foo (unsigned char *state)
+{
+  struct S i;
+  i.f.i[0] = 0;
+  i.f.i[1] = 0;
+  i.f.i[2] = 0;
+  i.f.q.f7 = 1;
+  i.f.q.f2 = 1;
+  i.f.q.f21 = 1;
+  i.f.q.f19 = 1;
+  i.f.q.f14 = 1;
+  i.f.q.f5 = 1;
+  i.f.q.f0 = 1;
+  i.f.q.f15 = 1;
+  i.f.q.f16 = 1;
+  i.f.q.f6 = 1;
+  i.f.q.f9 = 1;
+  i.f.q.f17 = 1;
+  i.f.q.f1 = 1;
+  i.f.q.f8 = 1;
+  i.f.q.f13 = 1;
+  i.f.q.f66 = 1;
+  if (*state)
+    {
+      i.f.q.f37 = 1;
+      i.f.q.f38 = 1;
+      i.f.q.f39 = 1;
+      i.f.q.f40 = 1;
+      i.f.q.f41 = 1;
+      i.f.q.f36 = 1;
+    }
+  bar (i.f.i);
+}
+
+int
+main ()
+{
+  unsigned char z = 0;
+  foo (&z);
+  return 0;
+}
--- gcc/testsuite/gcc.dg/store_merging_25.c     (nonexistent)
+++ gcc/testsuite/gcc.dg/store_merging_25.c     (revision 265794)
@@ -0,0 +1,75 @@
+/* PR tree-optimization/87859 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-store-merging-details" } */
+/* { dg-final { scan-tree-dump "New sequence of \[23] stmts to replace old one 
of 14 stmts" "store-merging" { target i?86-*-* x86_64-*-* } } } */
+/* { dg-final { scan-tree-dump "New sequence of 1 stmts to replace old one of 
6 stmts" "store-merging" { target i?86-*-* x86_64-*-* } } } */
+
+struct S {
+  union F {
+    struct T {
+#define A(n) unsigned n:1;
+#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \
+            A(n##5) A(n##6) A(n##7) A(n##8) A(n##9)
+      B(f) B(f1) B(f2) B(f3) B(f4) B(f5)
+      A(f60) A(f61) A(f62) A(f63) A(f64) A(f65) A(f66)
+    } q;
+    unsigned int i[3];
+  } f;
+};
+
+struct S s = {
+  .f.q.f0 = 1, .f.q.f1 = 1, .f.q.f2 = 1, .f.q.f5 = 1, .f.q.f6 = 1,
+  .f.q.f7 = 1, .f.q.f8 = 1, .f.q.f9 = 1, .f.q.f13 = 1, .f.q.f14 = 1,
+  .f.q.f15 = 1, .f.q.f16 = 1, .f.q.f17 = 1, .f.q.f19 = 1, .f.q.f21 = 1,
+  .f.q.f66 = 1
+};
+
+__attribute__((noipa)) void
+bar (unsigned *x)
+{
+  if (x[0] != s.f.i[0] || x[1] != s.f.i[1] || x[2] != s.f.i[2])
+    __builtin_abort ();
+}
+
+__attribute__((noipa)) void
+foo (unsigned char *state, unsigned char c)
+{
+  struct S i;
+  i.f.i[0] = 0;
+  i.f.i[1] = 0;
+  i.f.i[2] = 0;
+  i.f.q.f7 = 1;
+  i.f.q.f2 = 1;
+  i.f.q.f21 = 1;
+  i.f.q.f19 = 1;
+  i.f.q.f14 = 1;
+  i.f.q.f5 = 1;
+  i.f.q.f0 = 1;
+  i.f.q.f15 = 1;
+  i.f.q.f16 = 1;
+  i.f.q.f6 = 1;
+  i.f.q.f9 = 1;
+  i.f.q.f17 = c;
+  i.f.q.f1 = 1;
+  i.f.q.f8 = 1;
+  i.f.q.f13 = 1;
+  i.f.q.f66 = 1;
+  if (*state)
+    {
+      i.f.q.f37 = 1;
+      i.f.q.f38 = 1;
+      i.f.q.f39 = 1;
+      i.f.q.f40 = 1;
+      i.f.q.f41 = 1;
+      i.f.q.f36 = 1;
+    }
+  bar (i.f.i);
+}
+
+int
+main ()
+{
+  unsigned char z = 0;
+  foo (&z, 1);
+  return 0;
+}

Reply via email to