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 } } */