Hi! I've bootstrapped/regtested on x86_64-linux and i686-linux following backports and committed them to 4.8 branch.
Jakub
2015-06-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2015-02-18 Jakub Jelinek <ja...@redhat.com> PR gcov-profile/64634 * tree-eh.c (frob_into_branch_around): Fix up typos in function comment. (lower_catch): Put eh_seq resulting from EH lowering of the cleanup sequence after the cleanup rather than before it. * g++.dg/gcov/gcov-15.C: New test. --- gcc/tree-eh.c (revision 220800) +++ gcc/tree-eh.c (revision 220801) @@ -884,10 +884,10 @@ eh_region_may_contain_throw (eh_region r /* We want to transform try { body; } catch { stuff; } to - normal_seqence: + normal_sequence: body; over: - eh_seqence: + eh_sequence: landing_pad: stuff; goto over; @@ -1813,6 +1813,12 @@ lower_catch (struct leh_state *state, gt this_state.cur_region = state->cur_region; this_state.ehp_region = try_region; + /* Add eh_seq from lowering EH in the cleanup sequence after the cleanup + itself, so that e.g. for coverage purposes the nested cleanups don't + appear before the cleanup body. See PR64634 for details. */ + gimple_seq old_eh_seq = eh_seq; + eh_seq = NULL; + out_label = NULL; cleanup = gimple_try_cleanup (tp); for (gsi = gsi_start (cleanup); @@ -1849,7 +1855,11 @@ lower_catch (struct leh_state *state, gt gimple_try_set_cleanup (tp, new_seq); - return frob_into_branch_around (tp, try_region, out_label); + gimple_seq new_eh_seq = eh_seq; + eh_seq = old_eh_seq; + gimple_seq ret_seq = frob_into_branch_around (tp, try_region, out_label); + gimple_seq_add_seq (&eh_seq, new_eh_seq); + return ret_seq; } /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY with a --- gcc/testsuite/g++.dg/gcov/gcov-15.C (revision 0) +++ gcc/testsuite/g++.dg/gcov/gcov-15.C (revision 220801) @@ -0,0 +1,26 @@ +// PR gcov-profile/64634 +// { dg-options "-fprofile-arcs -ftest-coverage" } +// { dg-do run { target native } } + +void catchEx () // count(1) +{ + __builtin_exit (0); // count(1) + try + {} + catch (int) + {} +} + +int main () // count(1) +{ + try + { + throw 5; // count(1) + } + catch (...) // count(1) + { + catchEx (); // count(1) + } +} + +// { dg-final { run-gcov gcov-15.C } }
2015-06-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2015-03-10 Jakub Jelinek <ja...@redhat.com> PR target/65368 * config/i386/i386.md (bmi2_bzhi_<mode>3): Removed define_insn, new define_expand. (*bmi2_bzhi_<mode>3, *bmi2_bzhi_<mode>3_1): New define_insns. * gcc.target/i386/bmi2-bzhi-2.c: New test. --- gcc/config/i386/i386.md (revision 221334) +++ gcc/config/i386/i386.md (revision 221335) @@ -12172,17 +12172,51 @@ (set_attr "mode" "<MODE>")]) ;; BMI2 instructions. -(define_insn "bmi2_bzhi_<mode>3" +(define_expand "bmi2_bzhi_<mode>3" + [(parallel + [(set (match_operand:SWI48 0 "register_operand") + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (umin:SWI48 + (and:SWI48 (match_operand:SWI48 2 "register_operand") + (const_int 255)) + (match_dup 3)) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_BMI2" + "operands[3] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode));") + +(define_insn "*bmi2_bzhi_<mode>3" [(set (match_operand:SWI48 0 "register_operand" "=r") - (and:SWI48 (lshiftrt:SWI48 (const_int -1) - (match_operand:SWI48 2 "register_operand" "r")) - (match_operand:SWI48 1 "nonimmediate_operand" "rm"))) + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "rm") + (umin:SWI48 + (and:SWI48 (match_operand:SWI48 2 "register_operand" "r") + (const_int 255)) + (match_operand:SWI48 3 "const_int_operand" "n")) + (const_int 0))) (clobber (reg:CC FLAGS_REG))] - "TARGET_BMI2" + "TARGET_BMI2 && INTVAL (operands[3]) == GET_MODE_BITSIZE (<MODE>mode)" "bzhi\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "bitmanip") (set_attr "prefix" "vex") (set_attr "mode" "<MODE>")]) + +(define_mode_attr k [(SI "k") (DI "q")]) +(define_insn "*bmi2_bzhi_<mode>3_1" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "rm") + (umin:SWI48 + (zero_extend:SWI48 (match_operand:QI 2 "register_operand" "r")) + (match_operand:SWI48 3 "const_int_operand" "n")) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_BMI2 && INTVAL (operands[3]) == GET_MODE_BITSIZE (<MODE>mode)" + "bzhi\t{%<k>2, %1, %0|%0, %1, %<k>2}" + [(set_attr "type" "bitmanip") + (set_attr "prefix" "vex") + (set_attr "mode" "<MODE>")]) (define_insn "bmi2_pdep_<mode>3" [(set (match_operand:SWI48 0 "register_operand" "=r") --- gcc/testsuite/gcc.target/i386/bmi2-bzhi-2.c (revision 0) +++ gcc/testsuite/gcc.target/i386/bmi2-bzhi-2.c (revision 221335) @@ -0,0 +1,67 @@ +/* PR target/65368 */ +/* { dg-do assemble { target bmi2 } } */ +/* { dg-options "-O2 -mbmi2" } */ + +#include <x86intrin.h> +#include "bmi2-check.h" + +unsigned int a; +unsigned long long b; + +#define A __attribute__((noinline, noclone)) + +A unsigned int f1 (void) { return _bzhi_u32 (a, 0); } +A unsigned int f2 (unsigned int x) { return _bzhi_u32 (x, 0); } +A unsigned int f3 (void) { return _bzhi_u32 (a, 5); } +A unsigned int f4 (unsigned int x) { return _bzhi_u32 (x, 5); } +A unsigned int f5 (void) { return _bzhi_u32 (a, 31); } +A unsigned int f6 (unsigned int x) { return _bzhi_u32 (x, 31); } +A unsigned int f7 (void) { return _bzhi_u32 (a, 32); } +A unsigned int f8 (unsigned int x) { return _bzhi_u32 (x, 32); } +A unsigned int f9 (void) { return _bzhi_u32 (a, 37); } +A unsigned int f10 (unsigned int x) { return _bzhi_u32 (x, 37); } +A unsigned int f11 (void) { return _bzhi_u32 (a, 257); } +A unsigned int f12 (unsigned int x) { return _bzhi_u32 (x, 257); } +A unsigned int f13 (void) { return _bzhi_u32 (a, 289); } +A unsigned int f14 (unsigned int x) { return _bzhi_u32 (x, 289); } +#ifdef __x86_64__ +A unsigned long long f21 (void) { return _bzhi_u64 (b, 0); } +A unsigned long long f22 (unsigned long long x) { return _bzhi_u64 (x, 0); } +A unsigned long long f23 (void) { return _bzhi_u64 (b, 5); } +A unsigned long long f24 (unsigned long long x) { return _bzhi_u64 (x, 5); } +A unsigned long long f25 (void) { return _bzhi_u64 (b, 63); } +A unsigned long long f26 (unsigned long long x) { return _bzhi_u64 (x, 63); } +A unsigned long long f27 (void) { return _bzhi_u64 (b, 64); } +A unsigned long long f28 (unsigned long long x) { return _bzhi_u64 (x, 64); } +A unsigned long long f29 (void) { return _bzhi_u64 (b, 69); } +A unsigned long long f30 (unsigned long long x) { return _bzhi_u64 (x, 69); } +A unsigned long long f31 (void) { return _bzhi_u64 (b, 257); } +A unsigned long long f32 (unsigned long long x) { return _bzhi_u64 (x, 257); } +A unsigned long long f33 (void) { return _bzhi_u64 (b, 321); } +A unsigned long long f34 (unsigned long long x) { return _bzhi_u64 (x, 321); } +#endif + +static void +bmi2_test () +{ + a = -1U; + b = -1ULL; + if (f1 () != 0 || f2 (-1U) != 0 + || f3 () != 0x1f || f4 (-1U) != 0x1f + || f5 () != 0x7fffffffU || f6 (-1U) != 0x7fffffffU + || f7 () != -1U || f8 (-1U) != -1U + || f9 () != -1U || f10 (-1U) != -1U + || f11 () != 1 || f12 (-1U) != 1 + || f13 () != -1U || f14 (-1U) != -1U) + abort (); +#ifdef __x86_64__ + if (f21 () != 0 || f22 (-1ULL) != 0 + || f23 () != 0x1f || f24 (-1ULL) != 0x1f + || f25 () != 0x7fffffffffffffffULL || f26 (-1ULL) != 0x7fffffffffffffffULL + || f27 () != -1ULL || f28 (-1ULL) != -1ULL + || f29 () != -1ULL || f30 (-1ULL) != -1ULL + || f31 () != 1 || f32 (-1ULL) != 1 + || f33 () != -1ULL || f34 (-1ULL) != -1ULL) + abort (); +#endif +}
2015-06-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2015-04-07 Jakub Jelinek <ja...@redhat.com> PR middle-end/65680 * expr.c (get_inner_reference): Handle bit_offset that doesn't fit into signed HOST_WIDE_INT the same as negative bit_offset. * gcc.c-torture/compile/pr65680.c: New test. --- gcc/expr.c (revision 221898) +++ gcc/expr.c (revision 221899) @@ -6873,7 +6873,7 @@ get_inner_reference (tree exp, HOST_WIDE if (offset) { /* Avoid returning a negative bitpos as this may wreak havoc later. */ - if (bit_offset.is_negative ()) + if (bit_offset.is_negative () || !bit_offset.fits_shwi ()) { double_int mask = double_int::mask (BITS_PER_UNIT == 8 --- gcc/testsuite/gcc.c-torture/compile/pr65680.c (revision 0) +++ gcc/testsuite/gcc.c-torture/compile/pr65680.c (revision 221899) @@ -0,0 +1,20 @@ +/* PR middle-end/65680 */ +/* { dg-do compile { target lp64 } } */ + +struct S +{ + int f : 1; +} a[100000000000000001][3]; + +void +foo (void) +{ + struct S b = { 0 }; + a[100000000000000000][0] = b; +} + +void +bar (void) +{ + a[100000000000000000][0].f = 1; +}
2015-06-03 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2015-05-13 Jakub Jelinek <ja...@redhat.com> PR middle-end/66133 * omp-low.c (expand_omp_taskreg): For GIMPLE_OMP_TASK expansion, make sure it is never noreturn, even when the task body does not return. (lower_omp_taskreg): For GIMPLE_OMP_TASK, emit GIMPLE_OMP_CONTINUE right before GIMPLE_OMP_RETURN. * tree-cfg.c (make_edges): Accept GIMPLE_OMP_CONTINUE as ->cont for GIMPLE_OMP_TASK. For GIMPLE_OMP_RETURN corresponding to GIMPLE_OMP_TASK add an EDGE_ABNORMAL edge from entry to exit. * testsuite/libgomp.c/pr66133.c: New test. --- gcc/omp-low.c (revision 223519) +++ gcc/omp-low.c (revision 223520) @@ -3487,7 +3487,10 @@ expand_omp_taskreg (struct omp_region *r child_cfun = DECL_STRUCT_FUNCTION (child_fn); entry_bb = region->entry; - exit_bb = region->exit; + if (gimple_code (entry_stmt) == GIMPLE_OMP_TASK) + exit_bb = region->cont; + else + exit_bb = region->exit; if (is_combined_parallel (region)) ws_args = region->ws_args; @@ -3536,7 +3539,9 @@ expand_omp_taskreg (struct omp_region *r variable. In which case, we need to keep the assignment. */ if (gimple_omp_taskreg_data_arg (entry_stmt)) { - basic_block entry_succ_bb = single_succ (entry_bb); + basic_block entry_succ_bb + = single_succ_p (entry_bb) ? single_succ (entry_bb) + : FALLTHRU_EDGE (entry_bb)->dest; gimple_stmt_iterator gsi; tree arg, narg; gimple parcopy_stmt = NULL; @@ -3625,14 +3630,28 @@ expand_omp_taskreg (struct omp_region *r gsi_remove (&gsi, true); e = split_block (entry_bb, stmt); entry_bb = e->dest; - single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + edge e2 = NULL; + if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL) + single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; + else + { + e2 = make_edge (e->src, BRANCH_EDGE (entry_bb)->dest, EDGE_ABNORMAL); + gcc_assert (e2->dest == region->exit); + remove_edge (BRANCH_EDGE (entry_bb)); + set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src); + gsi = gsi_last_bb (region->exit); + gcc_assert (!gsi_end_p (gsi) + && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); + gsi_remove (&gsi, true); + } - /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */ + /* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR. */ if (exit_bb) { gsi = gsi_last_bb (exit_bb); gcc_assert (!gsi_end_p (gsi) - && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN); + && (gimple_code (gsi_stmt (gsi)) + == (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN))); stmt = gimple_build_return (NULL); gsi_insert_after (&gsi, stmt, GSI_SAME_STMT); gsi_remove (&gsi, true); @@ -3653,6 +3672,14 @@ expand_omp_taskreg (struct omp_region *r new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block); if (exit_bb) single_succ_edge (new_bb)->flags = EDGE_FALLTHRU; + if (e2) + { + basic_block dest_bb = e2->dest; + if (!exit_bb) + make_edge (new_bb, dest_bb, EDGE_FALLTHRU); + remove_edge (e2); + set_immediate_dominator (CDI_DOMINATORS, dest_bb, new_bb); + } /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */ num = vec_safe_length (child_cfun->local_decls); @@ -7020,6 +7047,10 @@ lower_omp_taskreg (gimple_stmt_iterator gimple_seq_add_seq (&new_body, par_body); gimple_seq_add_seq (&new_body, par_olist); new_body = maybe_catch_exception (new_body); + if (gimple_code (stmt) == GIMPLE_OMP_TASK) + gimple_seq_add_stmt (&new_body, + gimple_build_omp_continue (integer_zero_node, + integer_zero_node)); gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false)); gimple_omp_set_body (stmt, new_body); --- gcc/tree-cfg.c.jj 2014-02-20 21:39:14.000000000 +0100 +++ gcc/tree-cfg.c 2015-06-03 18:59:25.681769246 +0200 @@ -589,6 +589,10 @@ make_edges (void) somewhere other than the next block. This will be created later. */ cur_region->exit = bb; + if (cur_region->type == GIMPLE_OMP_TASK) + /* Add an edge corresponding to not scheduling the task + immediately. */ + make_edge (cur_region->entry, bb, EDGE_ABNORMAL); fallthru = cur_region->type != GIMPLE_OMP_SECTION; cur_region = cur_region->outer; break; @@ -637,6 +641,10 @@ make_edges (void) } break; + case GIMPLE_OMP_TASK: + fallthru = true; + break; + default: gcc_unreachable (); } --- libgomp/testsuite/libgomp.c/pr66133.c (revision 0) +++ libgomp/testsuite/libgomp.c/pr66133.c (revision 223520) @@ -0,0 +1,35 @@ +/* PR middle-end/66133 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +#include <stdlib.h> +#include <unistd.h> + +volatile int x; + +__attribute__((noinline)) void +foo (void) +{ + if (x == 0) + { + #pragma omp task + { + usleep (2000); + exit (0); + } + } + else + abort (); +} + +int +main () +{ + #pragma omp parallel num_threads (2) + { + #pragma omp barrier + #pragma omp single + foo (); + } + exit (0); +}