From 4e65deeffb7205dc20b70fdfbce51bc6b381f0db Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 16 May 2019 23:44:40 +0200 Subject: [PATCH] omp-low.c (lower_rec_input_clauses): If OMP_CLAUSE_IF has non-constant expression... * omp-low.c (lower_rec_input_clauses): If OMP_CLAUSE_IF has non-constant expression, force sctx.lane and use two argument IFN_GOMP_SIMD_LANE instead of single argument. * tree-ssa-dce.c (eliminate_unnecessary_stmts): Don't DCE two argument IFN_GOMP_SIMD_LANE without lhs. * tree-vectorizer.h (struct _loop_vec_info): Add simd_if_cond member. (LOOP_VINFO_SIMD_IF_COND, LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND): Define. (LOOP_REQUIRES_VERSIONING): Or in LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND. * tree-vect-loop.c (_loop_vec_info::_loop_vec_info): Initialize simd_if_cond. (vect_analyze_loop_2): Punt if LOOP_VINFO_SIMD_IF_COND is constant 0. * tree-vect-loop-manip.c (vect_loop_versioning): Add runtime check from simd if clause if needed. * gcc.dg/vect/vect-simd-1.c: New test. * gcc.dg/vect/vect-simd-2.c: New test. * gcc.dg/vect/vect-simd-3.c: New test. * gcc.dg/vect/vect-simd-4.c: New test. From-SVN: r271298 --- gcc/ChangeLog | 19 ++++++++ gcc/omp-low.c | 19 +++++++- gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/gcc.dg/vect/vect-simd-1.c | 64 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/vect/vect-simd-2.c | 18 +++++++ gcc/testsuite/gcc.dg/vect/vect-simd-3.c | 17 +++++++ gcc/testsuite/gcc.dg/vect/vect-simd-4.c | 18 +++++++ gcc/tree-ssa-dce.c | 8 +++- gcc/tree-vect-loop-manip.c | 27 +++++++++++ gcc/tree-vect-loop.c | 26 ++++++++++ gcc/tree-vectorizer.h | 13 ++++- 11 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-simd-1.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-simd-2.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-simd-3.c create mode 100644 gcc/testsuite/gcc.dg/vect/vect-simd-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e618471b8d1..232a7d6546d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2019-05-16 Jakub Jelinek + + * omp-low.c (lower_rec_input_clauses): If OMP_CLAUSE_IF + has non-constant expression, force sctx.lane and use two + argument IFN_GOMP_SIMD_LANE instead of single argument. + * tree-ssa-dce.c (eliminate_unnecessary_stmts): Don't DCE + two argument IFN_GOMP_SIMD_LANE without lhs. + * tree-vectorizer.h (struct _loop_vec_info): Add simd_if_cond + member. + (LOOP_VINFO_SIMD_IF_COND, LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND): + Define. + (LOOP_REQUIRES_VERSIONING): Or in + LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND. + * tree-vect-loop.c (_loop_vec_info::_loop_vec_info): Initialize + simd_if_cond. + (vect_analyze_loop_2): Punt if LOOP_VINFO_SIMD_IF_COND is constant 0. + * tree-vect-loop-manip.c (vect_loop_versioning): Add runtime check + from simd if clause if needed. + 2019-05-16 Richard Biener * tree-affine.c (expr_to_aff_combination): New function split diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 3a3d09c3b34..04fc5f6aaa8 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -3783,6 +3783,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, tree simt_lane = NULL_TREE, simtrec = NULL_TREE; tree ivar = NULL_TREE, lvar = NULL_TREE, uid = NULL_TREE; gimple_seq llist[3] = { }; + tree nonconst_simd_if = NULL_TREE; copyin_seq = NULL; sctx.is_simt = is_simd && omp_find_clause (clauses, OMP_CLAUSE__SIMT_); @@ -3814,6 +3815,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, case OMP_CLAUSE_IF: if (integer_zerop (OMP_CLAUSE_IF_EXPR (c))) sctx.max_vf = 1; + else if (TREE_CODE (OMP_CLAUSE_IF_EXPR (c)) != INTEGER_CST) + nonconst_simd_if = OMP_CLAUSE_IF_EXPR (c); break; case OMP_CLAUSE_SIMDLEN: if (integer_onep (OMP_CLAUSE_SIMDLEN_EXPR (c))) @@ -5190,6 +5193,17 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (known_eq (sctx.max_vf, 1U)) sctx.is_simt = false; + if (nonconst_simd_if) + { + if (sctx.lane == NULL_TREE) + { + sctx.idx = create_tmp_var (unsigned_type_node); + sctx.lane = create_tmp_var (unsigned_type_node); + } + /* FIXME: For now. */ + sctx.is_simt = false; + } + if (sctx.lane || sctx.is_simt) { uid = create_tmp_var (ptr_type_node, "simduid"); @@ -5219,8 +5233,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } if (sctx.lane) { - gimple *g - = gimple_build_call_internal (IFN_GOMP_SIMD_LANE, 1, uid); + gimple *g = gimple_build_call_internal (IFN_GOMP_SIMD_LANE, + 1 + (nonconst_simd_if != NULL), + uid, nonconst_simd_if); gimple_call_set_lhs (g, sctx.lane); gimple_stmt_iterator gsi = gsi_start_1 (gimple_omp_body_ptr (ctx->stmt)); gsi_insert_before_without_update (&gsi, g, GSI_SAME_STMT); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 36dbb1ba8b0..c352cebe46e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-05-16 Jakub Jelinek + + * gcc.dg/vect/vect-simd-1.c: New test. + * gcc.dg/vect/vect-simd-2.c: New test. + * gcc.dg/vect/vect-simd-3.c: New test. + * gcc.dg/vect/vect-simd-4.c: New test. + 2019-05-16 Martin Liska PR lto/90500 diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-1.c b/gcc/testsuite/gcc.dg/vect/vect-simd-1.c new file mode 100644 index 00000000000..7c3feeeffae --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-1.c @@ -0,0 +1,64 @@ +/* { dg-additional-options "-fopenmp-simd" } */ +/* { dg-additional-options "-mavx" { target avx_runtime } } */ + +#include "tree-vect.h" + +#define N 1024 +int a[N]; +int x; + +__attribute__((noipa)) int +bar (void) +{ + return x; +} + +__attribute__((noipa)) void +foo (void) +{ + #pragma omp simd if (bar ()) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +__attribute__((noipa)) void +baz (void) +{ + int c = 0; + #pragma omp simd if (c) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +__attribute__((noipa)) void +qux (void) +{ + int c = 1; + #pragma omp simd if (c) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +int +main () +{ + check_vect (); + foo (); + for (int i = 0; i < N; ++i) + if (a[i] != 1) + abort (); + x = 1; + foo (); + for (int i = 0; i < N; ++i) + if (a[i] != 2) + abort (); + baz (); + for (int i = 0; i < N; ++i) + if (a[i] != 3) + abort (); + qux (); + for (int i = 0; i < N; ++i) + if (a[i] != 4) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-2.c b/gcc/testsuite/gcc.dg/vect/vect-simd-2.c new file mode 100644 index 00000000000..42bb782a801 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fopenmp-simd" } */ + +#define N 1024 +int a[N]; +int bar (void); + +void +foo (void) +{ + #pragma omp simd if (bar ()) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "created versioning for simd if condition check" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-3.c b/gcc/testsuite/gcc.dg/vect/vect-simd-3.c new file mode 100644 index 00000000000..ff7f0dcc7a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fopenmp-simd" } */ + +#define N 1024 +int a[N]; + +void +foo (void) +{ + int c = 0; + #pragma omp simd if (c) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-4.c b/gcc/testsuite/gcc.dg/vect/vect-simd-4.c new file mode 100644 index 00000000000..b78b7b1dbe1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-4.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fopenmp-simd" } */ + +#define N 1024 +int a[N]; + +void +foo (void) +{ + int c = 1; + #pragma omp simd if (c) + for (int i = 0; i < N; ++i) + a[i] = a[i] + 1; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-not "created versioning for simd if condition check" "vect" } } */ diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 4853f0bd73e..2478219d873 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1328,12 +1328,16 @@ eliminate_unnecessary_stmts (void) update_stmt (stmt); release_ssa_name (name); - /* GOMP_SIMD_LANE or ASAN_POISON without lhs is not - needed. */ + /* GOMP_SIMD_LANE (unless two argument) or ASAN_POISON + without lhs is not needed. */ if (gimple_call_internal_p (stmt)) switch (gimple_call_internal_fn (stmt)) { case IFN_GOMP_SIMD_LANE: + if (gimple_call_num_args (stmt) >= 2 + && !integer_nonzerop (gimple_call_arg (stmt, 1))) + break; + /* FALLTHRU */ case IFN_ASAN_POISON: remove_dead_stmt (&gsi, bb, to_remove_edges); break; diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index 77d3dac771e..b3fae5ba4da 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -3009,6 +3009,8 @@ vect_loop_versioning (loop_vec_info loop_vinfo, bool version_align = LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (loop_vinfo); bool version_alias = LOOP_REQUIRES_VERSIONING_FOR_ALIAS (loop_vinfo); bool version_niter = LOOP_REQUIRES_VERSIONING_FOR_NITERS (loop_vinfo); + tree version_simd_if_cond + = LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND (loop_vinfo); if (check_profitability) cond_expr = fold_build2 (GE_EXPR, boolean_type_node, scalar_loop_iters, @@ -3044,6 +3046,31 @@ vect_loop_versioning (loop_vec_info loop_vinfo, vect_create_cond_for_alias_checks (loop_vinfo, &cond_expr); } + if (version_simd_if_cond) + { + gcc_assert (dom_info_available_p (CDI_DOMINATORS)); + if (flag_checking) + if (basic_block bb + = gimple_bb (SSA_NAME_DEF_STMT (version_simd_if_cond))) + gcc_assert (bb != loop->header + && dominated_by_p (CDI_DOMINATORS, loop->header, bb) + && (scalar_loop == NULL + || (bb != scalar_loop->header + && dominated_by_p (CDI_DOMINATORS, + scalar_loop->header, bb)))); + tree zero = build_zero_cst (TREE_TYPE (version_simd_if_cond)); + tree c = fold_build2 (NE_EXPR, boolean_type_node, + version_simd_if_cond, zero); + if (cond_expr) + cond_expr = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, + c, cond_expr); + else + cond_expr = c; + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "created versioning for simd if condition check.\n"); + } + cond_expr = force_gimple_operand_1 (unshare_expr (cond_expr), &gimplify_stmt_list, is_gimple_condexpr, NULL_TREE); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 057a8742677..57764176df0 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -819,6 +819,7 @@ _loop_vec_info::_loop_vec_info (struct loop *loop_in, vec_info_shared *shared) max_vectorization_factor (0), mask_skip_niters (NULL_TREE), mask_compare_type (NULL_TREE), + simd_if_cond (NULL_TREE), unaligned_dr (NULL), peeling_for_alignment (0), ptr_mask (0), @@ -862,6 +863,26 @@ _loop_vec_info::_loop_vec_info (struct loop *loop_in, vec_info_shared *shared) gimple *stmt = gsi_stmt (si); gimple_set_uid (stmt, 0); add_stmt (stmt); + /* If .GOMP_SIMD_LANE call for the current loop has 2 arguments, the + second argument is the #pragma omp simd if (x) condition, when 0, + loop shouldn't be vectorized, when non-zero constant, it should + be vectorized normally, otherwise versioned with vectorized loop + done if the condition is non-zero at runtime. */ + if (loop_in->simduid + && is_gimple_call (stmt) + && gimple_call_internal_p (stmt) + && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE + && gimple_call_num_args (stmt) >= 2 + && TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME + && (loop_in->simduid + == SSA_NAME_VAR (gimple_call_arg (stmt, 0)))) + { + tree arg = gimple_call_arg (stmt, 1); + if (integer_zerop (arg) || TREE_CODE (arg) == SSA_NAME) + simd_if_cond = arg; + else + gcc_assert (integer_nonzerop (arg)); + } } } } @@ -1769,6 +1790,11 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal, unsigned *n_stmts) /* The first group of checks is independent of the vector size. */ fatal = true; + if (LOOP_VINFO_SIMD_IF_COND (loop_vinfo) + && integer_zerop (LOOP_VINFO_SIMD_IF_COND (loop_vinfo))) + return opt_result::failure_at (vect_location, + "not vectorized: simd if(0)\n"); + /* Find all data references in the loop (which correspond to vdefs/vuses) and analyze their evolution in the loop. */ diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 6f59af64163..d5fd4690b1d 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -428,6 +428,13 @@ typedef struct _loop_vec_info : public vec_info { loops. */ tree mask_compare_type; + /* For #pragma omp simd if (x) loops the x expression. If constant 0, + the loop should not be vectorized, if constant non-zero, simd_if_cond + shouldn't be set and loop vectorized normally, if SSA_NAME, the loop + should be versioned on that condition, using scalar loop if the condition + is false and vectorized loop otherwise. */ + tree simd_if_cond; + /* Unknown DRs according to which loop was peeled. */ struct dr_vec_info *unaligned_dr; @@ -591,6 +598,7 @@ typedef struct _loop_vec_info : public vec_info { #define LOOP_VINFO_SCALAR_ITERATION_COST(L) (L)->scalar_cost_vec #define LOOP_VINFO_SINGLE_SCALAR_ITERATION_COST(L) (L)->single_scalar_iteration_cost #define LOOP_VINFO_ORIG_LOOP_INFO(L) (L)->orig_loop_info +#define LOOP_VINFO_SIMD_IF_COND(L) (L)->simd_if_cond #define LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT(L) \ ((L)->may_misalign_stmts.length () > 0) @@ -600,10 +608,13 @@ typedef struct _loop_vec_info : public vec_info { || (L)->lower_bounds.length () > 0) #define LOOP_REQUIRES_VERSIONING_FOR_NITERS(L) \ (LOOP_VINFO_NITERS_ASSUMPTIONS (L)) +#define LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND(L) \ + (LOOP_VINFO_SIMD_IF_COND (L)) #define LOOP_REQUIRES_VERSIONING(L) \ (LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (L) \ || LOOP_REQUIRES_VERSIONING_FOR_ALIAS (L) \ - || LOOP_REQUIRES_VERSIONING_FOR_NITERS (L)) + || LOOP_REQUIRES_VERSIONING_FOR_NITERS (L) \ + || LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND (L)) #define LOOP_VINFO_NITERS_KNOWN_P(L) \ (tree_fits_shwi_p ((L)->num_iters) && tree_to_shwi ((L)->num_iters) > 0) -- 2.30.2