Hi!

I've backported a bunch of patches to 6.x, after bootstrapping/regtesting
them on x86_64-linux and i686-linux:

        Jakub
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-05  Jakub Jelinek  <ja...@redhat.com>

        PR sanitizer/77396
        * asan/asan_globals.cc: Cherry-pick upstream r280657.

        * g++.dg/asan/pr77396-2.C: New test.

        2016-09-02  Jakub Jelinek  <ja...@redhat.com>

        PR sanitizer/77396
        * g++.dg/asan/pr77396.C: New test.

--- libsanitizer/asan/asan_globals.cc   (revision 239997)
+++ libsanitizer/asan/asan_globals.cc   (revision 239998)
@@ -248,10 +248,10 @@ void __asan_unregister_globals(__asan_gl
 // initializer can only touch global variables in the same TU.
 void __asan_before_dynamic_init(const char *module_name) {
   if (!flags()->check_initialization_order ||
-      !CanPoisonMemory())
+      !CanPoisonMemory() ||
+      !dynamic_init_globals)
     return;
   bool strict_init_order = flags()->strict_init_order;
-  CHECK(dynamic_init_globals);
   CHECK(module_name);
   CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
@@ -274,7 +274,8 @@ void __asan_before_dynamic_init(const ch
 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
 void __asan_after_dynamic_init() {
   if (!flags()->check_initialization_order ||
-      !CanPoisonMemory())
+      !CanPoisonMemory() ||
+      !dynamic_init_globals)
     return;
   CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
--- gcc/testsuite/g++.dg/asan/pr77396.C (revision 0)
+++ gcc/testsuite/g++.dg/asan/pr77396.C (revision 239961)
@@ -0,0 +1,12 @@
+// PR sanitizer/77396
+// { dg-do run }
+// { dg-set-target-env-var ASAN_OPTIONS "check_initialization_order=true" }
+
+static int a = 0; 
+static int b = a; 
+
+int
+main ()
+{
+  return 0;
+}
--- gcc/testsuite/g++.dg/asan/pr77396-2.C       (revision 0)
+++ gcc/testsuite/g++.dg/asan/pr77396-2.C       (revision 239998)
@@ -0,0 +1,12 @@
+// PR sanitizer/77396
+// { dg-do run }
+// { dg-set-target-env-var ASAN_OPTIONS "check_initialization_order=true" }
+
+struct S { S () { asm volatile ("" : : : "memory"); } };
+static S c;
+
+int
+main ()
+{
+  return 0;
+}
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-06  Jakub Jelinek  <ja...@redhat.com>

        PR target/69255
        * config/i386/i386.c (ix86_expand_builtin): For builtin with
        unsupported or unknown ISA, use expand_call.

        * gcc.target/i386/pr69255-1.c: New test.
        * gcc.target/i386/pr69255-2.c: New test.
        * gcc.target/i386/pr69255-3.c: New test.

--- gcc/config/i386/i386.c      (revision 240013)
+++ gcc/config/i386/i386.c      (revision 240014)
@@ -36107,7 +36107,7 @@ ix86_expand_builtin (tree exp, rtx targe
          error ("%qE needs isa option %s", fndecl, opts);
          free (opts);
        }
-      return const0_rtx;
+      return expand_call (exp, target, ignore);
     }
 
   switch (fcode)
--- gcc/testsuite/gcc.target/i386/pr69255-1.c   (revision 0)
+++ gcc/testsuite/gcc.target/i386/pr69255-1.c   (revision 240014)
@@ -0,0 +1,17 @@
+/* PR target/69255 */
+/* { dg-do compile } */
+/* { dg-options "-msse4 -mno-avx" } */
+
+#pragma GCC target "avx512vl"
+#pragma GCC target "no-avx512vl"
+__attribute__ ((__vector_size__ (32))) long long a;
+__attribute__ ((__vector_size__ (16))) int b;
+
+void
+foo (const long long *p)
+{
+  a = __builtin_ia32_gather3siv4di (a, p, b, 1, 1);    /* { dg-error "needs 
isa option -m32 -mavx512vl" } */
+}
+
+/* { dg-warning "AVX vector return without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
+/* { dg-warning "AVX vector argument without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
--- gcc/testsuite/gcc.target/i386/pr69255-2.c   (revision 0)
+++ gcc/testsuite/gcc.target/i386/pr69255-2.c   (revision 240014)
@@ -0,0 +1,17 @@
+/* PR target/69255 */
+/* { dg-do compile } */
+/* { dg-options "-msse4 -mno-avx" } */
+
+#pragma GCC target "avx512vl"
+#pragma GCC target ""
+__attribute__ ((__vector_size__ (32))) long long a;
+__attribute__ ((__vector_size__ (16))) int b;
+
+void
+foo (const long long *p)
+{
+  __builtin_ia32_gather3siv4di (a, p, b, 1, 1);                /* { dg-error 
"needs isa option -m32 -mavx512vl" } */
+}
+
+/* { dg-warning "AVX vector return without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
+/* { dg-warning "AVX vector argument without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
--- gcc/testsuite/gcc.target/i386/pr69255-3.c   (revision 0)
+++ gcc/testsuite/gcc.target/i386/pr69255-3.c   (revision 240014)
@@ -0,0 +1,17 @@
+/* PR target/69255 */
+/* { dg-do compile } */
+/* { dg-options "-msse4 -mno-avx" } */
+
+#pragma GCC target "avx512vl"
+#pragma GCC target ""
+__attribute__ ((__vector_size__ (32))) long long a;
+__attribute__ ((__vector_size__ (16))) int b;
+
+void
+foo (const long long *p, __attribute__ ((__vector_size__ (32))) long long *q)
+{
+  *q = __builtin_ia32_gather3siv4di (a, p, b, 1, 1);   /* { dg-error "needs 
isa option -m32 -mavx512vl" } */
+}
+
+/* { dg-warning "AVX vector return without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
+/* { dg-warning "AVX vector argument without AVX enabled changes the ABI" "" { 
target *-*-* } 13 } */
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-08  Jakub Jelinek  <ja...@redhat.com>

        PR fortran/77516
        * omp-low.c (lower_rec_simd_input_clauses): Use max_vf for non-positive
        OMP_CLAUSE_SAFELEN_EXPR.

        * gfortran.dg/gomp/pr77516.f90: New test.

--- gcc/omp-low.c       (revision 240036)
+++ gcc/omp-low.c       (revision 240037)
@@ -4302,7 +4302,9 @@ lower_rec_simd_input_clauses (tree new_v
        {
          tree c = find_omp_clause (gimple_omp_for_clauses (ctx->stmt),
                                    OMP_CLAUSE_SAFELEN);
-         if (c && TREE_CODE (OMP_CLAUSE_SAFELEN_EXPR (c)) != INTEGER_CST)
+         if (c
+             && (TREE_CODE (OMP_CLAUSE_SAFELEN_EXPR (c)) != INTEGER_CST
+                 || tree_int_cst_sgn (OMP_CLAUSE_SAFELEN_EXPR (c)) != 1))
            max_vf = 1;
          else if (c && compare_tree_int (OMP_CLAUSE_SAFELEN_EXPR (c),
                                          max_vf) == -1)
--- gcc/testsuite/gfortran.dg/gomp/pr77516.f90  (revision 0)
+++ gcc/testsuite/gfortran.dg/gomp/pr77516.f90  (revision 240037)
@@ -0,0 +1,12 @@
+! PR fortran/77516
+! { dg-do compile }
+
+program pr77516
+   integer :: i, x
+   x = 0
+!$omp simd safelen(0) reduction(+:x)
+   do i = 1, 8
+      x = x + 1
+   end do
+   print *, x
+end
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-08  Jakub Jelinek  <ja...@redhat.com>

        PR fortran/77500
        * trans-openmp.c (gfc_trans_omp_atomic): For atomic write or
        swap, don't try to look through GFC_ISYM_CONVERSION.  In other cases,
        check that value.function.isym is non-NULL before dereferencing it.

        * gfortran.dg/gomp/pr77500.f90: New test.

--- gcc/fortran/trans-openmp.c  (revision 240037)
+++ gcc/fortran/trans-openmp.c  (revision 240038)
@@ -2818,7 +2818,11 @@ gfc_trans_omp_atomic (gfc_code *code)
   gfc_start_block (&block);
 
   expr2 = code->expr2;
-  if (expr2->expr_type == EXPR_FUNCTION
+  if (((atomic_code->ext.omp_atomic & GFC_OMP_ATOMIC_MASK)
+       != GFC_OMP_ATOMIC_WRITE)
+      && (atomic_code->ext.omp_atomic & GFC_OMP_ATOMIC_SWAP) == 0
+      && expr2->expr_type == EXPR_FUNCTION
+      && expr2->value.function.isym
       && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
     expr2 = expr2->value.function.actual->expr;
 
@@ -2857,6 +2861,7 @@ gfc_trans_omp_atomic (gfc_code *code)
          var = code->expr1->symtree->n.sym;
          expr2 = code->expr2;
          if (expr2->expr_type == EXPR_FUNCTION
+             && expr2->value.function.isym
              && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
            expr2 = expr2->value.function.actual->expr;
        }
@@ -2914,6 +2919,7 @@ gfc_trans_omp_atomic (gfc_code *code)
        }
       e = expr2->value.op.op1;
       if (e->expr_type == EXPR_FUNCTION
+         && e->value.function.isym
          && e->value.function.isym->id == GFC_ISYM_CONVERSION)
        e = e->value.function.actual->expr;
       if (e->expr_type == EXPR_VARIABLE
@@ -2927,6 +2933,7 @@ gfc_trans_omp_atomic (gfc_code *code)
        {
          e = expr2->value.op.op2;
          if (e->expr_type == EXPR_FUNCTION
+             && e->value.function.isym
              && e->value.function.isym->id == GFC_ISYM_CONVERSION)
            e = e->value.function.actual->expr;
          gcc_assert (e->expr_type == EXPR_VARIABLE
@@ -3041,6 +3048,7 @@ gfc_trans_omp_atomic (gfc_code *code)
          code = code->next;
          expr2 = code->expr2;
          if (expr2->expr_type == EXPR_FUNCTION
+             && expr2->value.function.isym
              && expr2->value.function.isym->id == GFC_ISYM_CONVERSION)
            expr2 = expr2->value.function.actual->expr;
 
--- gcc/testsuite/gfortran.dg/gomp/pr77500.f90  (revision 0)
+++ gcc/testsuite/gfortran.dg/gomp/pr77500.f90  (revision 240038)
@@ -0,0 +1,9 @@
+! PR fortran/77500
+! { dg-do compile }
+
+program pr77500
+   real :: x
+!$omp atomic write
+   x = f()
+!$omp end atomic
+end
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-13  Jakub Jelinek  <ja...@redhat.com>

        PR c++/77553
        * constexpr.c (cxx_fold_pointer_plus_expression): New function.
        (cxx_eval_binary_expression): Use it for POINTER_PLUS_EXPR.
        (cxx_eval_pointer_plus_expression): Remove.
        (cxx_eval_constant_expression) <case POINTER_PLUS_EXPR>: Don't
        call cxx_eval_pointer_plus_expression.

        * g++.dg/cpp1y/constexpr-77553.C: New test.

--- gcc/cp/constexpr.c  (revision 240118)
+++ gcc/cp/constexpr.c  (revision 240119)
@@ -1745,6 +1745,63 @@ cxx_eval_unary_expression (const constex
   return r;
 }
 
+/* Helper function for cxx_eval_binary_expression.  Try to optimize
+   original POINTER_PLUS_EXPR T, LHS p+ RHS, return NULL_TREE if the
+   generic folding should be used.  */
+
+static tree
+cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
+                                 tree lhs, tree rhs, bool *non_constant_p,
+                                 bool *overflow_p)
+{
+  STRIP_NOPS (lhs);
+  if (TREE_CODE (lhs) != ADDR_EXPR)
+    return NULL_TREE;
+
+  lhs = TREE_OPERAND (lhs, 0);
+
+  /* &A[i] p+ j => &A[i + j] */
+  if (TREE_CODE (lhs) == ARRAY_REF
+      && TREE_CODE (TREE_OPERAND (lhs, 1)) == INTEGER_CST
+      && TREE_CODE (rhs) == INTEGER_CST
+      && TYPE_SIZE_UNIT (TREE_TYPE (lhs))
+      && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (lhs))) == INTEGER_CST)
+    {
+      tree orig_type = TREE_TYPE (t);
+      location_t loc = EXPR_LOCATION (t);
+      tree type = TREE_TYPE (lhs);
+
+      t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1));
+      tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0)));
+      nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
+                                           overflow_p);
+      if (*non_constant_p)
+       return NULL_TREE;
+      /* Don't fold an out-of-bound access.  */
+      if (!tree_int_cst_le (t, nelts))
+       return NULL_TREE;
+      rhs = cp_fold_convert (ssizetype, rhs);
+      /* Don't fold if rhs can't be divided exactly by TYPE_SIZE_UNIT.
+        constexpr int A[1]; ... (char *)&A[0] + 1 */
+      if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype,
+                                          rhs, TYPE_SIZE_UNIT (type))))
+       return NULL_TREE;
+      /* Make sure to treat the second operand of POINTER_PLUS_EXPR
+        as signed.  */
+      rhs = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, rhs,
+                            TYPE_SIZE_UNIT (type));
+      t = size_binop_loc (loc, PLUS_EXPR, rhs, t);
+      t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (lhs, 0),
+                     t, NULL_TREE, NULL_TREE);
+      t = cp_build_addr_expr (t, tf_warning_or_error);
+      t = cp_fold_convert (orig_type, t);
+      return cxx_eval_constant_expression (ctx, t, /*lval*/false,
+                                          non_constant_p, overflow_p);
+    }
+
+  return NULL_TREE;
+}
+
 /* Subroutine of cxx_eval_constant_expression.
    Like cxx_eval_unary_expression, except for binary expressions.  */
 
@@ -1790,6 +1847,9 @@ cxx_eval_binary_expression (const conste
       else if (TREE_CODE (rhs) == PTRMEM_CST)
        rhs = cplus_expand_constant (rhs);
     }
+  else if (code == POINTER_PLUS_EXPR)
+    r = cxx_fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
+                                         overflow_p);
 
   if (r == NULL_TREE)
     r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -3448,65 +3508,6 @@ cxx_eval_switch_expr (const constexpr_ct
   return NULL_TREE;
 }
 
-/* Subroutine of cxx_eval_constant_expression.
-   Attempt to reduce a POINTER_PLUS_EXPR expression T.  */
-
-static tree
-cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
-                                 bool lval, bool *non_constant_p,
-                                 bool *overflow_p)
-{
-  tree orig_type = TREE_TYPE (t);
-  tree op00 = TREE_OPERAND (t, 0);
-  tree op01 = TREE_OPERAND (t, 1);
-  location_t loc = EXPR_LOCATION (t);
-
-  op00 = cxx_eval_constant_expression (ctx, op00, lval,
-                                      non_constant_p, overflow_p);
-
-  STRIP_NOPS (op00);
-  if (TREE_CODE (op00) != ADDR_EXPR)
-    return NULL_TREE;
-
-  op01 = cxx_eval_constant_expression (ctx, op01, lval,
-                                      non_constant_p, overflow_p);
-  op00 = TREE_OPERAND (op00, 0);
-
-  /* &A[i] p+ j => &A[i + j] */
-  if (TREE_CODE (op00) == ARRAY_REF
-      && TREE_CODE (TREE_OPERAND (op00, 1)) == INTEGER_CST
-      && TREE_CODE (op01) == INTEGER_CST
-      && TYPE_SIZE_UNIT (TREE_TYPE (op00))
-      && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (op00))) == INTEGER_CST)
-    {
-      tree type = TREE_TYPE (op00);
-      t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (op00, 1));
-      tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (op00, 0)));
-      /* Don't fold an out-of-bound access.  */
-      if (!tree_int_cst_le (t, nelts))
-       return NULL_TREE;
-      op01 = cp_fold_convert (ssizetype, op01);
-      /* Don't fold if op01 can't be divided exactly by TYPE_SIZE_UNIT.
-        constexpr int A[1]; ... (char *)&A[0] + 1 */
-      if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype,
-                                          op01, TYPE_SIZE_UNIT (type))))
-       return NULL_TREE;
-      /* Make sure to treat the second operand of POINTER_PLUS_EXPR
-        as signed.  */
-      op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, op01,
-                             TYPE_SIZE_UNIT (type));
-      t = size_binop_loc (loc, PLUS_EXPR, op01, t);
-      t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (op00, 0),
-                     t, NULL_TREE, NULL_TREE);
-      t = cp_build_addr_expr (t, tf_warning_or_error);
-      t = cp_fold_convert (orig_type, t);
-      return cxx_eval_constant_expression (ctx, t, lval, non_constant_p,
-                                          overflow_p);
-    }
-
-  return NULL_TREE;
-}
-
 /* Attempt to reduce the expression T to a constant value.
    On failure, issue diagnostic and return error_mark_node.  */
 /* FIXME unify with c_fully_fold */
@@ -3824,12 +3825,6 @@ cxx_eval_constant_expression (const cons
       break;
 
     case POINTER_PLUS_EXPR:
-      r = cxx_eval_pointer_plus_expression (ctx, t, lval, non_constant_p,
-                                           overflow_p);
-      if (r)
-       break;
-      /* else fall through */
-
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
--- gcc/testsuite/g++.dg/cpp1y/constexpr-77553.C        (revision 0)
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-77553.C        (revision 240119)
@@ -0,0 +1,29 @@
+// PR c++/77553
+// { dg-do compile { target c++14 } }
+
+constexpr void
+bar (int *x)
+{
+  int i = 0;
+  x[i++] = 1;
+  x[3] = i;
+}
+
+constexpr int
+foo ()
+{
+  int a[] = { 0, 0, 0, 0 };
+  bar (a);
+
+  return a[0] + 8 * a[1] + 64 * a[2] + 512 * a[3];
+}
+
+constexpr int b = foo ();
+
+int
+main ()
+{
+  static_assert (b == 513, "");
+  if (foo () != 513)
+    __builtin_abort ();
+}
2016-09-16  Jakub Jelinek  <ja...@redhat.com>

        Backported from mainline
        2016-09-14  Jakub Jelinek  <ja...@redhat.com>

        PR sanitizer/68260
        * tsan.c: Include target.h.
        (enum tsan_atomic_action): Add bool_clear and bool_test_and_set.
        (BOOL_CLEAR, BOOL_TEST_AND_SET): Define.
        (tsan_atomic_table): Add BUILT_IN_ATOMIC_CLEAR and
        BUILT_IN_ATOMIC_TEST_AND_SET entries.
        (instrument_builtin_call): Handle bool_clear and bool_test_and_set.

        * c-c++-common/tsan/pr68260.c: New test.

--- gcc/tsan.c  (revision 240128)
+++ gcc/tsan.c  (revision 240129)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
 #include "tsan.h"
 #include "asan.h"
 #include "builtins.h"
+#include "target.h"
 
 /* Number of instrumented memory accesses in the current function.  */
 
@@ -240,7 +241,8 @@ instrument_expr (gimple_stmt_iterator gs
 enum tsan_atomic_action
 {
   check_last, add_seq_cst, add_acquire, weak_cas, strong_cas,
-  bool_cas, val_cas, lock_release, fetch_op, fetch_op_seq_cst
+  bool_cas, val_cas, lock_release, fetch_op, fetch_op_seq_cst,
+  bool_clear, bool_test_and_set
 };
 
 /* Table how to map sync/atomic builtins to their corresponding
@@ -274,6 +276,10 @@ static const struct tsan_map_atomic
   TRANSFORM (fcode, tsan_fcode, fetch_op, code)
 #define FETCH_OPS(fcode, tsan_fcode, code) \
   TRANSFORM (fcode, tsan_fcode, fetch_op_seq_cst, code)
+#define BOOL_CLEAR(fcode, tsan_fcode) \
+  TRANSFORM (fcode, tsan_fcode, bool_clear, ERROR_MARK)
+#define BOOL_TEST_AND_SET(fcode, tsan_fcode) \
+  TRANSFORM (fcode, tsan_fcode, bool_test_and_set, ERROR_MARK)
 
   CHECK_LAST (ATOMIC_LOAD_1, TSAN_ATOMIC8_LOAD),
   CHECK_LAST (ATOMIC_LOAD_2, TSAN_ATOMIC16_LOAD),
@@ -463,7 +469,11 @@ static const struct tsan_map_atomic
   LOCK_RELEASE (SYNC_LOCK_RELEASE_2, TSAN_ATOMIC16_STORE),
   LOCK_RELEASE (SYNC_LOCK_RELEASE_4, TSAN_ATOMIC32_STORE),
   LOCK_RELEASE (SYNC_LOCK_RELEASE_8, TSAN_ATOMIC64_STORE),
-  LOCK_RELEASE (SYNC_LOCK_RELEASE_16, TSAN_ATOMIC128_STORE)
+  LOCK_RELEASE (SYNC_LOCK_RELEASE_16, TSAN_ATOMIC128_STORE),
+
+  BOOL_CLEAR (ATOMIC_CLEAR, TSAN_ATOMIC8_STORE),
+
+  BOOL_TEST_AND_SET (ATOMIC_TEST_AND_SET, TSAN_ATOMIC8_EXCHANGE)
 };
 
 /* Instrument an atomic builtin.  */
@@ -615,6 +625,57 @@ instrument_builtin_call (gimple_stmt_ite
                                build_int_cst (NULL_TREE,
                                               MEMMODEL_RELEASE));
            return;
+         case bool_clear:
+         case bool_test_and_set:
+           if (BOOL_TYPE_SIZE != 8)
+             {
+               decl = NULL_TREE;
+               for (j = 1; j < 5; j++)
+                 if (BOOL_TYPE_SIZE == (8 << j))
+                   {
+                     enum built_in_function tsan_fcode
+                       = (enum built_in_function)
+                         (tsan_atomic_table[i].tsan_fcode + j);
+                     decl = builtin_decl_implicit (tsan_fcode);
+                     break;
+                   }
+               if (decl == NULL_TREE)
+                 return;
+             }
+           last_arg = gimple_call_arg (stmt, num - 1);
+           if (!tree_fits_uhwi_p (last_arg)
+               || memmodel_base (tree_to_uhwi (last_arg)) >= MEMMODEL_LAST)
+             return;
+           t = TYPE_ARG_TYPES (TREE_TYPE (decl));
+           t = TREE_VALUE (TREE_CHAIN (t));
+           if (tsan_atomic_table[i].action == bool_clear)
+             {
+               update_gimple_call (gsi, decl, 3, gimple_call_arg (stmt, 0),
+                                   build_int_cst (t, 0), last_arg);
+               return;
+             }
+           t = build_int_cst (t, targetm.atomic_test_and_set_trueval);
+           update_gimple_call (gsi, decl, 3, gimple_call_arg (stmt, 0),
+                               t, last_arg);
+           stmt = gsi_stmt (*gsi);
+           lhs = gimple_call_lhs (stmt);
+           if (lhs == NULL_TREE)
+             return;
+           if (targetm.atomic_test_and_set_trueval != 1
+               || !useless_type_conversion_p (TREE_TYPE (lhs),
+                                              TREE_TYPE (t)))
+             {
+               tree new_lhs = make_ssa_name (TREE_TYPE (t));
+               gimple_call_set_lhs (stmt, new_lhs);
+               if (targetm.atomic_test_and_set_trueval != 1)
+                 g = gimple_build_assign (lhs, NE_EXPR, new_lhs,
+                                          build_int_cst (TREE_TYPE (t), 0));
+               else
+                 g = gimple_build_assign (lhs, NOP_EXPR, new_lhs);
+               gsi_insert_after (gsi, g, GSI_NEW_STMT);
+               update_stmt (stmt);
+             }
+           return;
          default:
            continue;
          }
--- gcc/testsuite/c-c++-common/tsan/pr68260.c   (revision 0)
+++ gcc/testsuite/c-c++-common/tsan/pr68260.c   (revision 240129)
@@ -0,0 +1,28 @@
+/* PR sanitizer/68260 */
+
+#include <pthread.h>
+#include <stdbool.h>
+
+bool lock;
+int counter;
+
+void *
+tf (void *arg)
+{
+  (void) arg;
+  while (__atomic_test_and_set (&lock, __ATOMIC_ACQUIRE))
+    ;
+  ++counter;
+  __atomic_clear (&lock, __ATOMIC_RELEASE);
+  return (void *) 0;
+}
+
+int
+main ()
+{
+  pthread_t thr;
+  pthread_create (&thr, 0, tf, 0);
+  tf ((void *) 0);
+  pthread_join (thr, 0);
+  return 0;
+}
2016-09-16  Jakub Jelinek  <ja...@redhat.com>
            Eric Botcazou  <ebotca...@adacore.com>

        PR middle-end/77594
        * internal-fn.c (expand_arith_overflow) <case MINUS_EXPR>: Don't fall
        through into expand_addsub_overflow after expand_neg_overflow.

        * gcc.target/i386/pr77594.c: New test.

--- gcc/internal-fn.c   (revision 240172)
+++ gcc/internal-fn.c   (revision 240173)
@@ -1833,7 +1833,10 @@ expand_arith_overflow (enum tree_code co
            {
            case MINUS_EXPR:
              if (integer_zerop (arg0) && !unsr_p)
-               expand_neg_overflow (loc, lhs, arg1, false);
+               {
+                 expand_neg_overflow (loc, lhs, arg1, false);
+                 return;
+               }
              /* FALLTHRU */
            case PLUS_EXPR:
              expand_addsub_overflow (loc, code, lhs, arg0, arg1,
--- gcc/testsuite/gcc.target/i386/pr77594.c     (revision 0)
+++ gcc/testsuite/gcc.target/i386/pr77594.c     (revision 240173)
@@ -0,0 +1,11 @@
+/* PR middle-end/77594 */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+int
+foo (int a, int *b)
+{
+  return __builtin_sub_overflow (0, a, b);
+}
+
+/* { dg-final { scan-assembler-times "\tjn?o\t" 1 } } */

Reply via email to