138fd1498Szrj /* Expansion pass for OMP directives. Outlines regions of certain OMP
238fd1498Szrj directives to separate functions, converts others into explicit calls to the
338fd1498Szrj runtime library (libgomp) and so forth
438fd1498Szrj
538fd1498Szrj Copyright (C) 2005-2018 Free Software Foundation, Inc.
638fd1498Szrj
738fd1498Szrj This file is part of GCC.
838fd1498Szrj
938fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
1038fd1498Szrj the terms of the GNU General Public License as published by the Free
1138fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1238fd1498Szrj version.
1338fd1498Szrj
1438fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1538fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1638fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1738fd1498Szrj for more details.
1838fd1498Szrj
1938fd1498Szrj You should have received a copy of the GNU General Public License
2038fd1498Szrj along with GCC; see the file COPYING3. If not see
2138fd1498Szrj <http://www.gnu.org/licenses/>. */
2238fd1498Szrj
2338fd1498Szrj #include "config.h"
2438fd1498Szrj #include "system.h"
2538fd1498Szrj #include "coretypes.h"
2638fd1498Szrj #include "memmodel.h"
2738fd1498Szrj #include "backend.h"
2838fd1498Szrj #include "target.h"
2938fd1498Szrj #include "rtl.h"
3038fd1498Szrj #include "tree.h"
3138fd1498Szrj #include "gimple.h"
3238fd1498Szrj #include "cfghooks.h"
3338fd1498Szrj #include "tree-pass.h"
3438fd1498Szrj #include "ssa.h"
3538fd1498Szrj #include "optabs.h"
3638fd1498Szrj #include "cgraph.h"
3738fd1498Szrj #include "pretty-print.h"
3838fd1498Szrj #include "diagnostic-core.h"
3938fd1498Szrj #include "fold-const.h"
4038fd1498Szrj #include "stor-layout.h"
4138fd1498Szrj #include "cfganal.h"
4238fd1498Szrj #include "internal-fn.h"
4338fd1498Szrj #include "gimplify.h"
4438fd1498Szrj #include "gimple-iterator.h"
4538fd1498Szrj #include "gimplify-me.h"
4638fd1498Szrj #include "gimple-walk.h"
4738fd1498Szrj #include "tree-cfg.h"
4838fd1498Szrj #include "tree-into-ssa.h"
4938fd1498Szrj #include "tree-ssa.h"
5038fd1498Szrj #include "splay-tree.h"
5138fd1498Szrj #include "cfgloop.h"
5238fd1498Szrj #include "omp-general.h"
5338fd1498Szrj #include "omp-offload.h"
5438fd1498Szrj #include "tree-cfgcleanup.h"
5538fd1498Szrj #include "symbol-summary.h"
5638fd1498Szrj #include "gomp-constants.h"
5738fd1498Szrj #include "gimple-pretty-print.h"
5838fd1498Szrj #include "hsa-common.h"
5938fd1498Szrj #include "stringpool.h"
6038fd1498Szrj #include "attribs.h"
6138fd1498Szrj
6238fd1498Szrj /* OMP region information. Every parallel and workshare
6338fd1498Szrj directive is enclosed between two markers, the OMP_* directive
6438fd1498Szrj and a corresponding GIMPLE_OMP_RETURN statement. */
6538fd1498Szrj
6638fd1498Szrj struct omp_region
6738fd1498Szrj {
6838fd1498Szrj /* The enclosing region. */
6938fd1498Szrj struct omp_region *outer;
7038fd1498Szrj
7138fd1498Szrj /* First child region. */
7238fd1498Szrj struct omp_region *inner;
7338fd1498Szrj
7438fd1498Szrj /* Next peer region. */
7538fd1498Szrj struct omp_region *next;
7638fd1498Szrj
7738fd1498Szrj /* Block containing the omp directive as its last stmt. */
7838fd1498Szrj basic_block entry;
7938fd1498Szrj
8038fd1498Szrj /* Block containing the GIMPLE_OMP_RETURN as its last stmt. */
8138fd1498Szrj basic_block exit;
8238fd1498Szrj
8338fd1498Szrj /* Block containing the GIMPLE_OMP_CONTINUE as its last stmt. */
8438fd1498Szrj basic_block cont;
8538fd1498Szrj
8638fd1498Szrj /* If this is a combined parallel+workshare region, this is a list
8738fd1498Szrj of additional arguments needed by the combined parallel+workshare
8838fd1498Szrj library call. */
8938fd1498Szrj vec<tree, va_gc> *ws_args;
9038fd1498Szrj
9138fd1498Szrj /* The code for the omp directive of this region. */
9238fd1498Szrj enum gimple_code type;
9338fd1498Szrj
9438fd1498Szrj /* Schedule kind, only used for GIMPLE_OMP_FOR type regions. */
9538fd1498Szrj enum omp_clause_schedule_kind sched_kind;
9638fd1498Szrj
9738fd1498Szrj /* Schedule modifiers. */
9838fd1498Szrj unsigned char sched_modifiers;
9938fd1498Szrj
10038fd1498Szrj /* True if this is a combined parallel+workshare region. */
10138fd1498Szrj bool is_combined_parallel;
10238fd1498Szrj
10338fd1498Szrj /* The ordered stmt if type is GIMPLE_OMP_ORDERED and it has
10438fd1498Szrj a depend clause. */
10538fd1498Szrj gomp_ordered *ord_stmt;
10638fd1498Szrj };
10738fd1498Szrj
10838fd1498Szrj static struct omp_region *root_omp_region;
10938fd1498Szrj static bool omp_any_child_fn_dumped;
11038fd1498Szrj
11138fd1498Szrj static void expand_omp_build_assign (gimple_stmt_iterator *, tree, tree,
11238fd1498Szrj bool = false);
11338fd1498Szrj static gphi *find_phi_with_arg_on_edge (tree, edge);
11438fd1498Szrj static void expand_omp (struct omp_region *region);
11538fd1498Szrj
11638fd1498Szrj /* Return true if REGION is a combined parallel+workshare region. */
11738fd1498Szrj
11838fd1498Szrj static inline bool
is_combined_parallel(struct omp_region * region)11938fd1498Szrj is_combined_parallel (struct omp_region *region)
12038fd1498Szrj {
12138fd1498Szrj return region->is_combined_parallel;
12238fd1498Szrj }
12338fd1498Szrj
12438fd1498Szrj /* Given two blocks PAR_ENTRY_BB and WS_ENTRY_BB such that WS_ENTRY_BB
12538fd1498Szrj is the immediate dominator of PAR_ENTRY_BB, return true if there
12638fd1498Szrj are no data dependencies that would prevent expanding the parallel
12738fd1498Szrj directive at PAR_ENTRY_BB as a combined parallel+workshare region.
12838fd1498Szrj
12938fd1498Szrj When expanding a combined parallel+workshare region, the call to
13038fd1498Szrj the child function may need additional arguments in the case of
13138fd1498Szrj GIMPLE_OMP_FOR regions. In some cases, these arguments are
13238fd1498Szrj computed out of variables passed in from the parent to the child
13338fd1498Szrj via 'struct .omp_data_s'. For instance:
13438fd1498Szrj
13538fd1498Szrj #pragma omp parallel for schedule (guided, i * 4)
13638fd1498Szrj for (j ...)
13738fd1498Szrj
13838fd1498Szrj Is lowered into:
13938fd1498Szrj
14038fd1498Szrj # BLOCK 2 (PAR_ENTRY_BB)
14138fd1498Szrj .omp_data_o.i = i;
14238fd1498Szrj #pragma omp parallel [child fn: bar.omp_fn.0 ( ..., D.1598)
14338fd1498Szrj
14438fd1498Szrj # BLOCK 3 (WS_ENTRY_BB)
14538fd1498Szrj .omp_data_i = &.omp_data_o;
14638fd1498Szrj D.1667 = .omp_data_i->i;
14738fd1498Szrj D.1598 = D.1667 * 4;
14838fd1498Szrj #pragma omp for schedule (guided, D.1598)
14938fd1498Szrj
15038fd1498Szrj When we outline the parallel region, the call to the child function
15138fd1498Szrj 'bar.omp_fn.0' will need the value D.1598 in its argument list, but
15238fd1498Szrj that value is computed *after* the call site. So, in principle we
15338fd1498Szrj cannot do the transformation.
15438fd1498Szrj
15538fd1498Szrj To see whether the code in WS_ENTRY_BB blocks the combined
15638fd1498Szrj parallel+workshare call, we collect all the variables used in the
15738fd1498Szrj GIMPLE_OMP_FOR header check whether they appear on the LHS of any
15838fd1498Szrj statement in WS_ENTRY_BB. If so, then we cannot emit the combined
15938fd1498Szrj call.
16038fd1498Szrj
16138fd1498Szrj FIXME. If we had the SSA form built at this point, we could merely
16238fd1498Szrj hoist the code in block 3 into block 2 and be done with it. But at
16338fd1498Szrj this point we don't have dataflow information and though we could
16438fd1498Szrj hack something up here, it is really not worth the aggravation. */
16538fd1498Szrj
16638fd1498Szrj static bool
workshare_safe_to_combine_p(basic_block ws_entry_bb)16738fd1498Szrj workshare_safe_to_combine_p (basic_block ws_entry_bb)
16838fd1498Szrj {
16938fd1498Szrj struct omp_for_data fd;
17038fd1498Szrj gimple *ws_stmt = last_stmt (ws_entry_bb);
17138fd1498Szrj
17238fd1498Szrj if (gimple_code (ws_stmt) == GIMPLE_OMP_SECTIONS)
17338fd1498Szrj return true;
17438fd1498Szrj
17538fd1498Szrj gcc_assert (gimple_code (ws_stmt) == GIMPLE_OMP_FOR);
17638fd1498Szrj
17738fd1498Szrj omp_extract_for_data (as_a <gomp_for *> (ws_stmt), &fd, NULL);
17838fd1498Szrj
17938fd1498Szrj if (fd.collapse > 1 && TREE_CODE (fd.loop.n2) != INTEGER_CST)
18038fd1498Szrj return false;
18138fd1498Szrj if (fd.iter_type != long_integer_type_node)
18238fd1498Szrj return false;
18338fd1498Szrj
18438fd1498Szrj /* FIXME. We give up too easily here. If any of these arguments
18538fd1498Szrj are not constants, they will likely involve variables that have
18638fd1498Szrj been mapped into fields of .omp_data_s for sharing with the child
18738fd1498Szrj function. With appropriate data flow, it would be possible to
18838fd1498Szrj see through this. */
18938fd1498Szrj if (!is_gimple_min_invariant (fd.loop.n1)
19038fd1498Szrj || !is_gimple_min_invariant (fd.loop.n2)
19138fd1498Szrj || !is_gimple_min_invariant (fd.loop.step)
19238fd1498Szrj || (fd.chunk_size && !is_gimple_min_invariant (fd.chunk_size)))
19338fd1498Szrj return false;
19438fd1498Szrj
19538fd1498Szrj return true;
19638fd1498Szrj }
19738fd1498Szrj
19838fd1498Szrj /* Adjust CHUNK_SIZE from SCHEDULE clause, depending on simd modifier
19938fd1498Szrj presence (SIMD_SCHEDULE). */
20038fd1498Szrj
20138fd1498Szrj static tree
omp_adjust_chunk_size(tree chunk_size,bool simd_schedule)20238fd1498Szrj omp_adjust_chunk_size (tree chunk_size, bool simd_schedule)
20338fd1498Szrj {
20438fd1498Szrj if (!simd_schedule)
20538fd1498Szrj return chunk_size;
20638fd1498Szrj
20738fd1498Szrj poly_uint64 vf = omp_max_vf ();
20838fd1498Szrj if (known_eq (vf, 1U))
20938fd1498Szrj return chunk_size;
21038fd1498Szrj
21138fd1498Szrj tree type = TREE_TYPE (chunk_size);
21238fd1498Szrj chunk_size = fold_build2 (PLUS_EXPR, type, chunk_size,
21338fd1498Szrj build_int_cst (type, vf - 1));
21438fd1498Szrj return fold_build2 (BIT_AND_EXPR, type, chunk_size,
21538fd1498Szrj build_int_cst (type, -vf));
21638fd1498Szrj }
21738fd1498Szrj
21838fd1498Szrj /* Collect additional arguments needed to emit a combined
21938fd1498Szrj parallel+workshare call. WS_STMT is the workshare directive being
22038fd1498Szrj expanded. */
22138fd1498Szrj
22238fd1498Szrj static vec<tree, va_gc> *
get_ws_args_for(gimple * par_stmt,gimple * ws_stmt)22338fd1498Szrj get_ws_args_for (gimple *par_stmt, gimple *ws_stmt)
22438fd1498Szrj {
22538fd1498Szrj tree t;
22638fd1498Szrj location_t loc = gimple_location (ws_stmt);
22738fd1498Szrj vec<tree, va_gc> *ws_args;
22838fd1498Szrj
22938fd1498Szrj if (gomp_for *for_stmt = dyn_cast <gomp_for *> (ws_stmt))
23038fd1498Szrj {
23138fd1498Szrj struct omp_for_data fd;
23238fd1498Szrj tree n1, n2;
23338fd1498Szrj
23438fd1498Szrj omp_extract_for_data (for_stmt, &fd, NULL);
23538fd1498Szrj n1 = fd.loop.n1;
23638fd1498Szrj n2 = fd.loop.n2;
23738fd1498Szrj
23838fd1498Szrj if (gimple_omp_for_combined_into_p (for_stmt))
23938fd1498Szrj {
24038fd1498Szrj tree innerc
24138fd1498Szrj = omp_find_clause (gimple_omp_parallel_clauses (par_stmt),
24238fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
24338fd1498Szrj gcc_assert (innerc);
24438fd1498Szrj n1 = OMP_CLAUSE_DECL (innerc);
24538fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
24638fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
24738fd1498Szrj gcc_assert (innerc);
24838fd1498Szrj n2 = OMP_CLAUSE_DECL (innerc);
24938fd1498Szrj }
25038fd1498Szrj
25138fd1498Szrj vec_alloc (ws_args, 3 + (fd.chunk_size != 0));
25238fd1498Szrj
25338fd1498Szrj t = fold_convert_loc (loc, long_integer_type_node, n1);
25438fd1498Szrj ws_args->quick_push (t);
25538fd1498Szrj
25638fd1498Szrj t = fold_convert_loc (loc, long_integer_type_node, n2);
25738fd1498Szrj ws_args->quick_push (t);
25838fd1498Szrj
25938fd1498Szrj t = fold_convert_loc (loc, long_integer_type_node, fd.loop.step);
26038fd1498Szrj ws_args->quick_push (t);
26138fd1498Szrj
26238fd1498Szrj if (fd.chunk_size)
26338fd1498Szrj {
26438fd1498Szrj t = fold_convert_loc (loc, long_integer_type_node, fd.chunk_size);
26538fd1498Szrj t = omp_adjust_chunk_size (t, fd.simd_schedule);
26638fd1498Szrj ws_args->quick_push (t);
26738fd1498Szrj }
26838fd1498Szrj
26938fd1498Szrj return ws_args;
27038fd1498Szrj }
27138fd1498Szrj else if (gimple_code (ws_stmt) == GIMPLE_OMP_SECTIONS)
27238fd1498Szrj {
27338fd1498Szrj /* Number of sections is equal to the number of edges from the
27438fd1498Szrj GIMPLE_OMP_SECTIONS_SWITCH statement, except for the one to
27538fd1498Szrj the exit of the sections region. */
27638fd1498Szrj basic_block bb = single_succ (gimple_bb (ws_stmt));
27738fd1498Szrj t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs) - 1);
27838fd1498Szrj vec_alloc (ws_args, 1);
27938fd1498Szrj ws_args->quick_push (t);
28038fd1498Szrj return ws_args;
28138fd1498Szrj }
28238fd1498Szrj
28338fd1498Szrj gcc_unreachable ();
28438fd1498Szrj }
28538fd1498Szrj
28638fd1498Szrj /* Discover whether REGION is a combined parallel+workshare region. */
28738fd1498Szrj
28838fd1498Szrj static void
determine_parallel_type(struct omp_region * region)28938fd1498Szrj determine_parallel_type (struct omp_region *region)
29038fd1498Szrj {
29138fd1498Szrj basic_block par_entry_bb, par_exit_bb;
29238fd1498Szrj basic_block ws_entry_bb, ws_exit_bb;
29338fd1498Szrj
29438fd1498Szrj if (region == NULL || region->inner == NULL
29538fd1498Szrj || region->exit == NULL || region->inner->exit == NULL
29638fd1498Szrj || region->inner->cont == NULL)
29738fd1498Szrj return;
29838fd1498Szrj
29938fd1498Szrj /* We only support parallel+for and parallel+sections. */
30038fd1498Szrj if (region->type != GIMPLE_OMP_PARALLEL
30138fd1498Szrj || (region->inner->type != GIMPLE_OMP_FOR
30238fd1498Szrj && region->inner->type != GIMPLE_OMP_SECTIONS))
30338fd1498Szrj return;
30438fd1498Szrj
30538fd1498Szrj /* Check for perfect nesting PAR_ENTRY_BB -> WS_ENTRY_BB and
30638fd1498Szrj WS_EXIT_BB -> PAR_EXIT_BB. */
30738fd1498Szrj par_entry_bb = region->entry;
30838fd1498Szrj par_exit_bb = region->exit;
30938fd1498Szrj ws_entry_bb = region->inner->entry;
31038fd1498Szrj ws_exit_bb = region->inner->exit;
31138fd1498Szrj
31238fd1498Szrj if (single_succ (par_entry_bb) == ws_entry_bb
31338fd1498Szrj && single_succ (ws_exit_bb) == par_exit_bb
31438fd1498Szrj && workshare_safe_to_combine_p (ws_entry_bb)
31538fd1498Szrj && (gimple_omp_parallel_combined_p (last_stmt (par_entry_bb))
31638fd1498Szrj || (last_and_only_stmt (ws_entry_bb)
31738fd1498Szrj && last_and_only_stmt (par_exit_bb))))
31838fd1498Szrj {
31938fd1498Szrj gimple *par_stmt = last_stmt (par_entry_bb);
32038fd1498Szrj gimple *ws_stmt = last_stmt (ws_entry_bb);
32138fd1498Szrj
32238fd1498Szrj if (region->inner->type == GIMPLE_OMP_FOR)
32338fd1498Szrj {
32438fd1498Szrj /* If this is a combined parallel loop, we need to determine
32538fd1498Szrj whether or not to use the combined library calls. There
32638fd1498Szrj are two cases where we do not apply the transformation:
32738fd1498Szrj static loops and any kind of ordered loop. In the first
32838fd1498Szrj case, we already open code the loop so there is no need
32938fd1498Szrj to do anything else. In the latter case, the combined
33038fd1498Szrj parallel loop call would still need extra synchronization
33138fd1498Szrj to implement ordered semantics, so there would not be any
33238fd1498Szrj gain in using the combined call. */
33338fd1498Szrj tree clauses = gimple_omp_for_clauses (ws_stmt);
33438fd1498Szrj tree c = omp_find_clause (clauses, OMP_CLAUSE_SCHEDULE);
33538fd1498Szrj if (c == NULL
33638fd1498Szrj || ((OMP_CLAUSE_SCHEDULE_KIND (c) & OMP_CLAUSE_SCHEDULE_MASK)
33738fd1498Szrj == OMP_CLAUSE_SCHEDULE_STATIC)
33838fd1498Szrj || omp_find_clause (clauses, OMP_CLAUSE_ORDERED))
33938fd1498Szrj {
34038fd1498Szrj region->is_combined_parallel = false;
34138fd1498Szrj region->inner->is_combined_parallel = false;
34238fd1498Szrj return;
34338fd1498Szrj }
34438fd1498Szrj }
34538fd1498Szrj
34638fd1498Szrj region->is_combined_parallel = true;
34738fd1498Szrj region->inner->is_combined_parallel = true;
34838fd1498Szrj region->ws_args = get_ws_args_for (par_stmt, ws_stmt);
34938fd1498Szrj }
35038fd1498Szrj }
35138fd1498Szrj
35238fd1498Szrj /* Debugging dumps for parallel regions. */
35338fd1498Szrj void dump_omp_region (FILE *, struct omp_region *, int);
35438fd1498Szrj void debug_omp_region (struct omp_region *);
35538fd1498Szrj void debug_all_omp_regions (void);
35638fd1498Szrj
35738fd1498Szrj /* Dump the parallel region tree rooted at REGION. */
35838fd1498Szrj
35938fd1498Szrj void
dump_omp_region(FILE * file,struct omp_region * region,int indent)36038fd1498Szrj dump_omp_region (FILE *file, struct omp_region *region, int indent)
36138fd1498Szrj {
36238fd1498Szrj fprintf (file, "%*sbb %d: %s\n", indent, "", region->entry->index,
36338fd1498Szrj gimple_code_name[region->type]);
36438fd1498Szrj
36538fd1498Szrj if (region->inner)
36638fd1498Szrj dump_omp_region (file, region->inner, indent + 4);
36738fd1498Szrj
36838fd1498Szrj if (region->cont)
36938fd1498Szrj {
37038fd1498Szrj fprintf (file, "%*sbb %d: GIMPLE_OMP_CONTINUE\n", indent, "",
37138fd1498Szrj region->cont->index);
37238fd1498Szrj }
37338fd1498Szrj
37438fd1498Szrj if (region->exit)
37538fd1498Szrj fprintf (file, "%*sbb %d: GIMPLE_OMP_RETURN\n", indent, "",
37638fd1498Szrj region->exit->index);
37738fd1498Szrj else
37838fd1498Szrj fprintf (file, "%*s[no exit marker]\n", indent, "");
37938fd1498Szrj
38038fd1498Szrj if (region->next)
38138fd1498Szrj dump_omp_region (file, region->next, indent);
38238fd1498Szrj }
38338fd1498Szrj
38438fd1498Szrj DEBUG_FUNCTION void
debug_omp_region(struct omp_region * region)38538fd1498Szrj debug_omp_region (struct omp_region *region)
38638fd1498Szrj {
38738fd1498Szrj dump_omp_region (stderr, region, 0);
38838fd1498Szrj }
38938fd1498Szrj
39038fd1498Szrj DEBUG_FUNCTION void
debug_all_omp_regions(void)39138fd1498Szrj debug_all_omp_regions (void)
39238fd1498Szrj {
39338fd1498Szrj dump_omp_region (stderr, root_omp_region, 0);
39438fd1498Szrj }
39538fd1498Szrj
39638fd1498Szrj /* Create a new parallel region starting at STMT inside region PARENT. */
39738fd1498Szrj
39838fd1498Szrj static struct omp_region *
new_omp_region(basic_block bb,enum gimple_code type,struct omp_region * parent)39938fd1498Szrj new_omp_region (basic_block bb, enum gimple_code type,
40038fd1498Szrj struct omp_region *parent)
40138fd1498Szrj {
40238fd1498Szrj struct omp_region *region = XCNEW (struct omp_region);
40338fd1498Szrj
40438fd1498Szrj region->outer = parent;
40538fd1498Szrj region->entry = bb;
40638fd1498Szrj region->type = type;
40738fd1498Szrj
40838fd1498Szrj if (parent)
40938fd1498Szrj {
41038fd1498Szrj /* This is a nested region. Add it to the list of inner
41138fd1498Szrj regions in PARENT. */
41238fd1498Szrj region->next = parent->inner;
41338fd1498Szrj parent->inner = region;
41438fd1498Szrj }
41538fd1498Szrj else
41638fd1498Szrj {
41738fd1498Szrj /* This is a toplevel region. Add it to the list of toplevel
41838fd1498Szrj regions in ROOT_OMP_REGION. */
41938fd1498Szrj region->next = root_omp_region;
42038fd1498Szrj root_omp_region = region;
42138fd1498Szrj }
42238fd1498Szrj
42338fd1498Szrj return region;
42438fd1498Szrj }
42538fd1498Szrj
42638fd1498Szrj /* Release the memory associated with the region tree rooted at REGION. */
42738fd1498Szrj
42838fd1498Szrj static void
free_omp_region_1(struct omp_region * region)42938fd1498Szrj free_omp_region_1 (struct omp_region *region)
43038fd1498Szrj {
43138fd1498Szrj struct omp_region *i, *n;
43238fd1498Szrj
43338fd1498Szrj for (i = region->inner; i ; i = n)
43438fd1498Szrj {
43538fd1498Szrj n = i->next;
43638fd1498Szrj free_omp_region_1 (i);
43738fd1498Szrj }
43838fd1498Szrj
43938fd1498Szrj free (region);
44038fd1498Szrj }
44138fd1498Szrj
44238fd1498Szrj /* Release the memory for the entire omp region tree. */
44338fd1498Szrj
44438fd1498Szrj void
omp_free_regions(void)44538fd1498Szrj omp_free_regions (void)
44638fd1498Szrj {
44738fd1498Szrj struct omp_region *r, *n;
44838fd1498Szrj for (r = root_omp_region; r ; r = n)
44938fd1498Szrj {
45038fd1498Szrj n = r->next;
45138fd1498Szrj free_omp_region_1 (r);
45238fd1498Szrj }
45338fd1498Szrj root_omp_region = NULL;
45438fd1498Szrj }
45538fd1498Szrj
45638fd1498Szrj /* A convenience function to build an empty GIMPLE_COND with just the
45738fd1498Szrj condition. */
45838fd1498Szrj
45938fd1498Szrj static gcond *
gimple_build_cond_empty(tree cond)46038fd1498Szrj gimple_build_cond_empty (tree cond)
46138fd1498Szrj {
46238fd1498Szrj enum tree_code pred_code;
46338fd1498Szrj tree lhs, rhs;
46438fd1498Szrj
46538fd1498Szrj gimple_cond_get_ops_from_tree (cond, &pred_code, &lhs, &rhs);
46638fd1498Szrj return gimple_build_cond (pred_code, lhs, rhs, NULL_TREE, NULL_TREE);
46738fd1498Szrj }
46838fd1498Szrj
46938fd1498Szrj /* Return true if a parallel REGION is within a declare target function or
47038fd1498Szrj within a target region and is not a part of a gridified target. */
47138fd1498Szrj
47238fd1498Szrj static bool
parallel_needs_hsa_kernel_p(struct omp_region * region)47338fd1498Szrj parallel_needs_hsa_kernel_p (struct omp_region *region)
47438fd1498Szrj {
47538fd1498Szrj bool indirect = false;
47638fd1498Szrj for (region = region->outer; region; region = region->outer)
47738fd1498Szrj {
47838fd1498Szrj if (region->type == GIMPLE_OMP_PARALLEL)
47938fd1498Szrj indirect = true;
48038fd1498Szrj else if (region->type == GIMPLE_OMP_TARGET)
48138fd1498Szrj {
48238fd1498Szrj gomp_target *tgt_stmt
48338fd1498Szrj = as_a <gomp_target *> (last_stmt (region->entry));
48438fd1498Szrj
48538fd1498Szrj if (omp_find_clause (gimple_omp_target_clauses (tgt_stmt),
48638fd1498Szrj OMP_CLAUSE__GRIDDIM_))
48738fd1498Szrj return indirect;
48838fd1498Szrj else
48938fd1498Szrj return true;
49038fd1498Szrj }
49138fd1498Szrj }
49238fd1498Szrj
49338fd1498Szrj if (lookup_attribute ("omp declare target",
49438fd1498Szrj DECL_ATTRIBUTES (current_function_decl)))
49538fd1498Szrj return true;
49638fd1498Szrj
49738fd1498Szrj return false;
49838fd1498Szrj }
49938fd1498Szrj
50038fd1498Szrj /* Change DECL_CONTEXT of CHILD_FNDECL to that of the parent function.
50138fd1498Szrj Add CHILD_FNDECL to decl chain of the supercontext of the block
50238fd1498Szrj ENTRY_BLOCK - this is the block which originally contained the
50338fd1498Szrj code from which CHILD_FNDECL was created.
50438fd1498Szrj
50538fd1498Szrj Together, these actions ensure that the debug info for the outlined
50638fd1498Szrj function will be emitted with the correct lexical scope. */
50738fd1498Szrj
50838fd1498Szrj static void
adjust_context_and_scope(struct omp_region * region,tree entry_block,tree child_fndecl)509*58e805e6Szrj adjust_context_and_scope (struct omp_region *region, tree entry_block,
510*58e805e6Szrj tree child_fndecl)
51138fd1498Szrj {
512*58e805e6Szrj tree parent_fndecl = NULL_TREE;
513*58e805e6Szrj gimple *entry_stmt;
514*58e805e6Szrj /* OMP expansion expands inner regions before outer ones, so if
515*58e805e6Szrj we e.g. have explicit task region nested in parallel region, when
516*58e805e6Szrj expanding the task region current_function_decl will be the original
517*58e805e6Szrj source function, but we actually want to use as context the child
518*58e805e6Szrj function of the parallel. */
519*58e805e6Szrj for (region = region->outer;
520*58e805e6Szrj region && parent_fndecl == NULL_TREE; region = region->outer)
521*58e805e6Szrj switch (region->type)
522*58e805e6Szrj {
523*58e805e6Szrj case GIMPLE_OMP_PARALLEL:
524*58e805e6Szrj case GIMPLE_OMP_TASK:
525*58e805e6Szrj entry_stmt = last_stmt (region->entry);
526*58e805e6Szrj parent_fndecl = gimple_omp_taskreg_child_fn (entry_stmt);
527*58e805e6Szrj break;
528*58e805e6Szrj case GIMPLE_OMP_TARGET:
529*58e805e6Szrj entry_stmt = last_stmt (region->entry);
530*58e805e6Szrj parent_fndecl
531*58e805e6Szrj = gimple_omp_target_child_fn (as_a <gomp_target *> (entry_stmt));
532*58e805e6Szrj break;
533*58e805e6Szrj default:
534*58e805e6Szrj break;
535*58e805e6Szrj }
536*58e805e6Szrj
537*58e805e6Szrj if (parent_fndecl == NULL_TREE)
538*58e805e6Szrj parent_fndecl = current_function_decl;
539*58e805e6Szrj DECL_CONTEXT (child_fndecl) = parent_fndecl;
540*58e805e6Szrj
54138fd1498Szrj if (entry_block != NULL_TREE && TREE_CODE (entry_block) == BLOCK)
54238fd1498Szrj {
54338fd1498Szrj tree b = BLOCK_SUPERCONTEXT (entry_block);
54438fd1498Szrj if (TREE_CODE (b) == BLOCK)
54538fd1498Szrj {
54638fd1498Szrj DECL_CHAIN (child_fndecl) = BLOCK_VARS (b);
54738fd1498Szrj BLOCK_VARS (b) = child_fndecl;
54838fd1498Szrj }
54938fd1498Szrj }
55038fd1498Szrj }
55138fd1498Szrj
55238fd1498Szrj /* Build the function calls to GOMP_parallel_start etc to actually
55338fd1498Szrj generate the parallel operation. REGION is the parallel region
55438fd1498Szrj being expanded. BB is the block where to insert the code. WS_ARGS
55538fd1498Szrj will be set if this is a call to a combined parallel+workshare
55638fd1498Szrj construct, it contains the list of additional arguments needed by
55738fd1498Szrj the workshare construct. */
55838fd1498Szrj
55938fd1498Szrj static void
expand_parallel_call(struct omp_region * region,basic_block bb,gomp_parallel * entry_stmt,vec<tree,va_gc> * ws_args)56038fd1498Szrj expand_parallel_call (struct omp_region *region, basic_block bb,
56138fd1498Szrj gomp_parallel *entry_stmt,
56238fd1498Szrj vec<tree, va_gc> *ws_args)
56338fd1498Szrj {
56438fd1498Szrj tree t, t1, t2, val, cond, c, clauses, flags;
56538fd1498Szrj gimple_stmt_iterator gsi;
56638fd1498Szrj gimple *stmt;
56738fd1498Szrj enum built_in_function start_ix;
56838fd1498Szrj int start_ix2;
56938fd1498Szrj location_t clause_loc;
57038fd1498Szrj vec<tree, va_gc> *args;
57138fd1498Szrj
57238fd1498Szrj clauses = gimple_omp_parallel_clauses (entry_stmt);
57338fd1498Szrj
57438fd1498Szrj /* Determine what flavor of GOMP_parallel we will be
57538fd1498Szrj emitting. */
57638fd1498Szrj start_ix = BUILT_IN_GOMP_PARALLEL;
57738fd1498Szrj if (is_combined_parallel (region))
57838fd1498Szrj {
57938fd1498Szrj switch (region->inner->type)
58038fd1498Szrj {
58138fd1498Szrj case GIMPLE_OMP_FOR:
58238fd1498Szrj gcc_assert (region->inner->sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
58338fd1498Szrj switch (region->inner->sched_kind)
58438fd1498Szrj {
58538fd1498Szrj case OMP_CLAUSE_SCHEDULE_RUNTIME:
58638fd1498Szrj start_ix2 = 3;
58738fd1498Szrj break;
58838fd1498Szrj case OMP_CLAUSE_SCHEDULE_DYNAMIC:
58938fd1498Szrj case OMP_CLAUSE_SCHEDULE_GUIDED:
59038fd1498Szrj if (region->inner->sched_modifiers
59138fd1498Szrj & OMP_CLAUSE_SCHEDULE_NONMONOTONIC)
59238fd1498Szrj {
59338fd1498Szrj start_ix2 = 3 + region->inner->sched_kind;
59438fd1498Szrj break;
59538fd1498Szrj }
59638fd1498Szrj /* FALLTHRU */
59738fd1498Szrj default:
59838fd1498Szrj start_ix2 = region->inner->sched_kind;
59938fd1498Szrj break;
60038fd1498Szrj }
60138fd1498Szrj start_ix2 += (int) BUILT_IN_GOMP_PARALLEL_LOOP_STATIC;
60238fd1498Szrj start_ix = (enum built_in_function) start_ix2;
60338fd1498Szrj break;
60438fd1498Szrj case GIMPLE_OMP_SECTIONS:
60538fd1498Szrj start_ix = BUILT_IN_GOMP_PARALLEL_SECTIONS;
60638fd1498Szrj break;
60738fd1498Szrj default:
60838fd1498Szrj gcc_unreachable ();
60938fd1498Szrj }
61038fd1498Szrj }
61138fd1498Szrj
61238fd1498Szrj /* By default, the value of NUM_THREADS is zero (selected at run time)
61338fd1498Szrj and there is no conditional. */
61438fd1498Szrj cond = NULL_TREE;
61538fd1498Szrj val = build_int_cst (unsigned_type_node, 0);
61638fd1498Szrj flags = build_int_cst (unsigned_type_node, 0);
61738fd1498Szrj
61838fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_IF);
61938fd1498Szrj if (c)
62038fd1498Szrj cond = OMP_CLAUSE_IF_EXPR (c);
62138fd1498Szrj
62238fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_NUM_THREADS);
62338fd1498Szrj if (c)
62438fd1498Szrj {
62538fd1498Szrj val = OMP_CLAUSE_NUM_THREADS_EXPR (c);
62638fd1498Szrj clause_loc = OMP_CLAUSE_LOCATION (c);
62738fd1498Szrj }
62838fd1498Szrj else
62938fd1498Szrj clause_loc = gimple_location (entry_stmt);
63038fd1498Szrj
63138fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_PROC_BIND);
63238fd1498Szrj if (c)
63338fd1498Szrj flags = build_int_cst (unsigned_type_node, OMP_CLAUSE_PROC_BIND_KIND (c));
63438fd1498Szrj
63538fd1498Szrj /* Ensure 'val' is of the correct type. */
63638fd1498Szrj val = fold_convert_loc (clause_loc, unsigned_type_node, val);
63738fd1498Szrj
63838fd1498Szrj /* If we found the clause 'if (cond)', build either
63938fd1498Szrj (cond != 0) or (cond ? val : 1u). */
64038fd1498Szrj if (cond)
64138fd1498Szrj {
64238fd1498Szrj cond = gimple_boolify (cond);
64338fd1498Szrj
64438fd1498Szrj if (integer_zerop (val))
64538fd1498Szrj val = fold_build2_loc (clause_loc,
64638fd1498Szrj EQ_EXPR, unsigned_type_node, cond,
64738fd1498Szrj build_int_cst (TREE_TYPE (cond), 0));
64838fd1498Szrj else
64938fd1498Szrj {
65038fd1498Szrj basic_block cond_bb, then_bb, else_bb;
65138fd1498Szrj edge e, e_then, e_else;
65238fd1498Szrj tree tmp_then, tmp_else, tmp_join, tmp_var;
65338fd1498Szrj
65438fd1498Szrj tmp_var = create_tmp_var (TREE_TYPE (val));
65538fd1498Szrj if (gimple_in_ssa_p (cfun))
65638fd1498Szrj {
65738fd1498Szrj tmp_then = make_ssa_name (tmp_var);
65838fd1498Szrj tmp_else = make_ssa_name (tmp_var);
65938fd1498Szrj tmp_join = make_ssa_name (tmp_var);
66038fd1498Szrj }
66138fd1498Szrj else
66238fd1498Szrj {
66338fd1498Szrj tmp_then = tmp_var;
66438fd1498Szrj tmp_else = tmp_var;
66538fd1498Szrj tmp_join = tmp_var;
66638fd1498Szrj }
66738fd1498Szrj
66838fd1498Szrj e = split_block_after_labels (bb);
66938fd1498Szrj cond_bb = e->src;
67038fd1498Szrj bb = e->dest;
67138fd1498Szrj remove_edge (e);
67238fd1498Szrj
67338fd1498Szrj then_bb = create_empty_bb (cond_bb);
67438fd1498Szrj else_bb = create_empty_bb (then_bb);
67538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
67638fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
67738fd1498Szrj
67838fd1498Szrj stmt = gimple_build_cond_empty (cond);
67938fd1498Szrj gsi = gsi_start_bb (cond_bb);
68038fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
68138fd1498Szrj
68238fd1498Szrj gsi = gsi_start_bb (then_bb);
68338fd1498Szrj expand_omp_build_assign (&gsi, tmp_then, val, true);
68438fd1498Szrj
68538fd1498Szrj gsi = gsi_start_bb (else_bb);
68638fd1498Szrj expand_omp_build_assign (&gsi, tmp_else,
68738fd1498Szrj build_int_cst (unsigned_type_node, 1),
68838fd1498Szrj true);
68938fd1498Szrj
69038fd1498Szrj make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
69138fd1498Szrj make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
69238fd1498Szrj add_bb_to_loop (then_bb, cond_bb->loop_father);
69338fd1498Szrj add_bb_to_loop (else_bb, cond_bb->loop_father);
69438fd1498Szrj e_then = make_edge (then_bb, bb, EDGE_FALLTHRU);
69538fd1498Szrj e_else = make_edge (else_bb, bb, EDGE_FALLTHRU);
69638fd1498Szrj
69738fd1498Szrj if (gimple_in_ssa_p (cfun))
69838fd1498Szrj {
69938fd1498Szrj gphi *phi = create_phi_node (tmp_join, bb);
70038fd1498Szrj add_phi_arg (phi, tmp_then, e_then, UNKNOWN_LOCATION);
70138fd1498Szrj add_phi_arg (phi, tmp_else, e_else, UNKNOWN_LOCATION);
70238fd1498Szrj }
70338fd1498Szrj
70438fd1498Szrj val = tmp_join;
70538fd1498Szrj }
70638fd1498Szrj
70738fd1498Szrj gsi = gsi_start_bb (bb);
70838fd1498Szrj val = force_gimple_operand_gsi (&gsi, val, true, NULL_TREE,
70938fd1498Szrj false, GSI_CONTINUE_LINKING);
71038fd1498Szrj }
71138fd1498Szrj
71238fd1498Szrj gsi = gsi_last_nondebug_bb (bb);
71338fd1498Szrj t = gimple_omp_parallel_data_arg (entry_stmt);
71438fd1498Szrj if (t == NULL)
71538fd1498Szrj t1 = null_pointer_node;
71638fd1498Szrj else
71738fd1498Szrj t1 = build_fold_addr_expr (t);
71838fd1498Szrj tree child_fndecl = gimple_omp_parallel_child_fn (entry_stmt);
71938fd1498Szrj t2 = build_fold_addr_expr (child_fndecl);
72038fd1498Szrj
72138fd1498Szrj vec_alloc (args, 4 + vec_safe_length (ws_args));
72238fd1498Szrj args->quick_push (t2);
72338fd1498Szrj args->quick_push (t1);
72438fd1498Szrj args->quick_push (val);
72538fd1498Szrj if (ws_args)
72638fd1498Szrj args->splice (*ws_args);
72738fd1498Szrj args->quick_push (flags);
72838fd1498Szrj
72938fd1498Szrj t = build_call_expr_loc_vec (UNKNOWN_LOCATION,
73038fd1498Szrj builtin_decl_explicit (start_ix), args);
73138fd1498Szrj
73238fd1498Szrj force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
73338fd1498Szrj false, GSI_CONTINUE_LINKING);
73438fd1498Szrj
73538fd1498Szrj if (hsa_gen_requested_p ()
73638fd1498Szrj && parallel_needs_hsa_kernel_p (region))
73738fd1498Szrj {
73838fd1498Szrj cgraph_node *child_cnode = cgraph_node::get (child_fndecl);
73938fd1498Szrj hsa_register_kernel (child_cnode);
74038fd1498Szrj }
74138fd1498Szrj }
74238fd1498Szrj
74338fd1498Szrj /* Build the function call to GOMP_task to actually
74438fd1498Szrj generate the task operation. BB is the block where to insert the code. */
74538fd1498Szrj
74638fd1498Szrj static void
expand_task_call(struct omp_region * region,basic_block bb,gomp_task * entry_stmt)74738fd1498Szrj expand_task_call (struct omp_region *region, basic_block bb,
74838fd1498Szrj gomp_task *entry_stmt)
74938fd1498Szrj {
75038fd1498Szrj tree t1, t2, t3;
75138fd1498Szrj gimple_stmt_iterator gsi;
75238fd1498Szrj location_t loc = gimple_location (entry_stmt);
75338fd1498Szrj
75438fd1498Szrj tree clauses = gimple_omp_task_clauses (entry_stmt);
75538fd1498Szrj
75638fd1498Szrj tree ifc = omp_find_clause (clauses, OMP_CLAUSE_IF);
75738fd1498Szrj tree untied = omp_find_clause (clauses, OMP_CLAUSE_UNTIED);
75838fd1498Szrj tree mergeable = omp_find_clause (clauses, OMP_CLAUSE_MERGEABLE);
75938fd1498Szrj tree depend = omp_find_clause (clauses, OMP_CLAUSE_DEPEND);
76038fd1498Szrj tree finalc = omp_find_clause (clauses, OMP_CLAUSE_FINAL);
76138fd1498Szrj tree priority = omp_find_clause (clauses, OMP_CLAUSE_PRIORITY);
76238fd1498Szrj
76338fd1498Szrj unsigned int iflags
76438fd1498Szrj = (untied ? GOMP_TASK_FLAG_UNTIED : 0)
76538fd1498Szrj | (mergeable ? GOMP_TASK_FLAG_MERGEABLE : 0)
76638fd1498Szrj | (depend ? GOMP_TASK_FLAG_DEPEND : 0);
76738fd1498Szrj
76838fd1498Szrj bool taskloop_p = gimple_omp_task_taskloop_p (entry_stmt);
76938fd1498Szrj tree startvar = NULL_TREE, endvar = NULL_TREE, step = NULL_TREE;
77038fd1498Szrj tree num_tasks = NULL_TREE;
77138fd1498Szrj bool ull = false;
77238fd1498Szrj if (taskloop_p)
77338fd1498Szrj {
77438fd1498Szrj gimple *g = last_stmt (region->outer->entry);
77538fd1498Szrj gcc_assert (gimple_code (g) == GIMPLE_OMP_FOR
77638fd1498Szrj && gimple_omp_for_kind (g) == GF_OMP_FOR_KIND_TASKLOOP);
77738fd1498Szrj struct omp_for_data fd;
77838fd1498Szrj omp_extract_for_data (as_a <gomp_for *> (g), &fd, NULL);
77938fd1498Szrj startvar = omp_find_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
78038fd1498Szrj endvar = omp_find_clause (OMP_CLAUSE_CHAIN (startvar),
78138fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
78238fd1498Szrj startvar = OMP_CLAUSE_DECL (startvar);
78338fd1498Szrj endvar = OMP_CLAUSE_DECL (endvar);
78438fd1498Szrj step = fold_convert_loc (loc, fd.iter_type, fd.loop.step);
78538fd1498Szrj if (fd.loop.cond_code == LT_EXPR)
78638fd1498Szrj iflags |= GOMP_TASK_FLAG_UP;
78738fd1498Szrj tree tclauses = gimple_omp_for_clauses (g);
78838fd1498Szrj num_tasks = omp_find_clause (tclauses, OMP_CLAUSE_NUM_TASKS);
78938fd1498Szrj if (num_tasks)
79038fd1498Szrj num_tasks = OMP_CLAUSE_NUM_TASKS_EXPR (num_tasks);
79138fd1498Szrj else
79238fd1498Szrj {
79338fd1498Szrj num_tasks = omp_find_clause (tclauses, OMP_CLAUSE_GRAINSIZE);
79438fd1498Szrj if (num_tasks)
79538fd1498Szrj {
79638fd1498Szrj iflags |= GOMP_TASK_FLAG_GRAINSIZE;
79738fd1498Szrj num_tasks = OMP_CLAUSE_GRAINSIZE_EXPR (num_tasks);
79838fd1498Szrj }
79938fd1498Szrj else
80038fd1498Szrj num_tasks = integer_zero_node;
80138fd1498Szrj }
80238fd1498Szrj num_tasks = fold_convert_loc (loc, long_integer_type_node, num_tasks);
80338fd1498Szrj if (ifc == NULL_TREE)
80438fd1498Szrj iflags |= GOMP_TASK_FLAG_IF;
80538fd1498Szrj if (omp_find_clause (tclauses, OMP_CLAUSE_NOGROUP))
80638fd1498Szrj iflags |= GOMP_TASK_FLAG_NOGROUP;
80738fd1498Szrj ull = fd.iter_type == long_long_unsigned_type_node;
80838fd1498Szrj }
80938fd1498Szrj else if (priority)
81038fd1498Szrj iflags |= GOMP_TASK_FLAG_PRIORITY;
81138fd1498Szrj
81238fd1498Szrj tree flags = build_int_cst (unsigned_type_node, iflags);
81338fd1498Szrj
81438fd1498Szrj tree cond = boolean_true_node;
81538fd1498Szrj if (ifc)
81638fd1498Szrj {
81738fd1498Szrj if (taskloop_p)
81838fd1498Szrj {
81938fd1498Szrj tree t = gimple_boolify (OMP_CLAUSE_IF_EXPR (ifc));
82038fd1498Szrj t = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, t,
82138fd1498Szrj build_int_cst (unsigned_type_node,
82238fd1498Szrj GOMP_TASK_FLAG_IF),
82338fd1498Szrj build_int_cst (unsigned_type_node, 0));
82438fd1498Szrj flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node,
82538fd1498Szrj flags, t);
82638fd1498Szrj }
82738fd1498Szrj else
82838fd1498Szrj cond = gimple_boolify (OMP_CLAUSE_IF_EXPR (ifc));
82938fd1498Szrj }
83038fd1498Szrj
83138fd1498Szrj if (finalc)
83238fd1498Szrj {
83338fd1498Szrj tree t = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (finalc));
83438fd1498Szrj t = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, t,
83538fd1498Szrj build_int_cst (unsigned_type_node,
83638fd1498Szrj GOMP_TASK_FLAG_FINAL),
83738fd1498Szrj build_int_cst (unsigned_type_node, 0));
83838fd1498Szrj flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, t);
83938fd1498Szrj }
84038fd1498Szrj if (depend)
84138fd1498Szrj depend = OMP_CLAUSE_DECL (depend);
84238fd1498Szrj else
84338fd1498Szrj depend = build_int_cst (ptr_type_node, 0);
84438fd1498Szrj if (priority)
84538fd1498Szrj priority = fold_convert (integer_type_node,
84638fd1498Szrj OMP_CLAUSE_PRIORITY_EXPR (priority));
84738fd1498Szrj else
84838fd1498Szrj priority = integer_zero_node;
84938fd1498Szrj
85038fd1498Szrj gsi = gsi_last_nondebug_bb (bb);
85138fd1498Szrj tree t = gimple_omp_task_data_arg (entry_stmt);
85238fd1498Szrj if (t == NULL)
85338fd1498Szrj t2 = null_pointer_node;
85438fd1498Szrj else
85538fd1498Szrj t2 = build_fold_addr_expr_loc (loc, t);
85638fd1498Szrj t1 = build_fold_addr_expr_loc (loc, gimple_omp_task_child_fn (entry_stmt));
85738fd1498Szrj t = gimple_omp_task_copy_fn (entry_stmt);
85838fd1498Szrj if (t == NULL)
85938fd1498Szrj t3 = null_pointer_node;
86038fd1498Szrj else
86138fd1498Szrj t3 = build_fold_addr_expr_loc (loc, t);
86238fd1498Szrj
86338fd1498Szrj if (taskloop_p)
86438fd1498Szrj t = build_call_expr (ull
86538fd1498Szrj ? builtin_decl_explicit (BUILT_IN_GOMP_TASKLOOP_ULL)
86638fd1498Szrj : builtin_decl_explicit (BUILT_IN_GOMP_TASKLOOP),
86738fd1498Szrj 11, t1, t2, t3,
86838fd1498Szrj gimple_omp_task_arg_size (entry_stmt),
86938fd1498Szrj gimple_omp_task_arg_align (entry_stmt), flags,
87038fd1498Szrj num_tasks, priority, startvar, endvar, step);
87138fd1498Szrj else
87238fd1498Szrj t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK),
87338fd1498Szrj 9, t1, t2, t3,
87438fd1498Szrj gimple_omp_task_arg_size (entry_stmt),
87538fd1498Szrj gimple_omp_task_arg_align (entry_stmt), cond, flags,
87638fd1498Szrj depend, priority);
87738fd1498Szrj
87838fd1498Szrj force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
87938fd1498Szrj false, GSI_CONTINUE_LINKING);
88038fd1498Szrj }
88138fd1498Szrj
88238fd1498Szrj /* Chain all the DECLs in LIST by their TREE_CHAIN fields. */
88338fd1498Szrj
88438fd1498Szrj static tree
vec2chain(vec<tree,va_gc> * v)88538fd1498Szrj vec2chain (vec<tree, va_gc> *v)
88638fd1498Szrj {
88738fd1498Szrj tree chain = NULL_TREE, t;
88838fd1498Szrj unsigned ix;
88938fd1498Szrj
89038fd1498Szrj FOR_EACH_VEC_SAFE_ELT_REVERSE (v, ix, t)
89138fd1498Szrj {
89238fd1498Szrj DECL_CHAIN (t) = chain;
89338fd1498Szrj chain = t;
89438fd1498Szrj }
89538fd1498Szrj
89638fd1498Szrj return chain;
89738fd1498Szrj }
89838fd1498Szrj
89938fd1498Szrj /* Remove barriers in REGION->EXIT's block. Note that this is only
90038fd1498Szrj valid for GIMPLE_OMP_PARALLEL regions. Since the end of a parallel region
90138fd1498Szrj is an implicit barrier, any workshare inside the GIMPLE_OMP_PARALLEL that
90238fd1498Szrj left a barrier at the end of the GIMPLE_OMP_PARALLEL region can now be
90338fd1498Szrj removed. */
90438fd1498Szrj
90538fd1498Szrj static void
remove_exit_barrier(struct omp_region * region)90638fd1498Szrj remove_exit_barrier (struct omp_region *region)
90738fd1498Szrj {
90838fd1498Szrj gimple_stmt_iterator gsi;
90938fd1498Szrj basic_block exit_bb;
91038fd1498Szrj edge_iterator ei;
91138fd1498Szrj edge e;
91238fd1498Szrj gimple *stmt;
91338fd1498Szrj int any_addressable_vars = -1;
91438fd1498Szrj
91538fd1498Szrj exit_bb = region->exit;
91638fd1498Szrj
91738fd1498Szrj /* If the parallel region doesn't return, we don't have REGION->EXIT
91838fd1498Szrj block at all. */
91938fd1498Szrj if (! exit_bb)
92038fd1498Szrj return;
92138fd1498Szrj
92238fd1498Szrj /* The last insn in the block will be the parallel's GIMPLE_OMP_RETURN. The
92338fd1498Szrj workshare's GIMPLE_OMP_RETURN will be in a preceding block. The kinds of
92438fd1498Szrj statements that can appear in between are extremely limited -- no
92538fd1498Szrj memory operations at all. Here, we allow nothing at all, so the
92638fd1498Szrj only thing we allow to precede this GIMPLE_OMP_RETURN is a label. */
92738fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
92838fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
92938fd1498Szrj gsi_prev_nondebug (&gsi);
93038fd1498Szrj if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
93138fd1498Szrj return;
93238fd1498Szrj
93338fd1498Szrj FOR_EACH_EDGE (e, ei, exit_bb->preds)
93438fd1498Szrj {
93538fd1498Szrj gsi = gsi_last_nondebug_bb (e->src);
93638fd1498Szrj if (gsi_end_p (gsi))
93738fd1498Szrj continue;
93838fd1498Szrj stmt = gsi_stmt (gsi);
93938fd1498Szrj if (gimple_code (stmt) == GIMPLE_OMP_RETURN
94038fd1498Szrj && !gimple_omp_return_nowait_p (stmt))
94138fd1498Szrj {
94238fd1498Szrj /* OpenMP 3.0 tasks unfortunately prevent this optimization
94338fd1498Szrj in many cases. If there could be tasks queued, the barrier
94438fd1498Szrj might be needed to let the tasks run before some local
94538fd1498Szrj variable of the parallel that the task uses as shared
94638fd1498Szrj runs out of scope. The task can be spawned either
94738fd1498Szrj from within current function (this would be easy to check)
94838fd1498Szrj or from some function it calls and gets passed an address
94938fd1498Szrj of such a variable. */
95038fd1498Szrj if (any_addressable_vars < 0)
95138fd1498Szrj {
95238fd1498Szrj gomp_parallel *parallel_stmt
95338fd1498Szrj = as_a <gomp_parallel *> (last_stmt (region->entry));
95438fd1498Szrj tree child_fun = gimple_omp_parallel_child_fn (parallel_stmt);
95538fd1498Szrj tree local_decls, block, decl;
95638fd1498Szrj unsigned ix;
95738fd1498Szrj
95838fd1498Szrj any_addressable_vars = 0;
95938fd1498Szrj FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (child_fun), ix, decl)
96038fd1498Szrj if (TREE_ADDRESSABLE (decl))
96138fd1498Szrj {
96238fd1498Szrj any_addressable_vars = 1;
96338fd1498Szrj break;
96438fd1498Szrj }
96538fd1498Szrj for (block = gimple_block (stmt);
96638fd1498Szrj !any_addressable_vars
96738fd1498Szrj && block
96838fd1498Szrj && TREE_CODE (block) == BLOCK;
96938fd1498Szrj block = BLOCK_SUPERCONTEXT (block))
97038fd1498Szrj {
97138fd1498Szrj for (local_decls = BLOCK_VARS (block);
97238fd1498Szrj local_decls;
97338fd1498Szrj local_decls = DECL_CHAIN (local_decls))
97438fd1498Szrj if (TREE_ADDRESSABLE (local_decls))
97538fd1498Szrj {
97638fd1498Szrj any_addressable_vars = 1;
97738fd1498Szrj break;
97838fd1498Szrj }
97938fd1498Szrj if (block == gimple_block (parallel_stmt))
98038fd1498Szrj break;
98138fd1498Szrj }
98238fd1498Szrj }
98338fd1498Szrj if (!any_addressable_vars)
98438fd1498Szrj gimple_omp_return_set_nowait (stmt);
98538fd1498Szrj }
98638fd1498Szrj }
98738fd1498Szrj }
98838fd1498Szrj
98938fd1498Szrj static void
remove_exit_barriers(struct omp_region * region)99038fd1498Szrj remove_exit_barriers (struct omp_region *region)
99138fd1498Szrj {
99238fd1498Szrj if (region->type == GIMPLE_OMP_PARALLEL)
99338fd1498Szrj remove_exit_barrier (region);
99438fd1498Szrj
99538fd1498Szrj if (region->inner)
99638fd1498Szrj {
99738fd1498Szrj region = region->inner;
99838fd1498Szrj remove_exit_barriers (region);
99938fd1498Szrj while (region->next)
100038fd1498Szrj {
100138fd1498Szrj region = region->next;
100238fd1498Szrj remove_exit_barriers (region);
100338fd1498Szrj }
100438fd1498Szrj }
100538fd1498Szrj }
100638fd1498Szrj
100738fd1498Szrj /* Optimize omp_get_thread_num () and omp_get_num_threads ()
100838fd1498Szrj calls. These can't be declared as const functions, but
100938fd1498Szrj within one parallel body they are constant, so they can be
101038fd1498Szrj transformed there into __builtin_omp_get_{thread_num,num_threads} ()
101138fd1498Szrj which are declared const. Similarly for task body, except
101238fd1498Szrj that in untied task omp_get_thread_num () can change at any task
101338fd1498Szrj scheduling point. */
101438fd1498Szrj
101538fd1498Szrj static void
optimize_omp_library_calls(gimple * entry_stmt)101638fd1498Szrj optimize_omp_library_calls (gimple *entry_stmt)
101738fd1498Szrj {
101838fd1498Szrj basic_block bb;
101938fd1498Szrj gimple_stmt_iterator gsi;
102038fd1498Szrj tree thr_num_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
102138fd1498Szrj tree thr_num_id = DECL_ASSEMBLER_NAME (thr_num_tree);
102238fd1498Szrj tree num_thr_tree = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
102338fd1498Szrj tree num_thr_id = DECL_ASSEMBLER_NAME (num_thr_tree);
102438fd1498Szrj bool untied_task = (gimple_code (entry_stmt) == GIMPLE_OMP_TASK
102538fd1498Szrj && omp_find_clause (gimple_omp_task_clauses (entry_stmt),
102638fd1498Szrj OMP_CLAUSE_UNTIED) != NULL);
102738fd1498Szrj
102838fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
102938fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
103038fd1498Szrj {
103138fd1498Szrj gimple *call = gsi_stmt (gsi);
103238fd1498Szrj tree decl;
103338fd1498Szrj
103438fd1498Szrj if (is_gimple_call (call)
103538fd1498Szrj && (decl = gimple_call_fndecl (call))
103638fd1498Szrj && DECL_EXTERNAL (decl)
103738fd1498Szrj && TREE_PUBLIC (decl)
103838fd1498Szrj && DECL_INITIAL (decl) == NULL)
103938fd1498Szrj {
104038fd1498Szrj tree built_in;
104138fd1498Szrj
104238fd1498Szrj if (DECL_NAME (decl) == thr_num_id)
104338fd1498Szrj {
104438fd1498Szrj /* In #pragma omp task untied omp_get_thread_num () can change
104538fd1498Szrj during the execution of the task region. */
104638fd1498Szrj if (untied_task)
104738fd1498Szrj continue;
104838fd1498Szrj built_in = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
104938fd1498Szrj }
105038fd1498Szrj else if (DECL_NAME (decl) == num_thr_id)
105138fd1498Szrj built_in = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
105238fd1498Szrj else
105338fd1498Szrj continue;
105438fd1498Szrj
105538fd1498Szrj if (DECL_ASSEMBLER_NAME (decl) != DECL_ASSEMBLER_NAME (built_in)
105638fd1498Szrj || gimple_call_num_args (call) != 0)
105738fd1498Szrj continue;
105838fd1498Szrj
105938fd1498Szrj if (flag_exceptions && !TREE_NOTHROW (decl))
106038fd1498Szrj continue;
106138fd1498Szrj
106238fd1498Szrj if (TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE
106338fd1498Szrj || !types_compatible_p (TREE_TYPE (TREE_TYPE (decl)),
106438fd1498Szrj TREE_TYPE (TREE_TYPE (built_in))))
106538fd1498Szrj continue;
106638fd1498Szrj
106738fd1498Szrj gimple_call_set_fndecl (call, built_in);
106838fd1498Szrj }
106938fd1498Szrj }
107038fd1498Szrj }
107138fd1498Szrj
107238fd1498Szrj /* Callback for expand_omp_build_assign. Return non-NULL if *tp needs to be
107338fd1498Szrj regimplified. */
107438fd1498Szrj
107538fd1498Szrj static tree
expand_omp_regimplify_p(tree * tp,int * walk_subtrees,void *)107638fd1498Szrj expand_omp_regimplify_p (tree *tp, int *walk_subtrees, void *)
107738fd1498Szrj {
107838fd1498Szrj tree t = *tp;
107938fd1498Szrj
108038fd1498Szrj /* Any variable with DECL_VALUE_EXPR needs to be regimplified. */
108138fd1498Szrj if (VAR_P (t) && DECL_HAS_VALUE_EXPR_P (t))
108238fd1498Szrj return t;
108338fd1498Szrj
108438fd1498Szrj if (TREE_CODE (t) == ADDR_EXPR)
108538fd1498Szrj recompute_tree_invariant_for_addr_expr (t);
108638fd1498Szrj
108738fd1498Szrj *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
108838fd1498Szrj return NULL_TREE;
108938fd1498Szrj }
109038fd1498Szrj
109138fd1498Szrj /* Prepend or append TO = FROM assignment before or after *GSI_P. */
109238fd1498Szrj
109338fd1498Szrj static void
expand_omp_build_assign(gimple_stmt_iterator * gsi_p,tree to,tree from,bool after)109438fd1498Szrj expand_omp_build_assign (gimple_stmt_iterator *gsi_p, tree to, tree from,
109538fd1498Szrj bool after)
109638fd1498Szrj {
109738fd1498Szrj bool simple_p = DECL_P (to) && TREE_ADDRESSABLE (to);
109838fd1498Szrj from = force_gimple_operand_gsi (gsi_p, from, simple_p, NULL_TREE,
109938fd1498Szrj !after, after ? GSI_CONTINUE_LINKING
110038fd1498Szrj : GSI_SAME_STMT);
110138fd1498Szrj gimple *stmt = gimple_build_assign (to, from);
110238fd1498Szrj if (after)
110338fd1498Szrj gsi_insert_after (gsi_p, stmt, GSI_CONTINUE_LINKING);
110438fd1498Szrj else
110538fd1498Szrj gsi_insert_before (gsi_p, stmt, GSI_SAME_STMT);
110638fd1498Szrj if (walk_tree (&from, expand_omp_regimplify_p, NULL, NULL)
110738fd1498Szrj || walk_tree (&to, expand_omp_regimplify_p, NULL, NULL))
110838fd1498Szrj {
110938fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
111038fd1498Szrj gimple_regimplify_operands (stmt, &gsi);
111138fd1498Szrj }
111238fd1498Szrj }
111338fd1498Szrj
111438fd1498Szrj /* Expand the OpenMP parallel or task directive starting at REGION. */
111538fd1498Szrj
111638fd1498Szrj static void
expand_omp_taskreg(struct omp_region * region)111738fd1498Szrj expand_omp_taskreg (struct omp_region *region)
111838fd1498Szrj {
111938fd1498Szrj basic_block entry_bb, exit_bb, new_bb;
112038fd1498Szrj struct function *child_cfun;
112138fd1498Szrj tree child_fn, block, t;
112238fd1498Szrj gimple_stmt_iterator gsi;
112338fd1498Szrj gimple *entry_stmt, *stmt;
112438fd1498Szrj edge e;
112538fd1498Szrj vec<tree, va_gc> *ws_args;
112638fd1498Szrj
112738fd1498Szrj entry_stmt = last_stmt (region->entry);
112838fd1498Szrj child_fn = gimple_omp_taskreg_child_fn (entry_stmt);
112938fd1498Szrj child_cfun = DECL_STRUCT_FUNCTION (child_fn);
113038fd1498Szrj
113138fd1498Szrj entry_bb = region->entry;
113238fd1498Szrj if (gimple_code (entry_stmt) == GIMPLE_OMP_TASK)
113338fd1498Szrj exit_bb = region->cont;
113438fd1498Szrj else
113538fd1498Szrj exit_bb = region->exit;
113638fd1498Szrj
113738fd1498Szrj if (is_combined_parallel (region))
113838fd1498Szrj ws_args = region->ws_args;
113938fd1498Szrj else
114038fd1498Szrj ws_args = NULL;
114138fd1498Szrj
114238fd1498Szrj if (child_cfun->cfg)
114338fd1498Szrj {
114438fd1498Szrj /* Due to inlining, it may happen that we have already outlined
114538fd1498Szrj the region, in which case all we need to do is make the
114638fd1498Szrj sub-graph unreachable and emit the parallel call. */
114738fd1498Szrj edge entry_succ_e, exit_succ_e;
114838fd1498Szrj
114938fd1498Szrj entry_succ_e = single_succ_edge (entry_bb);
115038fd1498Szrj
115138fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
115238fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_PARALLEL
115338fd1498Szrj || gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
115438fd1498Szrj gsi_remove (&gsi, true);
115538fd1498Szrj
115638fd1498Szrj new_bb = entry_bb;
115738fd1498Szrj if (exit_bb)
115838fd1498Szrj {
115938fd1498Szrj exit_succ_e = single_succ_edge (exit_bb);
116038fd1498Szrj make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
116138fd1498Szrj }
116238fd1498Szrj remove_edge_and_dominated_blocks (entry_succ_e);
116338fd1498Szrj }
116438fd1498Szrj else
116538fd1498Szrj {
116638fd1498Szrj unsigned srcidx, dstidx, num;
116738fd1498Szrj
116838fd1498Szrj /* If the parallel region needs data sent from the parent
116938fd1498Szrj function, then the very first statement (except possible
117038fd1498Szrj tree profile counter updates) of the parallel body
117138fd1498Szrj is a copy assignment .OMP_DATA_I = &.OMP_DATA_O. Since
117238fd1498Szrj &.OMP_DATA_O is passed as an argument to the child function,
117338fd1498Szrj we need to replace it with the argument as seen by the child
117438fd1498Szrj function.
117538fd1498Szrj
117638fd1498Szrj In most cases, this will end up being the identity assignment
117738fd1498Szrj .OMP_DATA_I = .OMP_DATA_I. However, if the parallel body had
117838fd1498Szrj a function call that has been inlined, the original PARM_DECL
117938fd1498Szrj .OMP_DATA_I may have been converted into a different local
118038fd1498Szrj variable. In which case, we need to keep the assignment. */
118138fd1498Szrj if (gimple_omp_taskreg_data_arg (entry_stmt))
118238fd1498Szrj {
118338fd1498Szrj basic_block entry_succ_bb
118438fd1498Szrj = single_succ_p (entry_bb) ? single_succ (entry_bb)
118538fd1498Szrj : FALLTHRU_EDGE (entry_bb)->dest;
118638fd1498Szrj tree arg;
118738fd1498Szrj gimple *parcopy_stmt = NULL;
118838fd1498Szrj
118938fd1498Szrj for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
119038fd1498Szrj {
119138fd1498Szrj gimple *stmt;
119238fd1498Szrj
119338fd1498Szrj gcc_assert (!gsi_end_p (gsi));
119438fd1498Szrj stmt = gsi_stmt (gsi);
119538fd1498Szrj if (gimple_code (stmt) != GIMPLE_ASSIGN)
119638fd1498Szrj continue;
119738fd1498Szrj
119838fd1498Szrj if (gimple_num_ops (stmt) == 2)
119938fd1498Szrj {
120038fd1498Szrj tree arg = gimple_assign_rhs1 (stmt);
120138fd1498Szrj
120238fd1498Szrj /* We're ignore the subcode because we're
120338fd1498Szrj effectively doing a STRIP_NOPS. */
120438fd1498Szrj
120538fd1498Szrj if (TREE_CODE (arg) == ADDR_EXPR
120638fd1498Szrj && TREE_OPERAND (arg, 0)
120738fd1498Szrj == gimple_omp_taskreg_data_arg (entry_stmt))
120838fd1498Szrj {
120938fd1498Szrj parcopy_stmt = stmt;
121038fd1498Szrj break;
121138fd1498Szrj }
121238fd1498Szrj }
121338fd1498Szrj }
121438fd1498Szrj
121538fd1498Szrj gcc_assert (parcopy_stmt != NULL);
121638fd1498Szrj arg = DECL_ARGUMENTS (child_fn);
121738fd1498Szrj
121838fd1498Szrj if (!gimple_in_ssa_p (cfun))
121938fd1498Szrj {
122038fd1498Szrj if (gimple_assign_lhs (parcopy_stmt) == arg)
122138fd1498Szrj gsi_remove (&gsi, true);
122238fd1498Szrj else
122338fd1498Szrj {
122438fd1498Szrj /* ?? Is setting the subcode really necessary ?? */
122538fd1498Szrj gimple_omp_set_subcode (parcopy_stmt, TREE_CODE (arg));
122638fd1498Szrj gimple_assign_set_rhs1 (parcopy_stmt, arg);
122738fd1498Szrj }
122838fd1498Szrj }
122938fd1498Szrj else
123038fd1498Szrj {
123138fd1498Szrj tree lhs = gimple_assign_lhs (parcopy_stmt);
123238fd1498Szrj gcc_assert (SSA_NAME_VAR (lhs) == arg);
123338fd1498Szrj /* We'd like to set the rhs to the default def in the child_fn,
123438fd1498Szrj but it's too early to create ssa names in the child_fn.
123538fd1498Szrj Instead, we set the rhs to the parm. In
123638fd1498Szrj move_sese_region_to_fn, we introduce a default def for the
123738fd1498Szrj parm, map the parm to it's default def, and once we encounter
123838fd1498Szrj this stmt, replace the parm with the default def. */
123938fd1498Szrj gimple_assign_set_rhs1 (parcopy_stmt, arg);
124038fd1498Szrj update_stmt (parcopy_stmt);
124138fd1498Szrj }
124238fd1498Szrj }
124338fd1498Szrj
124438fd1498Szrj /* Declare local variables needed in CHILD_CFUN. */
124538fd1498Szrj block = DECL_INITIAL (child_fn);
124638fd1498Szrj BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
124738fd1498Szrj /* The gimplifier could record temporaries in parallel/task block
124838fd1498Szrj rather than in containing function's local_decls chain,
124938fd1498Szrj which would mean cgraph missed finalizing them. Do it now. */
125038fd1498Szrj for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
125138fd1498Szrj if (VAR_P (t) && TREE_STATIC (t) && !DECL_EXTERNAL (t))
125238fd1498Szrj varpool_node::finalize_decl (t);
125338fd1498Szrj DECL_SAVED_TREE (child_fn) = NULL;
125438fd1498Szrj /* We'll create a CFG for child_fn, so no gimple body is needed. */
125538fd1498Szrj gimple_set_body (child_fn, NULL);
125638fd1498Szrj TREE_USED (block) = 1;
125738fd1498Szrj
125838fd1498Szrj /* Reset DECL_CONTEXT on function arguments. */
125938fd1498Szrj for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
126038fd1498Szrj DECL_CONTEXT (t) = child_fn;
126138fd1498Szrj
126238fd1498Szrj /* Split ENTRY_BB at GIMPLE_OMP_PARALLEL or GIMPLE_OMP_TASK,
126338fd1498Szrj so that it can be moved to the child function. */
126438fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
126538fd1498Szrj stmt = gsi_stmt (gsi);
126638fd1498Szrj gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
126738fd1498Szrj || gimple_code (stmt) == GIMPLE_OMP_TASK));
126838fd1498Szrj e = split_block (entry_bb, stmt);
126938fd1498Szrj gsi_remove (&gsi, true);
127038fd1498Szrj entry_bb = e->dest;
127138fd1498Szrj edge e2 = NULL;
127238fd1498Szrj if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
127338fd1498Szrj single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
127438fd1498Szrj else
127538fd1498Szrj {
127638fd1498Szrj e2 = make_edge (e->src, BRANCH_EDGE (entry_bb)->dest, EDGE_ABNORMAL);
127738fd1498Szrj gcc_assert (e2->dest == region->exit);
127838fd1498Szrj remove_edge (BRANCH_EDGE (entry_bb));
127938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, e2->dest, e->src);
128038fd1498Szrj gsi = gsi_last_nondebug_bb (region->exit);
128138fd1498Szrj gcc_assert (!gsi_end_p (gsi)
128238fd1498Szrj && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
128338fd1498Szrj gsi_remove (&gsi, true);
128438fd1498Szrj }
128538fd1498Szrj
128638fd1498Szrj /* Convert GIMPLE_OMP_{RETURN,CONTINUE} into a RETURN_EXPR. */
128738fd1498Szrj if (exit_bb)
128838fd1498Szrj {
128938fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
129038fd1498Szrj gcc_assert (!gsi_end_p (gsi)
129138fd1498Szrj && (gimple_code (gsi_stmt (gsi))
129238fd1498Szrj == (e2 ? GIMPLE_OMP_CONTINUE : GIMPLE_OMP_RETURN)));
129338fd1498Szrj stmt = gimple_build_return (NULL);
129438fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
129538fd1498Szrj gsi_remove (&gsi, true);
129638fd1498Szrj }
129738fd1498Szrj
129838fd1498Szrj /* Move the parallel region into CHILD_CFUN. */
129938fd1498Szrj
130038fd1498Szrj if (gimple_in_ssa_p (cfun))
130138fd1498Szrj {
130238fd1498Szrj init_tree_ssa (child_cfun);
130338fd1498Szrj init_ssa_operands (child_cfun);
130438fd1498Szrj child_cfun->gimple_df->in_ssa_p = true;
130538fd1498Szrj block = NULL_TREE;
130638fd1498Szrj }
130738fd1498Szrj else
130838fd1498Szrj block = gimple_block (entry_stmt);
130938fd1498Szrj
131038fd1498Szrj new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
131138fd1498Szrj if (exit_bb)
131238fd1498Szrj single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
131338fd1498Szrj if (e2)
131438fd1498Szrj {
131538fd1498Szrj basic_block dest_bb = e2->dest;
131638fd1498Szrj if (!exit_bb)
131738fd1498Szrj make_edge (new_bb, dest_bb, EDGE_FALLTHRU);
131838fd1498Szrj remove_edge (e2);
131938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, dest_bb, new_bb);
132038fd1498Szrj }
132138fd1498Szrj /* When the OMP expansion process cannot guarantee an up-to-date
132238fd1498Szrj loop tree arrange for the child function to fixup loops. */
132338fd1498Szrj if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
132438fd1498Szrj child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
132538fd1498Szrj
132638fd1498Szrj /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */
132738fd1498Szrj num = vec_safe_length (child_cfun->local_decls);
132838fd1498Szrj for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
132938fd1498Szrj {
133038fd1498Szrj t = (*child_cfun->local_decls)[srcidx];
133138fd1498Szrj if (DECL_CONTEXT (t) == cfun->decl)
133238fd1498Szrj continue;
133338fd1498Szrj if (srcidx != dstidx)
133438fd1498Szrj (*child_cfun->local_decls)[dstidx] = t;
133538fd1498Szrj dstidx++;
133638fd1498Szrj }
133738fd1498Szrj if (dstidx != num)
133838fd1498Szrj vec_safe_truncate (child_cfun->local_decls, dstidx);
133938fd1498Szrj
134038fd1498Szrj /* Inform the callgraph about the new function. */
134138fd1498Szrj child_cfun->curr_properties = cfun->curr_properties;
134238fd1498Szrj child_cfun->has_simduid_loops |= cfun->has_simduid_loops;
134338fd1498Szrj child_cfun->has_force_vectorize_loops |= cfun->has_force_vectorize_loops;
134438fd1498Szrj cgraph_node *node = cgraph_node::get_create (child_fn);
134538fd1498Szrj node->parallelized_function = 1;
134638fd1498Szrj cgraph_node::add_new_function (child_fn, true);
134738fd1498Szrj
134838fd1498Szrj bool need_asm = DECL_ASSEMBLER_NAME_SET_P (current_function_decl)
134938fd1498Szrj && !DECL_ASSEMBLER_NAME_SET_P (child_fn);
135038fd1498Szrj
135138fd1498Szrj /* Fix the callgraph edges for child_cfun. Those for cfun will be
135238fd1498Szrj fixed in a following pass. */
135338fd1498Szrj push_cfun (child_cfun);
135438fd1498Szrj if (need_asm)
135538fd1498Szrj assign_assembler_name_if_needed (child_fn);
135638fd1498Szrj
135738fd1498Szrj if (optimize)
135838fd1498Szrj optimize_omp_library_calls (entry_stmt);
135938fd1498Szrj update_max_bb_count ();
136038fd1498Szrj cgraph_edge::rebuild_edges ();
136138fd1498Szrj
136238fd1498Szrj /* Some EH regions might become dead, see PR34608. If
136338fd1498Szrj pass_cleanup_cfg isn't the first pass to happen with the
136438fd1498Szrj new child, these dead EH edges might cause problems.
136538fd1498Szrj Clean them up now. */
136638fd1498Szrj if (flag_exceptions)
136738fd1498Szrj {
136838fd1498Szrj basic_block bb;
136938fd1498Szrj bool changed = false;
137038fd1498Szrj
137138fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
137238fd1498Szrj changed |= gimple_purge_dead_eh_edges (bb);
137338fd1498Szrj if (changed)
137438fd1498Szrj cleanup_tree_cfg ();
137538fd1498Szrj }
137638fd1498Szrj if (gimple_in_ssa_p (cfun))
137738fd1498Szrj update_ssa (TODO_update_ssa);
137838fd1498Szrj if (flag_checking && !loops_state_satisfies_p (LOOPS_NEED_FIXUP))
137938fd1498Szrj verify_loop_structure ();
138038fd1498Szrj pop_cfun ();
138138fd1498Szrj
138238fd1498Szrj if (dump_file && !gimple_in_ssa_p (cfun))
138338fd1498Szrj {
138438fd1498Szrj omp_any_child_fn_dumped = true;
138538fd1498Szrj dump_function_header (dump_file, child_fn, dump_flags);
138638fd1498Szrj dump_function_to_file (child_fn, dump_file, dump_flags);
138738fd1498Szrj }
138838fd1498Szrj }
138938fd1498Szrj
1390*58e805e6Szrj adjust_context_and_scope (region, gimple_block (entry_stmt), child_fn);
1391*58e805e6Szrj
139238fd1498Szrj if (gimple_code (entry_stmt) == GIMPLE_OMP_PARALLEL)
139338fd1498Szrj expand_parallel_call (region, new_bb,
139438fd1498Szrj as_a <gomp_parallel *> (entry_stmt), ws_args);
139538fd1498Szrj else
139638fd1498Szrj expand_task_call (region, new_bb, as_a <gomp_task *> (entry_stmt));
139738fd1498Szrj if (gimple_in_ssa_p (cfun))
139838fd1498Szrj update_ssa (TODO_update_ssa_only_virtuals);
139938fd1498Szrj }
140038fd1498Szrj
140138fd1498Szrj /* Information about members of an OpenACC collapsed loop nest. */
140238fd1498Szrj
140338fd1498Szrj struct oacc_collapse
140438fd1498Szrj {
140538fd1498Szrj tree base; /* Base value. */
140638fd1498Szrj tree iters; /* Number of steps. */
140738fd1498Szrj tree step; /* Step size. */
140838fd1498Szrj tree tile; /* Tile increment (if tiled). */
140938fd1498Szrj tree outer; /* Tile iterator var. */
141038fd1498Szrj };
141138fd1498Szrj
141238fd1498Szrj /* Helper for expand_oacc_for. Determine collapsed loop information.
141338fd1498Szrj Fill in COUNTS array. Emit any initialization code before GSI.
141438fd1498Szrj Return the calculated outer loop bound of BOUND_TYPE. */
141538fd1498Szrj
141638fd1498Szrj static tree
expand_oacc_collapse_init(const struct omp_for_data * fd,gimple_stmt_iterator * gsi,oacc_collapse * counts,tree bound_type,location_t loc)141738fd1498Szrj expand_oacc_collapse_init (const struct omp_for_data *fd,
141838fd1498Szrj gimple_stmt_iterator *gsi,
141938fd1498Szrj oacc_collapse *counts, tree bound_type,
142038fd1498Szrj location_t loc)
142138fd1498Szrj {
142238fd1498Szrj tree tiling = fd->tiling;
142338fd1498Szrj tree total = build_int_cst (bound_type, 1);
142438fd1498Szrj int ix;
142538fd1498Szrj
142638fd1498Szrj gcc_assert (integer_onep (fd->loop.step));
142738fd1498Szrj gcc_assert (integer_zerop (fd->loop.n1));
142838fd1498Szrj
142938fd1498Szrj /* When tiling, the first operand of the tile clause applies to the
143038fd1498Szrj innermost loop, and we work outwards from there. Seems
143138fd1498Szrj backwards, but whatever. */
143238fd1498Szrj for (ix = fd->collapse; ix--;)
143338fd1498Szrj {
143438fd1498Szrj const omp_for_data_loop *loop = &fd->loops[ix];
143538fd1498Szrj
143638fd1498Szrj tree iter_type = TREE_TYPE (loop->v);
143738fd1498Szrj tree diff_type = iter_type;
143838fd1498Szrj tree plus_type = iter_type;
143938fd1498Szrj
144038fd1498Szrj gcc_assert (loop->cond_code == fd->loop.cond_code);
144138fd1498Szrj
144238fd1498Szrj if (POINTER_TYPE_P (iter_type))
144338fd1498Szrj plus_type = sizetype;
144438fd1498Szrj if (POINTER_TYPE_P (diff_type) || TYPE_UNSIGNED (diff_type))
144538fd1498Szrj diff_type = signed_type_for (diff_type);
144638fd1498Szrj if (TYPE_PRECISION (diff_type) < TYPE_PRECISION (integer_type_node))
144738fd1498Szrj diff_type = integer_type_node;
144838fd1498Szrj
144938fd1498Szrj if (tiling)
145038fd1498Szrj {
145138fd1498Szrj tree num = build_int_cst (integer_type_node, fd->collapse);
145238fd1498Szrj tree loop_no = build_int_cst (integer_type_node, ix);
145338fd1498Szrj tree tile = TREE_VALUE (tiling);
145438fd1498Szrj gcall *call
145538fd1498Szrj = gimple_build_call_internal (IFN_GOACC_TILE, 5, num, loop_no, tile,
145638fd1498Szrj /* gwv-outer=*/integer_zero_node,
145738fd1498Szrj /* gwv-inner=*/integer_zero_node);
145838fd1498Szrj
145938fd1498Szrj counts[ix].outer = create_tmp_var (iter_type, ".outer");
146038fd1498Szrj counts[ix].tile = create_tmp_var (diff_type, ".tile");
146138fd1498Szrj gimple_call_set_lhs (call, counts[ix].tile);
146238fd1498Szrj gimple_set_location (call, loc);
146338fd1498Szrj gsi_insert_before (gsi, call, GSI_SAME_STMT);
146438fd1498Szrj
146538fd1498Szrj tiling = TREE_CHAIN (tiling);
146638fd1498Szrj }
146738fd1498Szrj else
146838fd1498Szrj {
146938fd1498Szrj counts[ix].tile = NULL;
147038fd1498Szrj counts[ix].outer = loop->v;
147138fd1498Szrj }
147238fd1498Szrj
147338fd1498Szrj tree b = loop->n1;
147438fd1498Szrj tree e = loop->n2;
147538fd1498Szrj tree s = loop->step;
147638fd1498Szrj bool up = loop->cond_code == LT_EXPR;
147738fd1498Szrj tree dir = build_int_cst (diff_type, up ? +1 : -1);
147838fd1498Szrj bool negating;
147938fd1498Szrj tree expr;
148038fd1498Szrj
148138fd1498Szrj b = force_gimple_operand_gsi (gsi, b, true, NULL_TREE,
148238fd1498Szrj true, GSI_SAME_STMT);
148338fd1498Szrj e = force_gimple_operand_gsi (gsi, e, true, NULL_TREE,
148438fd1498Szrj true, GSI_SAME_STMT);
148538fd1498Szrj
148638fd1498Szrj /* Convert the step, avoiding possible unsigned->signed overflow. */
148738fd1498Szrj negating = !up && TYPE_UNSIGNED (TREE_TYPE (s));
148838fd1498Szrj if (negating)
148938fd1498Szrj s = fold_build1 (NEGATE_EXPR, TREE_TYPE (s), s);
149038fd1498Szrj s = fold_convert (diff_type, s);
149138fd1498Szrj if (negating)
149238fd1498Szrj s = fold_build1 (NEGATE_EXPR, diff_type, s);
149338fd1498Szrj s = force_gimple_operand_gsi (gsi, s, true, NULL_TREE,
149438fd1498Szrj true, GSI_SAME_STMT);
149538fd1498Szrj
149638fd1498Szrj /* Determine the range, avoiding possible unsigned->signed overflow. */
149738fd1498Szrj negating = !up && TYPE_UNSIGNED (iter_type);
149838fd1498Szrj expr = fold_build2 (MINUS_EXPR, plus_type,
149938fd1498Szrj fold_convert (plus_type, negating ? b : e),
150038fd1498Szrj fold_convert (plus_type, negating ? e : b));
150138fd1498Szrj expr = fold_convert (diff_type, expr);
150238fd1498Szrj if (negating)
150338fd1498Szrj expr = fold_build1 (NEGATE_EXPR, diff_type, expr);
150438fd1498Szrj tree range = force_gimple_operand_gsi
150538fd1498Szrj (gsi, expr, true, NULL_TREE, true, GSI_SAME_STMT);
150638fd1498Szrj
150738fd1498Szrj /* Determine number of iterations. */
150838fd1498Szrj expr = fold_build2 (MINUS_EXPR, diff_type, range, dir);
150938fd1498Szrj expr = fold_build2 (PLUS_EXPR, diff_type, expr, s);
151038fd1498Szrj expr = fold_build2 (TRUNC_DIV_EXPR, diff_type, expr, s);
151138fd1498Szrj
151238fd1498Szrj tree iters = force_gimple_operand_gsi (gsi, expr, true, NULL_TREE,
151338fd1498Szrj true, GSI_SAME_STMT);
151438fd1498Szrj
151538fd1498Szrj counts[ix].base = b;
151638fd1498Szrj counts[ix].iters = iters;
151738fd1498Szrj counts[ix].step = s;
151838fd1498Szrj
151938fd1498Szrj total = fold_build2 (MULT_EXPR, bound_type, total,
152038fd1498Szrj fold_convert (bound_type, iters));
152138fd1498Szrj }
152238fd1498Szrj
152338fd1498Szrj return total;
152438fd1498Szrj }
152538fd1498Szrj
152638fd1498Szrj /* Emit initializers for collapsed loop members. INNER is true if
152738fd1498Szrj this is for the element loop of a TILE. IVAR is the outer
152838fd1498Szrj loop iteration variable, from which collapsed loop iteration values
152938fd1498Szrj are calculated. COUNTS array has been initialized by
153038fd1498Szrj expand_oacc_collapse_inits. */
153138fd1498Szrj
153238fd1498Szrj static void
expand_oacc_collapse_vars(const struct omp_for_data * fd,bool inner,gimple_stmt_iterator * gsi,const oacc_collapse * counts,tree ivar)153338fd1498Szrj expand_oacc_collapse_vars (const struct omp_for_data *fd, bool inner,
153438fd1498Szrj gimple_stmt_iterator *gsi,
153538fd1498Szrj const oacc_collapse *counts, tree ivar)
153638fd1498Szrj {
153738fd1498Szrj tree ivar_type = TREE_TYPE (ivar);
153838fd1498Szrj
153938fd1498Szrj /* The most rapidly changing iteration variable is the innermost
154038fd1498Szrj one. */
154138fd1498Szrj for (int ix = fd->collapse; ix--;)
154238fd1498Szrj {
154338fd1498Szrj const omp_for_data_loop *loop = &fd->loops[ix];
154438fd1498Szrj const oacc_collapse *collapse = &counts[ix];
154538fd1498Szrj tree v = inner ? loop->v : collapse->outer;
154638fd1498Szrj tree iter_type = TREE_TYPE (v);
154738fd1498Szrj tree diff_type = TREE_TYPE (collapse->step);
154838fd1498Szrj tree plus_type = iter_type;
154938fd1498Szrj enum tree_code plus_code = PLUS_EXPR;
155038fd1498Szrj tree expr;
155138fd1498Szrj
155238fd1498Szrj if (POINTER_TYPE_P (iter_type))
155338fd1498Szrj {
155438fd1498Szrj plus_code = POINTER_PLUS_EXPR;
155538fd1498Szrj plus_type = sizetype;
155638fd1498Szrj }
155738fd1498Szrj
155838fd1498Szrj expr = ivar;
155938fd1498Szrj if (ix)
156038fd1498Szrj {
156138fd1498Szrj tree mod = fold_convert (ivar_type, collapse->iters);
156238fd1498Szrj ivar = fold_build2 (TRUNC_DIV_EXPR, ivar_type, expr, mod);
156338fd1498Szrj expr = fold_build2 (TRUNC_MOD_EXPR, ivar_type, expr, mod);
156438fd1498Szrj ivar = force_gimple_operand_gsi (gsi, ivar, true, NULL_TREE,
156538fd1498Szrj true, GSI_SAME_STMT);
156638fd1498Szrj }
156738fd1498Szrj
156838fd1498Szrj expr = fold_build2 (MULT_EXPR, diff_type, fold_convert (diff_type, expr),
156938fd1498Szrj collapse->step);
157038fd1498Szrj expr = fold_build2 (plus_code, iter_type,
157138fd1498Szrj inner ? collapse->outer : collapse->base,
157238fd1498Szrj fold_convert (plus_type, expr));
157338fd1498Szrj expr = force_gimple_operand_gsi (gsi, expr, false, NULL_TREE,
157438fd1498Szrj true, GSI_SAME_STMT);
157538fd1498Szrj gassign *ass = gimple_build_assign (v, expr);
157638fd1498Szrj gsi_insert_before (gsi, ass, GSI_SAME_STMT);
157738fd1498Szrj }
157838fd1498Szrj }
157938fd1498Szrj
158038fd1498Szrj /* Helper function for expand_omp_{for_*,simd}. If this is the outermost
158138fd1498Szrj of the combined collapse > 1 loop constructs, generate code like:
158238fd1498Szrj if (__builtin_expect (N32 cond3 N31, 0)) goto ZERO_ITER_BB;
158338fd1498Szrj if (cond3 is <)
158438fd1498Szrj adj = STEP3 - 1;
158538fd1498Szrj else
158638fd1498Szrj adj = STEP3 + 1;
158738fd1498Szrj count3 = (adj + N32 - N31) / STEP3;
158838fd1498Szrj if (__builtin_expect (N22 cond2 N21, 0)) goto ZERO_ITER_BB;
158938fd1498Szrj if (cond2 is <)
159038fd1498Szrj adj = STEP2 - 1;
159138fd1498Szrj else
159238fd1498Szrj adj = STEP2 + 1;
159338fd1498Szrj count2 = (adj + N22 - N21) / STEP2;
159438fd1498Szrj if (__builtin_expect (N12 cond1 N11, 0)) goto ZERO_ITER_BB;
159538fd1498Szrj if (cond1 is <)
159638fd1498Szrj adj = STEP1 - 1;
159738fd1498Szrj else
159838fd1498Szrj adj = STEP1 + 1;
159938fd1498Szrj count1 = (adj + N12 - N11) / STEP1;
160038fd1498Szrj count = count1 * count2 * count3;
160138fd1498Szrj Furthermore, if ZERO_ITER_BB is NULL, create a BB which does:
160238fd1498Szrj count = 0;
160338fd1498Szrj and set ZERO_ITER_BB to that bb. If this isn't the outermost
160438fd1498Szrj of the combined loop constructs, just initialize COUNTS array
160538fd1498Szrj from the _looptemp_ clauses. */
160638fd1498Szrj
160738fd1498Szrj /* NOTE: It *could* be better to moosh all of the BBs together,
160838fd1498Szrj creating one larger BB with all the computation and the unexpected
160938fd1498Szrj jump at the end. I.e.
161038fd1498Szrj
161138fd1498Szrj bool zero3, zero2, zero1, zero;
161238fd1498Szrj
161338fd1498Szrj zero3 = N32 c3 N31;
161438fd1498Szrj count3 = (N32 - N31) /[cl] STEP3;
161538fd1498Szrj zero2 = N22 c2 N21;
161638fd1498Szrj count2 = (N22 - N21) /[cl] STEP2;
161738fd1498Szrj zero1 = N12 c1 N11;
161838fd1498Szrj count1 = (N12 - N11) /[cl] STEP1;
161938fd1498Szrj zero = zero3 || zero2 || zero1;
162038fd1498Szrj count = count1 * count2 * count3;
162138fd1498Szrj if (__builtin_expect(zero, false)) goto zero_iter_bb;
162238fd1498Szrj
162338fd1498Szrj After all, we expect the zero=false, and thus we expect to have to
162438fd1498Szrj evaluate all of the comparison expressions, so short-circuiting
162538fd1498Szrj oughtn't be a win. Since the condition isn't protecting a
162638fd1498Szrj denominator, we're not concerned about divide-by-zero, so we can
162738fd1498Szrj fully evaluate count even if a numerator turned out to be wrong.
162838fd1498Szrj
162938fd1498Szrj It seems like putting this all together would create much better
163038fd1498Szrj scheduling opportunities, and less pressure on the chip's branch
163138fd1498Szrj predictor. */
163238fd1498Szrj
163338fd1498Szrj static void
expand_omp_for_init_counts(struct omp_for_data * fd,gimple_stmt_iterator * gsi,basic_block & entry_bb,tree * counts,basic_block & zero_iter1_bb,int & first_zero_iter1,basic_block & zero_iter2_bb,int & first_zero_iter2,basic_block & l2_dom_bb)163438fd1498Szrj expand_omp_for_init_counts (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
163538fd1498Szrj basic_block &entry_bb, tree *counts,
163638fd1498Szrj basic_block &zero_iter1_bb, int &first_zero_iter1,
163738fd1498Szrj basic_block &zero_iter2_bb, int &first_zero_iter2,
163838fd1498Szrj basic_block &l2_dom_bb)
163938fd1498Szrj {
164038fd1498Szrj tree t, type = TREE_TYPE (fd->loop.v);
164138fd1498Szrj edge e, ne;
164238fd1498Szrj int i;
164338fd1498Szrj
164438fd1498Szrj /* Collapsed loops need work for expansion into SSA form. */
164538fd1498Szrj gcc_assert (!gimple_in_ssa_p (cfun));
164638fd1498Szrj
164738fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt)
164838fd1498Szrj && TREE_CODE (fd->loop.n2) != INTEGER_CST)
164938fd1498Szrj {
165038fd1498Szrj gcc_assert (fd->ordered == 0);
165138fd1498Szrj /* First two _looptemp_ clauses are for istart/iend, counts[0]
165238fd1498Szrj isn't supposed to be handled, as the inner loop doesn't
165338fd1498Szrj use it. */
165438fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
165538fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
165638fd1498Szrj gcc_assert (innerc);
165738fd1498Szrj for (i = 0; i < fd->collapse; i++)
165838fd1498Szrj {
165938fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
166038fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
166138fd1498Szrj gcc_assert (innerc);
166238fd1498Szrj if (i)
166338fd1498Szrj counts[i] = OMP_CLAUSE_DECL (innerc);
166438fd1498Szrj else
166538fd1498Szrj counts[0] = NULL_TREE;
166638fd1498Szrj }
166738fd1498Szrj return;
166838fd1498Szrj }
166938fd1498Szrj
167038fd1498Szrj for (i = fd->collapse; i < fd->ordered; i++)
167138fd1498Szrj {
167238fd1498Szrj tree itype = TREE_TYPE (fd->loops[i].v);
167338fd1498Szrj counts[i] = NULL_TREE;
167438fd1498Szrj t = fold_binary (fd->loops[i].cond_code, boolean_type_node,
167538fd1498Szrj fold_convert (itype, fd->loops[i].n1),
167638fd1498Szrj fold_convert (itype, fd->loops[i].n2));
167738fd1498Szrj if (t && integer_zerop (t))
167838fd1498Szrj {
167938fd1498Szrj for (i = fd->collapse; i < fd->ordered; i++)
168038fd1498Szrj counts[i] = build_int_cst (type, 0);
168138fd1498Szrj break;
168238fd1498Szrj }
168338fd1498Szrj }
168438fd1498Szrj for (i = 0; i < (fd->ordered ? fd->ordered : fd->collapse); i++)
168538fd1498Szrj {
168638fd1498Szrj tree itype = TREE_TYPE (fd->loops[i].v);
168738fd1498Szrj
168838fd1498Szrj if (i >= fd->collapse && counts[i])
168938fd1498Szrj continue;
169038fd1498Szrj if ((SSA_VAR_P (fd->loop.n2) || i >= fd->collapse)
169138fd1498Szrj && ((t = fold_binary (fd->loops[i].cond_code, boolean_type_node,
169238fd1498Szrj fold_convert (itype, fd->loops[i].n1),
169338fd1498Szrj fold_convert (itype, fd->loops[i].n2)))
169438fd1498Szrj == NULL_TREE || !integer_onep (t)))
169538fd1498Szrj {
169638fd1498Szrj gcond *cond_stmt;
169738fd1498Szrj tree n1, n2;
169838fd1498Szrj n1 = fold_convert (itype, unshare_expr (fd->loops[i].n1));
169938fd1498Szrj n1 = force_gimple_operand_gsi (gsi, n1, true, NULL_TREE,
170038fd1498Szrj true, GSI_SAME_STMT);
170138fd1498Szrj n2 = fold_convert (itype, unshare_expr (fd->loops[i].n2));
170238fd1498Szrj n2 = force_gimple_operand_gsi (gsi, n2, true, NULL_TREE,
170338fd1498Szrj true, GSI_SAME_STMT);
170438fd1498Szrj cond_stmt = gimple_build_cond (fd->loops[i].cond_code, n1, n2,
170538fd1498Szrj NULL_TREE, NULL_TREE);
170638fd1498Szrj gsi_insert_before (gsi, cond_stmt, GSI_SAME_STMT);
170738fd1498Szrj if (walk_tree (gimple_cond_lhs_ptr (cond_stmt),
170838fd1498Szrj expand_omp_regimplify_p, NULL, NULL)
170938fd1498Szrj || walk_tree (gimple_cond_rhs_ptr (cond_stmt),
171038fd1498Szrj expand_omp_regimplify_p, NULL, NULL))
171138fd1498Szrj {
171238fd1498Szrj *gsi = gsi_for_stmt (cond_stmt);
171338fd1498Szrj gimple_regimplify_operands (cond_stmt, gsi);
171438fd1498Szrj }
171538fd1498Szrj e = split_block (entry_bb, cond_stmt);
171638fd1498Szrj basic_block &zero_iter_bb
171738fd1498Szrj = i < fd->collapse ? zero_iter1_bb : zero_iter2_bb;
171838fd1498Szrj int &first_zero_iter
171938fd1498Szrj = i < fd->collapse ? first_zero_iter1 : first_zero_iter2;
172038fd1498Szrj if (zero_iter_bb == NULL)
172138fd1498Szrj {
172238fd1498Szrj gassign *assign_stmt;
172338fd1498Szrj first_zero_iter = i;
172438fd1498Szrj zero_iter_bb = create_empty_bb (entry_bb);
172538fd1498Szrj add_bb_to_loop (zero_iter_bb, entry_bb->loop_father);
172638fd1498Szrj *gsi = gsi_after_labels (zero_iter_bb);
172738fd1498Szrj if (i < fd->collapse)
172838fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.n2,
172938fd1498Szrj build_zero_cst (type));
173038fd1498Szrj else
173138fd1498Szrj {
173238fd1498Szrj counts[i] = create_tmp_reg (type, ".count");
173338fd1498Szrj assign_stmt
173438fd1498Szrj = gimple_build_assign (counts[i], build_zero_cst (type));
173538fd1498Szrj }
173638fd1498Szrj gsi_insert_before (gsi, assign_stmt, GSI_SAME_STMT);
173738fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, zero_iter_bb,
173838fd1498Szrj entry_bb);
173938fd1498Szrj }
174038fd1498Szrj ne = make_edge (entry_bb, zero_iter_bb, EDGE_FALSE_VALUE);
174138fd1498Szrj ne->probability = profile_probability::very_unlikely ();
174238fd1498Szrj e->flags = EDGE_TRUE_VALUE;
174338fd1498Szrj e->probability = ne->probability.invert ();
174438fd1498Szrj if (l2_dom_bb == NULL)
174538fd1498Szrj l2_dom_bb = entry_bb;
174638fd1498Szrj entry_bb = e->dest;
174738fd1498Szrj *gsi = gsi_last_nondebug_bb (entry_bb);
174838fd1498Szrj }
174938fd1498Szrj
175038fd1498Szrj if (POINTER_TYPE_P (itype))
175138fd1498Szrj itype = signed_type_for (itype);
175238fd1498Szrj t = build_int_cst (itype, (fd->loops[i].cond_code == LT_EXPR
175338fd1498Szrj ? -1 : 1));
175438fd1498Szrj t = fold_build2 (PLUS_EXPR, itype,
175538fd1498Szrj fold_convert (itype, fd->loops[i].step), t);
175638fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, t,
175738fd1498Szrj fold_convert (itype, fd->loops[i].n2));
175838fd1498Szrj t = fold_build2 (MINUS_EXPR, itype, t,
175938fd1498Szrj fold_convert (itype, fd->loops[i].n1));
176038fd1498Szrj /* ?? We could probably use CEIL_DIV_EXPR instead of
176138fd1498Szrj TRUNC_DIV_EXPR and adjusting by hand. Unless we can't
176238fd1498Szrj generate the same code in the end because generically we
176338fd1498Szrj don't know that the values involved must be negative for
176438fd1498Szrj GT?? */
176538fd1498Szrj if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
176638fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype,
176738fd1498Szrj fold_build1 (NEGATE_EXPR, itype, t),
176838fd1498Szrj fold_build1 (NEGATE_EXPR, itype,
176938fd1498Szrj fold_convert (itype,
177038fd1498Szrj fd->loops[i].step)));
177138fd1498Szrj else
177238fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype, t,
177338fd1498Szrj fold_convert (itype, fd->loops[i].step));
177438fd1498Szrj t = fold_convert (type, t);
177538fd1498Szrj if (TREE_CODE (t) == INTEGER_CST)
177638fd1498Szrj counts[i] = t;
177738fd1498Szrj else
177838fd1498Szrj {
177938fd1498Szrj if (i < fd->collapse || i != first_zero_iter2)
178038fd1498Szrj counts[i] = create_tmp_reg (type, ".count");
178138fd1498Szrj expand_omp_build_assign (gsi, counts[i], t);
178238fd1498Szrj }
178338fd1498Szrj if (SSA_VAR_P (fd->loop.n2) && i < fd->collapse)
178438fd1498Szrj {
178538fd1498Szrj if (i == 0)
178638fd1498Szrj t = counts[0];
178738fd1498Szrj else
178838fd1498Szrj t = fold_build2 (MULT_EXPR, type, fd->loop.n2, counts[i]);
178938fd1498Szrj expand_omp_build_assign (gsi, fd->loop.n2, t);
179038fd1498Szrj }
179138fd1498Szrj }
179238fd1498Szrj }
179338fd1498Szrj
179438fd1498Szrj /* Helper function for expand_omp_{for_*,simd}. Generate code like:
179538fd1498Szrj T = V;
179638fd1498Szrj V3 = N31 + (T % count3) * STEP3;
179738fd1498Szrj T = T / count3;
179838fd1498Szrj V2 = N21 + (T % count2) * STEP2;
179938fd1498Szrj T = T / count2;
180038fd1498Szrj V1 = N11 + T * STEP1;
180138fd1498Szrj if this loop doesn't have an inner loop construct combined with it.
180238fd1498Szrj If it does have an inner loop construct combined with it and the
180338fd1498Szrj iteration count isn't known constant, store values from counts array
180438fd1498Szrj into its _looptemp_ temporaries instead. */
180538fd1498Szrj
180638fd1498Szrj static void
expand_omp_for_init_vars(struct omp_for_data * fd,gimple_stmt_iterator * gsi,tree * counts,gimple * inner_stmt,tree startvar)180738fd1498Szrj expand_omp_for_init_vars (struct omp_for_data *fd, gimple_stmt_iterator *gsi,
180838fd1498Szrj tree *counts, gimple *inner_stmt, tree startvar)
180938fd1498Szrj {
181038fd1498Szrj int i;
181138fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
181238fd1498Szrj {
181338fd1498Szrj /* If fd->loop.n2 is constant, then no propagation of the counts
181438fd1498Szrj is needed, they are constant. */
181538fd1498Szrj if (TREE_CODE (fd->loop.n2) == INTEGER_CST)
181638fd1498Szrj return;
181738fd1498Szrj
181838fd1498Szrj tree clauses = gimple_code (inner_stmt) != GIMPLE_OMP_FOR
181938fd1498Szrj ? gimple_omp_taskreg_clauses (inner_stmt)
182038fd1498Szrj : gimple_omp_for_clauses (inner_stmt);
182138fd1498Szrj /* First two _looptemp_ clauses are for istart/iend, counts[0]
182238fd1498Szrj isn't supposed to be handled, as the inner loop doesn't
182338fd1498Szrj use it. */
182438fd1498Szrj tree innerc = omp_find_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
182538fd1498Szrj gcc_assert (innerc);
182638fd1498Szrj for (i = 0; i < fd->collapse; i++)
182738fd1498Szrj {
182838fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
182938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
183038fd1498Szrj gcc_assert (innerc);
183138fd1498Szrj if (i)
183238fd1498Szrj {
183338fd1498Szrj tree tem = OMP_CLAUSE_DECL (innerc);
183438fd1498Szrj tree t = fold_convert (TREE_TYPE (tem), counts[i]);
183538fd1498Szrj t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE,
183638fd1498Szrj false, GSI_CONTINUE_LINKING);
183738fd1498Szrj gassign *stmt = gimple_build_assign (tem, t);
183838fd1498Szrj gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING);
183938fd1498Szrj }
184038fd1498Szrj }
184138fd1498Szrj return;
184238fd1498Szrj }
184338fd1498Szrj
184438fd1498Szrj tree type = TREE_TYPE (fd->loop.v);
184538fd1498Szrj tree tem = create_tmp_reg (type, ".tem");
184638fd1498Szrj gassign *stmt = gimple_build_assign (tem, startvar);
184738fd1498Szrj gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING);
184838fd1498Szrj
184938fd1498Szrj for (i = fd->collapse - 1; i >= 0; i--)
185038fd1498Szrj {
185138fd1498Szrj tree vtype = TREE_TYPE (fd->loops[i].v), itype, t;
185238fd1498Szrj itype = vtype;
185338fd1498Szrj if (POINTER_TYPE_P (vtype))
185438fd1498Szrj itype = signed_type_for (vtype);
185538fd1498Szrj if (i != 0)
185638fd1498Szrj t = fold_build2 (TRUNC_MOD_EXPR, type, tem, counts[i]);
185738fd1498Szrj else
185838fd1498Szrj t = tem;
185938fd1498Szrj t = fold_convert (itype, t);
186038fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t,
186138fd1498Szrj fold_convert (itype, fd->loops[i].step));
186238fd1498Szrj if (POINTER_TYPE_P (vtype))
186338fd1498Szrj t = fold_build_pointer_plus (fd->loops[i].n1, t);
186438fd1498Szrj else
186538fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, fd->loops[i].n1, t);
186638fd1498Szrj t = force_gimple_operand_gsi (gsi, t,
186738fd1498Szrj DECL_P (fd->loops[i].v)
186838fd1498Szrj && TREE_ADDRESSABLE (fd->loops[i].v),
186938fd1498Szrj NULL_TREE, false,
187038fd1498Szrj GSI_CONTINUE_LINKING);
187138fd1498Szrj stmt = gimple_build_assign (fd->loops[i].v, t);
187238fd1498Szrj gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING);
187338fd1498Szrj if (i != 0)
187438fd1498Szrj {
187538fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, type, tem, counts[i]);
187638fd1498Szrj t = force_gimple_operand_gsi (gsi, t, false, NULL_TREE,
187738fd1498Szrj false, GSI_CONTINUE_LINKING);
187838fd1498Szrj stmt = gimple_build_assign (tem, t);
187938fd1498Szrj gsi_insert_after (gsi, stmt, GSI_CONTINUE_LINKING);
188038fd1498Szrj }
188138fd1498Szrj }
188238fd1498Szrj }
188338fd1498Szrj
188438fd1498Szrj /* Helper function for expand_omp_for_*. Generate code like:
188538fd1498Szrj L10:
188638fd1498Szrj V3 += STEP3;
188738fd1498Szrj if (V3 cond3 N32) goto BODY_BB; else goto L11;
188838fd1498Szrj L11:
188938fd1498Szrj V3 = N31;
189038fd1498Szrj V2 += STEP2;
189138fd1498Szrj if (V2 cond2 N22) goto BODY_BB; else goto L12;
189238fd1498Szrj L12:
189338fd1498Szrj V2 = N21;
189438fd1498Szrj V1 += STEP1;
189538fd1498Szrj goto BODY_BB; */
189638fd1498Szrj
189738fd1498Szrj static basic_block
extract_omp_for_update_vars(struct omp_for_data * fd,basic_block cont_bb,basic_block body_bb)189838fd1498Szrj extract_omp_for_update_vars (struct omp_for_data *fd, basic_block cont_bb,
189938fd1498Szrj basic_block body_bb)
190038fd1498Szrj {
190138fd1498Szrj basic_block last_bb, bb, collapse_bb = NULL;
190238fd1498Szrj int i;
190338fd1498Szrj gimple_stmt_iterator gsi;
190438fd1498Szrj edge e;
190538fd1498Szrj tree t;
190638fd1498Szrj gimple *stmt;
190738fd1498Szrj
190838fd1498Szrj last_bb = cont_bb;
190938fd1498Szrj for (i = fd->collapse - 1; i >= 0; i--)
191038fd1498Szrj {
191138fd1498Szrj tree vtype = TREE_TYPE (fd->loops[i].v);
191238fd1498Szrj
191338fd1498Szrj bb = create_empty_bb (last_bb);
191438fd1498Szrj add_bb_to_loop (bb, last_bb->loop_father);
191538fd1498Szrj gsi = gsi_start_bb (bb);
191638fd1498Szrj
191738fd1498Szrj if (i < fd->collapse - 1)
191838fd1498Szrj {
191938fd1498Szrj e = make_edge (last_bb, bb, EDGE_FALSE_VALUE);
192038fd1498Szrj e->probability = profile_probability::guessed_always ().apply_scale (1, 8);
192138fd1498Szrj
192238fd1498Szrj t = fd->loops[i + 1].n1;
192338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
192438fd1498Szrj DECL_P (fd->loops[i + 1].v)
192538fd1498Szrj && TREE_ADDRESSABLE (fd->loops[i
192638fd1498Szrj + 1].v),
192738fd1498Szrj NULL_TREE, false,
192838fd1498Szrj GSI_CONTINUE_LINKING);
192938fd1498Szrj stmt = gimple_build_assign (fd->loops[i + 1].v, t);
193038fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
193138fd1498Szrj }
193238fd1498Szrj else
193338fd1498Szrj collapse_bb = bb;
193438fd1498Szrj
193538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, bb, last_bb);
193638fd1498Szrj
193738fd1498Szrj if (POINTER_TYPE_P (vtype))
193838fd1498Szrj t = fold_build_pointer_plus (fd->loops[i].v, fd->loops[i].step);
193938fd1498Szrj else
194038fd1498Szrj t = fold_build2 (PLUS_EXPR, vtype, fd->loops[i].v, fd->loops[i].step);
194138fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
194238fd1498Szrj DECL_P (fd->loops[i].v)
194338fd1498Szrj && TREE_ADDRESSABLE (fd->loops[i].v),
194438fd1498Szrj NULL_TREE, false, GSI_CONTINUE_LINKING);
194538fd1498Szrj stmt = gimple_build_assign (fd->loops[i].v, t);
194638fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
194738fd1498Szrj
194838fd1498Szrj if (i > 0)
194938fd1498Szrj {
195038fd1498Szrj t = fd->loops[i].n2;
195138fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
195238fd1498Szrj false, GSI_CONTINUE_LINKING);
195338fd1498Szrj tree v = fd->loops[i].v;
195438fd1498Szrj if (DECL_P (v) && TREE_ADDRESSABLE (v))
195538fd1498Szrj v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE,
195638fd1498Szrj false, GSI_CONTINUE_LINKING);
195738fd1498Szrj t = fold_build2 (fd->loops[i].cond_code, boolean_type_node, v, t);
195838fd1498Szrj stmt = gimple_build_cond_empty (t);
195938fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
1960*58e805e6Szrj if (walk_tree (gimple_cond_lhs_ptr (as_a <gcond *> (stmt)),
1961*58e805e6Szrj expand_omp_regimplify_p, NULL, NULL)
1962*58e805e6Szrj || walk_tree (gimple_cond_rhs_ptr (as_a <gcond *> (stmt)),
1963*58e805e6Szrj expand_omp_regimplify_p, NULL, NULL))
1964*58e805e6Szrj gimple_regimplify_operands (stmt, &gsi);
196538fd1498Szrj e = make_edge (bb, body_bb, EDGE_TRUE_VALUE);
196638fd1498Szrj e->probability = profile_probability::guessed_always ().apply_scale (7, 8);
196738fd1498Szrj }
196838fd1498Szrj else
196938fd1498Szrj make_edge (bb, body_bb, EDGE_FALLTHRU);
197038fd1498Szrj last_bb = bb;
197138fd1498Szrj }
197238fd1498Szrj
197338fd1498Szrj return collapse_bb;
197438fd1498Szrj }
197538fd1498Szrj
197638fd1498Szrj /* Expand #pragma omp ordered depend(source). */
197738fd1498Szrj
197838fd1498Szrj static void
expand_omp_ordered_source(gimple_stmt_iterator * gsi,struct omp_for_data * fd,tree * counts,location_t loc)197938fd1498Szrj expand_omp_ordered_source (gimple_stmt_iterator *gsi, struct omp_for_data *fd,
198038fd1498Szrj tree *counts, location_t loc)
198138fd1498Szrj {
198238fd1498Szrj enum built_in_function source_ix
198338fd1498Szrj = fd->iter_type == long_integer_type_node
198438fd1498Szrj ? BUILT_IN_GOMP_DOACROSS_POST : BUILT_IN_GOMP_DOACROSS_ULL_POST;
198538fd1498Szrj gimple *g
198638fd1498Szrj = gimple_build_call (builtin_decl_explicit (source_ix), 1,
198738fd1498Szrj build_fold_addr_expr (counts[fd->ordered]));
198838fd1498Szrj gimple_set_location (g, loc);
198938fd1498Szrj gsi_insert_before (gsi, g, GSI_SAME_STMT);
199038fd1498Szrj }
199138fd1498Szrj
199238fd1498Szrj /* Expand a single depend from #pragma omp ordered depend(sink:...). */
199338fd1498Szrj
199438fd1498Szrj static void
expand_omp_ordered_sink(gimple_stmt_iterator * gsi,struct omp_for_data * fd,tree * counts,tree c,location_t loc)199538fd1498Szrj expand_omp_ordered_sink (gimple_stmt_iterator *gsi, struct omp_for_data *fd,
199638fd1498Szrj tree *counts, tree c, location_t loc)
199738fd1498Szrj {
199838fd1498Szrj auto_vec<tree, 10> args;
199938fd1498Szrj enum built_in_function sink_ix
200038fd1498Szrj = fd->iter_type == long_integer_type_node
200138fd1498Szrj ? BUILT_IN_GOMP_DOACROSS_WAIT : BUILT_IN_GOMP_DOACROSS_ULL_WAIT;
200238fd1498Szrj tree t, off, coff = NULL_TREE, deps = OMP_CLAUSE_DECL (c), cond = NULL_TREE;
200338fd1498Szrj int i;
200438fd1498Szrj gimple_stmt_iterator gsi2 = *gsi;
200538fd1498Szrj bool warned_step = false;
200638fd1498Szrj
200738fd1498Szrj for (i = 0; i < fd->ordered; i++)
200838fd1498Szrj {
200938fd1498Szrj tree step = NULL_TREE;
201038fd1498Szrj off = TREE_PURPOSE (deps);
201138fd1498Szrj if (TREE_CODE (off) == TRUNC_DIV_EXPR)
201238fd1498Szrj {
201338fd1498Szrj step = TREE_OPERAND (off, 1);
201438fd1498Szrj off = TREE_OPERAND (off, 0);
201538fd1498Szrj }
201638fd1498Szrj if (!integer_zerop (off))
201738fd1498Szrj {
201838fd1498Szrj gcc_assert (fd->loops[i].cond_code == LT_EXPR
201938fd1498Szrj || fd->loops[i].cond_code == GT_EXPR);
202038fd1498Szrj bool forward = fd->loops[i].cond_code == LT_EXPR;
202138fd1498Szrj if (step)
202238fd1498Szrj {
202338fd1498Szrj /* Non-simple Fortran DO loops. If step is variable,
202438fd1498Szrj we don't know at compile even the direction, so can't
202538fd1498Szrj warn. */
202638fd1498Szrj if (TREE_CODE (step) != INTEGER_CST)
202738fd1498Szrj break;
202838fd1498Szrj forward = tree_int_cst_sgn (step) != -1;
202938fd1498Szrj }
203038fd1498Szrj if (forward ^ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
203138fd1498Szrj warning_at (loc, 0, "%<depend(sink)%> clause waiting for "
203238fd1498Szrj "lexically later iteration");
203338fd1498Szrj break;
203438fd1498Szrj }
203538fd1498Szrj deps = TREE_CHAIN (deps);
203638fd1498Szrj }
203738fd1498Szrj /* If all offsets corresponding to the collapsed loops are zero,
203838fd1498Szrj this depend clause can be ignored. FIXME: but there is still a
203938fd1498Szrj flush needed. We need to emit one __sync_synchronize () for it
204038fd1498Szrj though (perhaps conditionally)? Solve this together with the
204138fd1498Szrj conservative dependence folding optimization.
204238fd1498Szrj if (i >= fd->collapse)
204338fd1498Szrj return; */
204438fd1498Szrj
204538fd1498Szrj deps = OMP_CLAUSE_DECL (c);
204638fd1498Szrj gsi_prev (&gsi2);
204738fd1498Szrj edge e1 = split_block (gsi_bb (gsi2), gsi_stmt (gsi2));
204838fd1498Szrj edge e2 = split_block_after_labels (e1->dest);
204938fd1498Szrj
205038fd1498Szrj gsi2 = gsi_after_labels (e1->dest);
205138fd1498Szrj *gsi = gsi_last_bb (e1->src);
205238fd1498Szrj for (i = 0; i < fd->ordered; i++)
205338fd1498Szrj {
205438fd1498Szrj tree itype = TREE_TYPE (fd->loops[i].v);
205538fd1498Szrj tree step = NULL_TREE;
205638fd1498Szrj tree orig_off = NULL_TREE;
205738fd1498Szrj if (POINTER_TYPE_P (itype))
205838fd1498Szrj itype = sizetype;
205938fd1498Szrj if (i)
206038fd1498Szrj deps = TREE_CHAIN (deps);
206138fd1498Szrj off = TREE_PURPOSE (deps);
206238fd1498Szrj if (TREE_CODE (off) == TRUNC_DIV_EXPR)
206338fd1498Szrj {
206438fd1498Szrj step = TREE_OPERAND (off, 1);
206538fd1498Szrj off = TREE_OPERAND (off, 0);
206638fd1498Szrj gcc_assert (fd->loops[i].cond_code == LT_EXPR
206738fd1498Szrj && integer_onep (fd->loops[i].step)
206838fd1498Szrj && !POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)));
206938fd1498Szrj }
207038fd1498Szrj tree s = fold_convert_loc (loc, itype, step ? step : fd->loops[i].step);
207138fd1498Szrj if (step)
207238fd1498Szrj {
207338fd1498Szrj off = fold_convert_loc (loc, itype, off);
207438fd1498Szrj orig_off = off;
207538fd1498Szrj off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, s);
207638fd1498Szrj }
207738fd1498Szrj
207838fd1498Szrj if (integer_zerop (off))
207938fd1498Szrj t = boolean_true_node;
208038fd1498Szrj else
208138fd1498Szrj {
208238fd1498Szrj tree a;
208338fd1498Szrj tree co = fold_convert_loc (loc, itype, off);
208438fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)))
208538fd1498Szrj {
208638fd1498Szrj if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
208738fd1498Szrj co = fold_build1_loc (loc, NEGATE_EXPR, itype, co);
208838fd1498Szrj a = fold_build2_loc (loc, POINTER_PLUS_EXPR,
208938fd1498Szrj TREE_TYPE (fd->loops[i].v), fd->loops[i].v,
209038fd1498Szrj co);
209138fd1498Szrj }
209238fd1498Szrj else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
209338fd1498Szrj a = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v),
209438fd1498Szrj fd->loops[i].v, co);
209538fd1498Szrj else
209638fd1498Szrj a = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (fd->loops[i].v),
209738fd1498Szrj fd->loops[i].v, co);
209838fd1498Szrj if (step)
209938fd1498Szrj {
210038fd1498Szrj tree t1, t2;
210138fd1498Szrj if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
210238fd1498Szrj t1 = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
210338fd1498Szrj fd->loops[i].n1);
210438fd1498Szrj else
210538fd1498Szrj t1 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
210638fd1498Szrj fd->loops[i].n2);
210738fd1498Szrj if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
210838fd1498Szrj t2 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
210938fd1498Szrj fd->loops[i].n2);
211038fd1498Szrj else
211138fd1498Szrj t2 = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
211238fd1498Szrj fd->loops[i].n1);
211338fd1498Szrj t = fold_build2_loc (loc, LT_EXPR, boolean_type_node,
211438fd1498Szrj step, build_int_cst (TREE_TYPE (step), 0));
211538fd1498Szrj if (TREE_CODE (step) != INTEGER_CST)
211638fd1498Szrj {
211738fd1498Szrj t1 = unshare_expr (t1);
211838fd1498Szrj t1 = force_gimple_operand_gsi (gsi, t1, true, NULL_TREE,
211938fd1498Szrj false, GSI_CONTINUE_LINKING);
212038fd1498Szrj t2 = unshare_expr (t2);
212138fd1498Szrj t2 = force_gimple_operand_gsi (gsi, t2, true, NULL_TREE,
212238fd1498Szrj false, GSI_CONTINUE_LINKING);
212338fd1498Szrj }
212438fd1498Szrj t = fold_build3_loc (loc, COND_EXPR, boolean_type_node,
212538fd1498Szrj t, t2, t1);
212638fd1498Szrj }
212738fd1498Szrj else if (fd->loops[i].cond_code == LT_EXPR)
212838fd1498Szrj {
212938fd1498Szrj if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
213038fd1498Szrj t = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
213138fd1498Szrj fd->loops[i].n1);
213238fd1498Szrj else
213338fd1498Szrj t = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
213438fd1498Szrj fd->loops[i].n2);
213538fd1498Szrj }
213638fd1498Szrj else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
213738fd1498Szrj t = fold_build2_loc (loc, GT_EXPR, boolean_type_node, a,
213838fd1498Szrj fd->loops[i].n2);
213938fd1498Szrj else
214038fd1498Szrj t = fold_build2_loc (loc, LE_EXPR, boolean_type_node, a,
214138fd1498Szrj fd->loops[i].n1);
214238fd1498Szrj }
214338fd1498Szrj if (cond)
214438fd1498Szrj cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, cond, t);
214538fd1498Szrj else
214638fd1498Szrj cond = t;
214738fd1498Szrj
214838fd1498Szrj off = fold_convert_loc (loc, itype, off);
214938fd1498Szrj
215038fd1498Szrj if (step
215138fd1498Szrj || (fd->loops[i].cond_code == LT_EXPR
215238fd1498Szrj ? !integer_onep (fd->loops[i].step)
215338fd1498Szrj : !integer_minus_onep (fd->loops[i].step)))
215438fd1498Szrj {
215538fd1498Szrj if (step == NULL_TREE
215638fd1498Szrj && TYPE_UNSIGNED (itype)
215738fd1498Szrj && fd->loops[i].cond_code == GT_EXPR)
215838fd1498Szrj t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype, off,
215938fd1498Szrj fold_build1_loc (loc, NEGATE_EXPR, itype,
216038fd1498Szrj s));
216138fd1498Szrj else
216238fd1498Szrj t = fold_build2_loc (loc, TRUNC_MOD_EXPR, itype,
216338fd1498Szrj orig_off ? orig_off : off, s);
216438fd1498Szrj t = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, t,
216538fd1498Szrj build_int_cst (itype, 0));
216638fd1498Szrj if (integer_zerop (t) && !warned_step)
216738fd1498Szrj {
216838fd1498Szrj warning_at (loc, 0, "%<depend(sink)%> refers to iteration never "
216938fd1498Szrj "in the iteration space");
217038fd1498Szrj warned_step = true;
217138fd1498Szrj }
217238fd1498Szrj cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node,
217338fd1498Szrj cond, t);
217438fd1498Szrj }
217538fd1498Szrj
217638fd1498Szrj if (i <= fd->collapse - 1 && fd->collapse > 1)
217738fd1498Szrj t = fd->loop.v;
217838fd1498Szrj else if (counts[i])
217938fd1498Szrj t = counts[i];
218038fd1498Szrj else
218138fd1498Szrj {
218238fd1498Szrj t = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v),
218338fd1498Szrj fd->loops[i].v, fd->loops[i].n1);
218438fd1498Szrj t = fold_convert_loc (loc, fd->iter_type, t);
218538fd1498Szrj }
218638fd1498Szrj if (step)
218738fd1498Szrj /* We have divided off by step already earlier. */;
218838fd1498Szrj else if (TYPE_UNSIGNED (itype) && fd->loops[i].cond_code == GT_EXPR)
218938fd1498Szrj off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off,
219038fd1498Szrj fold_build1_loc (loc, NEGATE_EXPR, itype,
219138fd1498Szrj s));
219238fd1498Szrj else
219338fd1498Szrj off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, s);
219438fd1498Szrj if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
219538fd1498Szrj off = fold_build1_loc (loc, NEGATE_EXPR, itype, off);
219638fd1498Szrj off = fold_convert_loc (loc, fd->iter_type, off);
219738fd1498Szrj if (i <= fd->collapse - 1 && fd->collapse > 1)
219838fd1498Szrj {
219938fd1498Szrj if (i)
220038fd1498Szrj off = fold_build2_loc (loc, PLUS_EXPR, fd->iter_type, coff,
220138fd1498Szrj off);
220238fd1498Szrj if (i < fd->collapse - 1)
220338fd1498Szrj {
220438fd1498Szrj coff = fold_build2_loc (loc, MULT_EXPR, fd->iter_type, off,
220538fd1498Szrj counts[i]);
220638fd1498Szrj continue;
220738fd1498Szrj }
220838fd1498Szrj }
220938fd1498Szrj off = unshare_expr (off);
221038fd1498Szrj t = fold_build2_loc (loc, PLUS_EXPR, fd->iter_type, t, off);
221138fd1498Szrj t = force_gimple_operand_gsi (&gsi2, t, true, NULL_TREE,
221238fd1498Szrj true, GSI_SAME_STMT);
221338fd1498Szrj args.safe_push (t);
221438fd1498Szrj }
221538fd1498Szrj gimple *g = gimple_build_call_vec (builtin_decl_explicit (sink_ix), args);
221638fd1498Szrj gimple_set_location (g, loc);
221738fd1498Szrj gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
221838fd1498Szrj
221938fd1498Szrj cond = unshare_expr (cond);
222038fd1498Szrj cond = force_gimple_operand_gsi (gsi, cond, true, NULL_TREE, false,
222138fd1498Szrj GSI_CONTINUE_LINKING);
222238fd1498Szrj gsi_insert_after (gsi, gimple_build_cond_empty (cond), GSI_NEW_STMT);
222338fd1498Szrj edge e3 = make_edge (e1->src, e2->dest, EDGE_FALSE_VALUE);
222438fd1498Szrj e3->probability = profile_probability::guessed_always ().apply_scale (1, 8);
222538fd1498Szrj e1->probability = e3->probability.invert ();
222638fd1498Szrj e1->flags = EDGE_TRUE_VALUE;
222738fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, e2->dest, e1->src);
222838fd1498Szrj
222938fd1498Szrj *gsi = gsi_after_labels (e2->dest);
223038fd1498Szrj }
223138fd1498Szrj
223238fd1498Szrj /* Expand all #pragma omp ordered depend(source) and
223338fd1498Szrj #pragma omp ordered depend(sink:...) constructs in the current
223438fd1498Szrj #pragma omp for ordered(n) region. */
223538fd1498Szrj
223638fd1498Szrj static void
expand_omp_ordered_source_sink(struct omp_region * region,struct omp_for_data * fd,tree * counts,basic_block cont_bb)223738fd1498Szrj expand_omp_ordered_source_sink (struct omp_region *region,
223838fd1498Szrj struct omp_for_data *fd, tree *counts,
223938fd1498Szrj basic_block cont_bb)
224038fd1498Szrj {
224138fd1498Szrj struct omp_region *inner;
224238fd1498Szrj int i;
224338fd1498Szrj for (i = fd->collapse - 1; i < fd->ordered; i++)
224438fd1498Szrj if (i == fd->collapse - 1 && fd->collapse > 1)
224538fd1498Szrj counts[i] = NULL_TREE;
224638fd1498Szrj else if (i >= fd->collapse && !cont_bb)
224738fd1498Szrj counts[i] = build_zero_cst (fd->iter_type);
224838fd1498Szrj else if (!POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))
224938fd1498Szrj && integer_onep (fd->loops[i].step))
225038fd1498Szrj counts[i] = NULL_TREE;
225138fd1498Szrj else
225238fd1498Szrj counts[i] = create_tmp_var (fd->iter_type, ".orditer");
225338fd1498Szrj tree atype
225438fd1498Szrj = build_array_type_nelts (fd->iter_type, fd->ordered - fd->collapse + 1);
225538fd1498Szrj counts[fd->ordered] = create_tmp_var (atype, ".orditera");
225638fd1498Szrj TREE_ADDRESSABLE (counts[fd->ordered]) = 1;
225738fd1498Szrj
225838fd1498Szrj for (inner = region->inner; inner; inner = inner->next)
225938fd1498Szrj if (inner->type == GIMPLE_OMP_ORDERED)
226038fd1498Szrj {
226138fd1498Szrj gomp_ordered *ord_stmt = inner->ord_stmt;
226238fd1498Szrj gimple_stmt_iterator gsi = gsi_for_stmt (ord_stmt);
226338fd1498Szrj location_t loc = gimple_location (ord_stmt);
226438fd1498Szrj tree c;
226538fd1498Szrj for (c = gimple_omp_ordered_clauses (ord_stmt);
226638fd1498Szrj c; c = OMP_CLAUSE_CHAIN (c))
226738fd1498Szrj if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)
226838fd1498Szrj break;
226938fd1498Szrj if (c)
227038fd1498Szrj expand_omp_ordered_source (&gsi, fd, counts, loc);
227138fd1498Szrj for (c = gimple_omp_ordered_clauses (ord_stmt);
227238fd1498Szrj c; c = OMP_CLAUSE_CHAIN (c))
227338fd1498Szrj if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
227438fd1498Szrj expand_omp_ordered_sink (&gsi, fd, counts, c, loc);
227538fd1498Szrj gsi_remove (&gsi, true);
227638fd1498Szrj }
227738fd1498Szrj }
227838fd1498Szrj
227938fd1498Szrj /* Wrap the body into fd->ordered - fd->collapse loops that aren't
228038fd1498Szrj collapsed. */
228138fd1498Szrj
228238fd1498Szrj static basic_block
expand_omp_for_ordered_loops(struct omp_for_data * fd,tree * counts,basic_block cont_bb,basic_block body_bb,bool ordered_lastprivate)228338fd1498Szrj expand_omp_for_ordered_loops (struct omp_for_data *fd, tree *counts,
228438fd1498Szrj basic_block cont_bb, basic_block body_bb,
228538fd1498Szrj bool ordered_lastprivate)
228638fd1498Szrj {
228738fd1498Szrj if (fd->ordered == fd->collapse)
228838fd1498Szrj return cont_bb;
228938fd1498Szrj
229038fd1498Szrj if (!cont_bb)
229138fd1498Szrj {
229238fd1498Szrj gimple_stmt_iterator gsi = gsi_after_labels (body_bb);
229338fd1498Szrj for (int i = fd->collapse; i < fd->ordered; i++)
229438fd1498Szrj {
229538fd1498Szrj tree type = TREE_TYPE (fd->loops[i].v);
229638fd1498Szrj tree n1 = fold_convert (type, fd->loops[i].n1);
229738fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v, n1);
229838fd1498Szrj tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered],
229938fd1498Szrj size_int (i - fd->collapse + 1),
230038fd1498Szrj NULL_TREE, NULL_TREE);
230138fd1498Szrj expand_omp_build_assign (&gsi, aref, build_zero_cst (fd->iter_type));
230238fd1498Szrj }
230338fd1498Szrj return NULL;
230438fd1498Szrj }
230538fd1498Szrj
230638fd1498Szrj for (int i = fd->ordered - 1; i >= fd->collapse; i--)
230738fd1498Szrj {
230838fd1498Szrj tree t, type = TREE_TYPE (fd->loops[i].v);
230938fd1498Szrj gimple_stmt_iterator gsi = gsi_after_labels (body_bb);
231038fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v,
231138fd1498Szrj fold_convert (type, fd->loops[i].n1));
231238fd1498Szrj if (counts[i])
231338fd1498Szrj expand_omp_build_assign (&gsi, counts[i],
231438fd1498Szrj build_zero_cst (fd->iter_type));
231538fd1498Szrj tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered],
231638fd1498Szrj size_int (i - fd->collapse + 1),
231738fd1498Szrj NULL_TREE, NULL_TREE);
231838fd1498Szrj expand_omp_build_assign (&gsi, aref, build_zero_cst (fd->iter_type));
231938fd1498Szrj if (!gsi_end_p (gsi))
232038fd1498Szrj gsi_prev (&gsi);
232138fd1498Szrj else
232238fd1498Szrj gsi = gsi_last_bb (body_bb);
232338fd1498Szrj edge e1 = split_block (body_bb, gsi_stmt (gsi));
232438fd1498Szrj basic_block new_body = e1->dest;
232538fd1498Szrj if (body_bb == cont_bb)
232638fd1498Szrj cont_bb = new_body;
232738fd1498Szrj edge e2 = NULL;
232838fd1498Szrj basic_block new_header;
232938fd1498Szrj if (EDGE_COUNT (cont_bb->preds) > 0)
233038fd1498Szrj {
233138fd1498Szrj gsi = gsi_last_bb (cont_bb);
233238fd1498Szrj if (POINTER_TYPE_P (type))
233338fd1498Szrj t = fold_build_pointer_plus (fd->loops[i].v,
233438fd1498Szrj fold_convert (sizetype,
233538fd1498Szrj fd->loops[i].step));
233638fd1498Szrj else
233738fd1498Szrj t = fold_build2 (PLUS_EXPR, type, fd->loops[i].v,
233838fd1498Szrj fold_convert (type, fd->loops[i].step));
233938fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v, t);
234038fd1498Szrj if (counts[i])
234138fd1498Szrj {
234238fd1498Szrj t = fold_build2 (PLUS_EXPR, fd->iter_type, counts[i],
234338fd1498Szrj build_int_cst (fd->iter_type, 1));
234438fd1498Szrj expand_omp_build_assign (&gsi, counts[i], t);
234538fd1498Szrj t = counts[i];
234638fd1498Szrj }
234738fd1498Szrj else
234838fd1498Szrj {
234938fd1498Szrj t = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[i].v),
235038fd1498Szrj fd->loops[i].v, fd->loops[i].n1);
235138fd1498Szrj t = fold_convert (fd->iter_type, t);
235238fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
235338fd1498Szrj true, GSI_SAME_STMT);
235438fd1498Szrj }
235538fd1498Szrj aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered],
235638fd1498Szrj size_int (i - fd->collapse + 1),
235738fd1498Szrj NULL_TREE, NULL_TREE);
235838fd1498Szrj expand_omp_build_assign (&gsi, aref, t);
235938fd1498Szrj gsi_prev (&gsi);
236038fd1498Szrj e2 = split_block (cont_bb, gsi_stmt (gsi));
236138fd1498Szrj new_header = e2->dest;
236238fd1498Szrj }
236338fd1498Szrj else
236438fd1498Szrj new_header = cont_bb;
236538fd1498Szrj gsi = gsi_after_labels (new_header);
236638fd1498Szrj tree v = force_gimple_operand_gsi (&gsi, fd->loops[i].v, true, NULL_TREE,
236738fd1498Szrj true, GSI_SAME_STMT);
236838fd1498Szrj tree n2
236938fd1498Szrj = force_gimple_operand_gsi (&gsi, fold_convert (type, fd->loops[i].n2),
237038fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
237138fd1498Szrj t = build2 (fd->loops[i].cond_code, boolean_type_node, v, n2);
237238fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_NEW_STMT);
237338fd1498Szrj edge e3 = split_block (new_header, gsi_stmt (gsi));
237438fd1498Szrj cont_bb = e3->dest;
237538fd1498Szrj remove_edge (e1);
237638fd1498Szrj make_edge (body_bb, new_header, EDGE_FALLTHRU);
237738fd1498Szrj e3->flags = EDGE_FALSE_VALUE;
237838fd1498Szrj e3->probability = profile_probability::guessed_always ().apply_scale (1, 8);
237938fd1498Szrj e1 = make_edge (new_header, new_body, EDGE_TRUE_VALUE);
238038fd1498Szrj e1->probability = e3->probability.invert ();
238138fd1498Szrj
238238fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, new_header, body_bb);
238338fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, new_body, new_header);
238438fd1498Szrj
238538fd1498Szrj if (e2)
238638fd1498Szrj {
238738fd1498Szrj struct loop *loop = alloc_loop ();
238838fd1498Szrj loop->header = new_header;
238938fd1498Szrj loop->latch = e2->src;
239038fd1498Szrj add_loop (loop, body_bb->loop_father);
239138fd1498Szrj }
239238fd1498Szrj }
239338fd1498Szrj
239438fd1498Szrj /* If there are any lastprivate clauses and it is possible some loops
239538fd1498Szrj might have zero iterations, ensure all the decls are initialized,
239638fd1498Szrj otherwise we could crash evaluating C++ class iterators with lastprivate
239738fd1498Szrj clauses. */
239838fd1498Szrj bool need_inits = false;
239938fd1498Szrj for (int i = fd->collapse; ordered_lastprivate && i < fd->ordered; i++)
240038fd1498Szrj if (need_inits)
240138fd1498Szrj {
240238fd1498Szrj tree type = TREE_TYPE (fd->loops[i].v);
240338fd1498Szrj gimple_stmt_iterator gsi = gsi_after_labels (body_bb);
240438fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v,
240538fd1498Szrj fold_convert (type, fd->loops[i].n1));
240638fd1498Szrj }
240738fd1498Szrj else
240838fd1498Szrj {
240938fd1498Szrj tree type = TREE_TYPE (fd->loops[i].v);
241038fd1498Szrj tree this_cond = fold_build2 (fd->loops[i].cond_code,
241138fd1498Szrj boolean_type_node,
241238fd1498Szrj fold_convert (type, fd->loops[i].n1),
241338fd1498Szrj fold_convert (type, fd->loops[i].n2));
241438fd1498Szrj if (!integer_onep (this_cond))
241538fd1498Szrj need_inits = true;
241638fd1498Szrj }
241738fd1498Szrj
241838fd1498Szrj return cont_bb;
241938fd1498Szrj }
242038fd1498Szrj
242138fd1498Szrj /* A subroutine of expand_omp_for. Generate code for a parallel
242238fd1498Szrj loop with any schedule. Given parameters:
242338fd1498Szrj
242438fd1498Szrj for (V = N1; V cond N2; V += STEP) BODY;
242538fd1498Szrj
242638fd1498Szrj where COND is "<" or ">", we generate pseudocode
242738fd1498Szrj
242838fd1498Szrj more = GOMP_loop_foo_start (N1, N2, STEP, CHUNK, &istart0, &iend0);
242938fd1498Szrj if (more) goto L0; else goto L3;
243038fd1498Szrj L0:
243138fd1498Szrj V = istart0;
243238fd1498Szrj iend = iend0;
243338fd1498Szrj L1:
243438fd1498Szrj BODY;
243538fd1498Szrj V += STEP;
243638fd1498Szrj if (V cond iend) goto L1; else goto L2;
243738fd1498Szrj L2:
243838fd1498Szrj if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
243938fd1498Szrj L3:
244038fd1498Szrj
244138fd1498Szrj If this is a combined omp parallel loop, instead of the call to
244238fd1498Szrj GOMP_loop_foo_start, we call GOMP_loop_foo_next.
244338fd1498Szrj If this is gimple_omp_for_combined_p loop, then instead of assigning
244438fd1498Szrj V and iend in L0 we assign the first two _looptemp_ clause decls of the
244538fd1498Szrj inner GIMPLE_OMP_FOR and V += STEP; and
244638fd1498Szrj if (V cond iend) goto L1; else goto L2; are removed.
244738fd1498Szrj
244838fd1498Szrj For collapsed loops, given parameters:
244938fd1498Szrj collapse(3)
245038fd1498Szrj for (V1 = N11; V1 cond1 N12; V1 += STEP1)
245138fd1498Szrj for (V2 = N21; V2 cond2 N22; V2 += STEP2)
245238fd1498Szrj for (V3 = N31; V3 cond3 N32; V3 += STEP3)
245338fd1498Szrj BODY;
245438fd1498Szrj
245538fd1498Szrj we generate pseudocode
245638fd1498Szrj
245738fd1498Szrj if (__builtin_expect (N32 cond3 N31, 0)) goto Z0;
245838fd1498Szrj if (cond3 is <)
245938fd1498Szrj adj = STEP3 - 1;
246038fd1498Szrj else
246138fd1498Szrj adj = STEP3 + 1;
246238fd1498Szrj count3 = (adj + N32 - N31) / STEP3;
246338fd1498Szrj if (__builtin_expect (N22 cond2 N21, 0)) goto Z0;
246438fd1498Szrj if (cond2 is <)
246538fd1498Szrj adj = STEP2 - 1;
246638fd1498Szrj else
246738fd1498Szrj adj = STEP2 + 1;
246838fd1498Szrj count2 = (adj + N22 - N21) / STEP2;
246938fd1498Szrj if (__builtin_expect (N12 cond1 N11, 0)) goto Z0;
247038fd1498Szrj if (cond1 is <)
247138fd1498Szrj adj = STEP1 - 1;
247238fd1498Szrj else
247338fd1498Szrj adj = STEP1 + 1;
247438fd1498Szrj count1 = (adj + N12 - N11) / STEP1;
247538fd1498Szrj count = count1 * count2 * count3;
247638fd1498Szrj goto Z1;
247738fd1498Szrj Z0:
247838fd1498Szrj count = 0;
247938fd1498Szrj Z1:
248038fd1498Szrj more = GOMP_loop_foo_start (0, count, 1, CHUNK, &istart0, &iend0);
248138fd1498Szrj if (more) goto L0; else goto L3;
248238fd1498Szrj L0:
248338fd1498Szrj V = istart0;
248438fd1498Szrj T = V;
248538fd1498Szrj V3 = N31 + (T % count3) * STEP3;
248638fd1498Szrj T = T / count3;
248738fd1498Szrj V2 = N21 + (T % count2) * STEP2;
248838fd1498Szrj T = T / count2;
248938fd1498Szrj V1 = N11 + T * STEP1;
249038fd1498Szrj iend = iend0;
249138fd1498Szrj L1:
249238fd1498Szrj BODY;
249338fd1498Szrj V += 1;
249438fd1498Szrj if (V < iend) goto L10; else goto L2;
249538fd1498Szrj L10:
249638fd1498Szrj V3 += STEP3;
249738fd1498Szrj if (V3 cond3 N32) goto L1; else goto L11;
249838fd1498Szrj L11:
249938fd1498Szrj V3 = N31;
250038fd1498Szrj V2 += STEP2;
250138fd1498Szrj if (V2 cond2 N22) goto L1; else goto L12;
250238fd1498Szrj L12:
250338fd1498Szrj V2 = N21;
250438fd1498Szrj V1 += STEP1;
250538fd1498Szrj goto L1;
250638fd1498Szrj L2:
250738fd1498Szrj if (GOMP_loop_foo_next (&istart0, &iend0)) goto L0; else goto L3;
250838fd1498Szrj L3:
250938fd1498Szrj
251038fd1498Szrj */
251138fd1498Szrj
251238fd1498Szrj static void
expand_omp_for_generic(struct omp_region * region,struct omp_for_data * fd,enum built_in_function start_fn,enum built_in_function next_fn,gimple * inner_stmt)251338fd1498Szrj expand_omp_for_generic (struct omp_region *region,
251438fd1498Szrj struct omp_for_data *fd,
251538fd1498Szrj enum built_in_function start_fn,
251638fd1498Szrj enum built_in_function next_fn,
251738fd1498Szrj gimple *inner_stmt)
251838fd1498Szrj {
251938fd1498Szrj tree type, istart0, iend0, iend;
252038fd1498Szrj tree t, vmain, vback, bias = NULL_TREE;
252138fd1498Szrj basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, collapse_bb;
252238fd1498Szrj basic_block l2_bb = NULL, l3_bb = NULL;
252338fd1498Szrj gimple_stmt_iterator gsi;
252438fd1498Szrj gassign *assign_stmt;
252538fd1498Szrj bool in_combined_parallel = is_combined_parallel (region);
252638fd1498Szrj bool broken_loop = region->cont == NULL;
252738fd1498Szrj edge e, ne;
252838fd1498Szrj tree *counts = NULL;
252938fd1498Szrj int i;
253038fd1498Szrj bool ordered_lastprivate = false;
253138fd1498Szrj
253238fd1498Szrj gcc_assert (!broken_loop || !in_combined_parallel);
253338fd1498Szrj gcc_assert (fd->iter_type == long_integer_type_node
253438fd1498Szrj || !in_combined_parallel);
253538fd1498Szrj
253638fd1498Szrj entry_bb = region->entry;
253738fd1498Szrj cont_bb = region->cont;
253838fd1498Szrj collapse_bb = NULL;
253938fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
254038fd1498Szrj gcc_assert (broken_loop
254138fd1498Szrj || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
254238fd1498Szrj l0_bb = split_edge (FALLTHRU_EDGE (entry_bb));
254338fd1498Szrj l1_bb = single_succ (l0_bb);
254438fd1498Szrj if (!broken_loop)
254538fd1498Szrj {
254638fd1498Szrj l2_bb = create_empty_bb (cont_bb);
254738fd1498Szrj gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb
254838fd1498Szrj || (single_succ_edge (BRANCH_EDGE (cont_bb)->dest)->dest
254938fd1498Szrj == l1_bb));
255038fd1498Szrj gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
255138fd1498Szrj }
255238fd1498Szrj else
255338fd1498Szrj l2_bb = NULL;
255438fd1498Szrj l3_bb = BRANCH_EDGE (entry_bb)->dest;
255538fd1498Szrj exit_bb = region->exit;
255638fd1498Szrj
255738fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
255838fd1498Szrj
255938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
256038fd1498Szrj if (fd->ordered
256138fd1498Szrj && omp_find_clause (gimple_omp_for_clauses (gsi_stmt (gsi)),
256238fd1498Szrj OMP_CLAUSE_LASTPRIVATE))
256338fd1498Szrj ordered_lastprivate = false;
256438fd1498Szrj if (fd->collapse > 1 || fd->ordered)
256538fd1498Szrj {
256638fd1498Szrj int first_zero_iter1 = -1, first_zero_iter2 = -1;
256738fd1498Szrj basic_block zero_iter1_bb = NULL, zero_iter2_bb = NULL, l2_dom_bb = NULL;
256838fd1498Szrj
256938fd1498Szrj counts = XALLOCAVEC (tree, fd->ordered ? fd->ordered + 1 : fd->collapse);
257038fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
257138fd1498Szrj zero_iter1_bb, first_zero_iter1,
257238fd1498Szrj zero_iter2_bb, first_zero_iter2, l2_dom_bb);
257338fd1498Szrj
257438fd1498Szrj if (zero_iter1_bb)
257538fd1498Szrj {
257638fd1498Szrj /* Some counts[i] vars might be uninitialized if
257738fd1498Szrj some loop has zero iterations. But the body shouldn't
257838fd1498Szrj be executed in that case, so just avoid uninit warnings. */
257938fd1498Szrj for (i = first_zero_iter1;
258038fd1498Szrj i < (fd->ordered ? fd->ordered : fd->collapse); i++)
258138fd1498Szrj if (SSA_VAR_P (counts[i]))
258238fd1498Szrj TREE_NO_WARNING (counts[i]) = 1;
258338fd1498Szrj gsi_prev (&gsi);
258438fd1498Szrj e = split_block (entry_bb, gsi_stmt (gsi));
258538fd1498Szrj entry_bb = e->dest;
258638fd1498Szrj make_edge (zero_iter1_bb, entry_bb, EDGE_FALLTHRU);
258738fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
258838fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, entry_bb,
258938fd1498Szrj get_immediate_dominator (CDI_DOMINATORS,
259038fd1498Szrj zero_iter1_bb));
259138fd1498Szrj }
259238fd1498Szrj if (zero_iter2_bb)
259338fd1498Szrj {
259438fd1498Szrj /* Some counts[i] vars might be uninitialized if
259538fd1498Szrj some loop has zero iterations. But the body shouldn't
259638fd1498Szrj be executed in that case, so just avoid uninit warnings. */
259738fd1498Szrj for (i = first_zero_iter2; i < fd->ordered; i++)
259838fd1498Szrj if (SSA_VAR_P (counts[i]))
259938fd1498Szrj TREE_NO_WARNING (counts[i]) = 1;
260038fd1498Szrj if (zero_iter1_bb)
260138fd1498Szrj make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU);
260238fd1498Szrj else
260338fd1498Szrj {
260438fd1498Szrj gsi_prev (&gsi);
260538fd1498Szrj e = split_block (entry_bb, gsi_stmt (gsi));
260638fd1498Szrj entry_bb = e->dest;
260738fd1498Szrj make_edge (zero_iter2_bb, entry_bb, EDGE_FALLTHRU);
260838fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
260938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, entry_bb,
261038fd1498Szrj get_immediate_dominator
261138fd1498Szrj (CDI_DOMINATORS, zero_iter2_bb));
261238fd1498Szrj }
261338fd1498Szrj }
261438fd1498Szrj if (fd->collapse == 1)
261538fd1498Szrj {
261638fd1498Szrj counts[0] = fd->loop.n2;
261738fd1498Szrj fd->loop = fd->loops[0];
261838fd1498Szrj }
261938fd1498Szrj }
262038fd1498Szrj
262138fd1498Szrj type = TREE_TYPE (fd->loop.v);
262238fd1498Szrj istart0 = create_tmp_var (fd->iter_type, ".istart0");
262338fd1498Szrj iend0 = create_tmp_var (fd->iter_type, ".iend0");
262438fd1498Szrj TREE_ADDRESSABLE (istart0) = 1;
262538fd1498Szrj TREE_ADDRESSABLE (iend0) = 1;
262638fd1498Szrj
262738fd1498Szrj /* See if we need to bias by LLONG_MIN. */
262838fd1498Szrj if (fd->iter_type == long_long_unsigned_type_node
262938fd1498Szrj && TREE_CODE (type) == INTEGER_TYPE
263038fd1498Szrj && !TYPE_UNSIGNED (type)
263138fd1498Szrj && fd->ordered == 0)
263238fd1498Szrj {
263338fd1498Szrj tree n1, n2;
263438fd1498Szrj
263538fd1498Szrj if (fd->loop.cond_code == LT_EXPR)
263638fd1498Szrj {
263738fd1498Szrj n1 = fd->loop.n1;
263838fd1498Szrj n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
263938fd1498Szrj }
264038fd1498Szrj else
264138fd1498Szrj {
264238fd1498Szrj n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
264338fd1498Szrj n2 = fd->loop.n1;
264438fd1498Szrj }
264538fd1498Szrj if (TREE_CODE (n1) != INTEGER_CST
264638fd1498Szrj || TREE_CODE (n2) != INTEGER_CST
264738fd1498Szrj || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
264838fd1498Szrj bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
264938fd1498Szrj }
265038fd1498Szrj
265138fd1498Szrj gimple_stmt_iterator gsif = gsi;
265238fd1498Szrj gsi_prev (&gsif);
265338fd1498Szrj
265438fd1498Szrj tree arr = NULL_TREE;
265538fd1498Szrj if (in_combined_parallel)
265638fd1498Szrj {
265738fd1498Szrj gcc_assert (fd->ordered == 0);
265838fd1498Szrj /* In a combined parallel loop, emit a call to
265938fd1498Szrj GOMP_loop_foo_next. */
266038fd1498Szrj t = build_call_expr (builtin_decl_explicit (next_fn), 2,
266138fd1498Szrj build_fold_addr_expr (istart0),
266238fd1498Szrj build_fold_addr_expr (iend0));
266338fd1498Szrj }
266438fd1498Szrj else
266538fd1498Szrj {
266638fd1498Szrj tree t0, t1, t2, t3, t4;
266738fd1498Szrj /* If this is not a combined parallel loop, emit a call to
266838fd1498Szrj GOMP_loop_foo_start in ENTRY_BB. */
266938fd1498Szrj t4 = build_fold_addr_expr (iend0);
267038fd1498Szrj t3 = build_fold_addr_expr (istart0);
267138fd1498Szrj if (fd->ordered)
267238fd1498Szrj {
267338fd1498Szrj t0 = build_int_cst (unsigned_type_node,
267438fd1498Szrj fd->ordered - fd->collapse + 1);
267538fd1498Szrj arr = create_tmp_var (build_array_type_nelts (fd->iter_type,
267638fd1498Szrj fd->ordered
267738fd1498Szrj - fd->collapse + 1),
267838fd1498Szrj ".omp_counts");
267938fd1498Szrj DECL_NAMELESS (arr) = 1;
268038fd1498Szrj TREE_ADDRESSABLE (arr) = 1;
268138fd1498Szrj TREE_STATIC (arr) = 1;
268238fd1498Szrj vec<constructor_elt, va_gc> *v;
268338fd1498Szrj vec_alloc (v, fd->ordered - fd->collapse + 1);
268438fd1498Szrj int idx;
268538fd1498Szrj
268638fd1498Szrj for (idx = 0; idx < fd->ordered - fd->collapse + 1; idx++)
268738fd1498Szrj {
268838fd1498Szrj tree c;
268938fd1498Szrj if (idx == 0 && fd->collapse > 1)
269038fd1498Szrj c = fd->loop.n2;
269138fd1498Szrj else
269238fd1498Szrj c = counts[idx + fd->collapse - 1];
269338fd1498Szrj tree purpose = size_int (idx);
269438fd1498Szrj CONSTRUCTOR_APPEND_ELT (v, purpose, c);
269538fd1498Szrj if (TREE_CODE (c) != INTEGER_CST)
269638fd1498Szrj TREE_STATIC (arr) = 0;
269738fd1498Szrj }
269838fd1498Szrj
269938fd1498Szrj DECL_INITIAL (arr) = build_constructor (TREE_TYPE (arr), v);
270038fd1498Szrj if (!TREE_STATIC (arr))
270138fd1498Szrj force_gimple_operand_gsi (&gsi, build1 (DECL_EXPR,
270238fd1498Szrj void_type_node, arr),
270338fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
270438fd1498Szrj t1 = build_fold_addr_expr (arr);
270538fd1498Szrj t2 = NULL_TREE;
270638fd1498Szrj }
270738fd1498Szrj else
270838fd1498Szrj {
270938fd1498Szrj t2 = fold_convert (fd->iter_type, fd->loop.step);
271038fd1498Szrj t1 = fd->loop.n2;
271138fd1498Szrj t0 = fd->loop.n1;
271238fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
271338fd1498Szrj {
271438fd1498Szrj tree innerc
271538fd1498Szrj = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
271638fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
271738fd1498Szrj gcc_assert (innerc);
271838fd1498Szrj t0 = OMP_CLAUSE_DECL (innerc);
271938fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
272038fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
272138fd1498Szrj gcc_assert (innerc);
272238fd1498Szrj t1 = OMP_CLAUSE_DECL (innerc);
272338fd1498Szrj }
272438fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (t0))
272538fd1498Szrj && TYPE_PRECISION (TREE_TYPE (t0))
272638fd1498Szrj != TYPE_PRECISION (fd->iter_type))
272738fd1498Szrj {
272838fd1498Szrj /* Avoid casting pointers to integer of a different size. */
272938fd1498Szrj tree itype = signed_type_for (type);
273038fd1498Szrj t1 = fold_convert (fd->iter_type, fold_convert (itype, t1));
273138fd1498Szrj t0 = fold_convert (fd->iter_type, fold_convert (itype, t0));
273238fd1498Szrj }
273338fd1498Szrj else
273438fd1498Szrj {
273538fd1498Szrj t1 = fold_convert (fd->iter_type, t1);
273638fd1498Szrj t0 = fold_convert (fd->iter_type, t0);
273738fd1498Szrj }
273838fd1498Szrj if (bias)
273938fd1498Szrj {
274038fd1498Szrj t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
274138fd1498Szrj t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
274238fd1498Szrj }
274338fd1498Szrj }
274438fd1498Szrj if (fd->iter_type == long_integer_type_node || fd->ordered)
274538fd1498Szrj {
274638fd1498Szrj if (fd->chunk_size)
274738fd1498Szrj {
274838fd1498Szrj t = fold_convert (fd->iter_type, fd->chunk_size);
274938fd1498Szrj t = omp_adjust_chunk_size (t, fd->simd_schedule);
275038fd1498Szrj if (fd->ordered)
275138fd1498Szrj t = build_call_expr (builtin_decl_explicit (start_fn),
275238fd1498Szrj 5, t0, t1, t, t3, t4);
275338fd1498Szrj else
275438fd1498Szrj t = build_call_expr (builtin_decl_explicit (start_fn),
275538fd1498Szrj 6, t0, t1, t2, t, t3, t4);
275638fd1498Szrj }
275738fd1498Szrj else if (fd->ordered)
275838fd1498Szrj t = build_call_expr (builtin_decl_explicit (start_fn),
275938fd1498Szrj 4, t0, t1, t3, t4);
276038fd1498Szrj else
276138fd1498Szrj t = build_call_expr (builtin_decl_explicit (start_fn),
276238fd1498Szrj 5, t0, t1, t2, t3, t4);
276338fd1498Szrj }
276438fd1498Szrj else
276538fd1498Szrj {
276638fd1498Szrj tree t5;
276738fd1498Szrj tree c_bool_type;
276838fd1498Szrj tree bfn_decl;
276938fd1498Szrj
277038fd1498Szrj /* The GOMP_loop_ull_*start functions have additional boolean
277138fd1498Szrj argument, true for < loops and false for > loops.
277238fd1498Szrj In Fortran, the C bool type can be different from
277338fd1498Szrj boolean_type_node. */
277438fd1498Szrj bfn_decl = builtin_decl_explicit (start_fn);
277538fd1498Szrj c_bool_type = TREE_TYPE (TREE_TYPE (bfn_decl));
277638fd1498Szrj t5 = build_int_cst (c_bool_type,
277738fd1498Szrj fd->loop.cond_code == LT_EXPR ? 1 : 0);
277838fd1498Szrj if (fd->chunk_size)
277938fd1498Szrj {
278038fd1498Szrj tree bfn_decl = builtin_decl_explicit (start_fn);
278138fd1498Szrj t = fold_convert (fd->iter_type, fd->chunk_size);
278238fd1498Szrj t = omp_adjust_chunk_size (t, fd->simd_schedule);
278338fd1498Szrj t = build_call_expr (bfn_decl, 7, t5, t0, t1, t2, t, t3, t4);
278438fd1498Szrj }
278538fd1498Szrj else
278638fd1498Szrj t = build_call_expr (builtin_decl_explicit (start_fn),
278738fd1498Szrj 6, t5, t0, t1, t2, t3, t4);
278838fd1498Szrj }
278938fd1498Szrj }
279038fd1498Szrj if (TREE_TYPE (t) != boolean_type_node)
279138fd1498Szrj t = fold_build2 (NE_EXPR, boolean_type_node,
279238fd1498Szrj t, build_int_cst (TREE_TYPE (t), 0));
279338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
279438fd1498Szrj true, GSI_SAME_STMT);
279538fd1498Szrj if (arr && !TREE_STATIC (arr))
279638fd1498Szrj {
279738fd1498Szrj tree clobber = build_constructor (TREE_TYPE (arr), NULL);
279838fd1498Szrj TREE_THIS_VOLATILE (clobber) = 1;
279938fd1498Szrj gsi_insert_before (&gsi, gimple_build_assign (arr, clobber),
280038fd1498Szrj GSI_SAME_STMT);
280138fd1498Szrj }
280238fd1498Szrj gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
280338fd1498Szrj
280438fd1498Szrj /* Remove the GIMPLE_OMP_FOR statement. */
280538fd1498Szrj gsi_remove (&gsi, true);
280638fd1498Szrj
280738fd1498Szrj if (gsi_end_p (gsif))
280838fd1498Szrj gsif = gsi_after_labels (gsi_bb (gsif));
280938fd1498Szrj gsi_next (&gsif);
281038fd1498Szrj
281138fd1498Szrj /* Iteration setup for sequential loop goes in L0_BB. */
281238fd1498Szrj tree startvar = fd->loop.v;
281338fd1498Szrj tree endvar = NULL_TREE;
281438fd1498Szrj
281538fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
281638fd1498Szrj {
281738fd1498Szrj gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_FOR
281838fd1498Szrj && gimple_omp_for_kind (inner_stmt)
281938fd1498Szrj == GF_OMP_FOR_KIND_SIMD);
282038fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (inner_stmt),
282138fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
282238fd1498Szrj gcc_assert (innerc);
282338fd1498Szrj startvar = OMP_CLAUSE_DECL (innerc);
282438fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
282538fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
282638fd1498Szrj gcc_assert (innerc);
282738fd1498Szrj endvar = OMP_CLAUSE_DECL (innerc);
282838fd1498Szrj }
282938fd1498Szrj
283038fd1498Szrj gsi = gsi_start_bb (l0_bb);
283138fd1498Szrj t = istart0;
283238fd1498Szrj if (fd->ordered && fd->collapse == 1)
283338fd1498Szrj t = fold_build2 (MULT_EXPR, fd->iter_type, t,
283438fd1498Szrj fold_convert (fd->iter_type, fd->loop.step));
283538fd1498Szrj else if (bias)
283638fd1498Szrj t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias);
283738fd1498Szrj if (fd->ordered && fd->collapse == 1)
283838fd1498Szrj {
283938fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (startvar)))
284038fd1498Szrj t = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (startvar),
284138fd1498Szrj fd->loop.n1, fold_convert (sizetype, t));
284238fd1498Szrj else
284338fd1498Szrj {
284438fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
284538fd1498Szrj t = fold_build2 (PLUS_EXPR, TREE_TYPE (startvar),
284638fd1498Szrj fd->loop.n1, t);
284738fd1498Szrj }
284838fd1498Szrj }
284938fd1498Szrj else
285038fd1498Szrj {
285138fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (startvar)))
285238fd1498Szrj t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t);
285338fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
285438fd1498Szrj }
285538fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
285638fd1498Szrj DECL_P (startvar)
285738fd1498Szrj && TREE_ADDRESSABLE (startvar),
285838fd1498Szrj NULL_TREE, false, GSI_CONTINUE_LINKING);
285938fd1498Szrj assign_stmt = gimple_build_assign (startvar, t);
286038fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
286138fd1498Szrj
286238fd1498Szrj t = iend0;
286338fd1498Szrj if (fd->ordered && fd->collapse == 1)
286438fd1498Szrj t = fold_build2 (MULT_EXPR, fd->iter_type, t,
286538fd1498Szrj fold_convert (fd->iter_type, fd->loop.step));
286638fd1498Szrj else if (bias)
286738fd1498Szrj t = fold_build2 (MINUS_EXPR, fd->iter_type, t, bias);
286838fd1498Szrj if (fd->ordered && fd->collapse == 1)
286938fd1498Szrj {
287038fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (startvar)))
287138fd1498Szrj t = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (startvar),
287238fd1498Szrj fd->loop.n1, fold_convert (sizetype, t));
287338fd1498Szrj else
287438fd1498Szrj {
287538fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
287638fd1498Szrj t = fold_build2 (PLUS_EXPR, TREE_TYPE (startvar),
287738fd1498Szrj fd->loop.n1, t);
287838fd1498Szrj }
287938fd1498Szrj }
288038fd1498Szrj else
288138fd1498Szrj {
288238fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (startvar)))
288338fd1498Szrj t = fold_convert (signed_type_for (TREE_TYPE (startvar)), t);
288438fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
288538fd1498Szrj }
288638fd1498Szrj iend = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
288738fd1498Szrj false, GSI_CONTINUE_LINKING);
288838fd1498Szrj if (endvar)
288938fd1498Szrj {
289038fd1498Szrj assign_stmt = gimple_build_assign (endvar, iend);
289138fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
289238fd1498Szrj if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (iend)))
289338fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, iend);
289438fd1498Szrj else
289538fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, iend);
289638fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
289738fd1498Szrj }
289838fd1498Szrj /* Handle linear clause adjustments. */
289938fd1498Szrj tree itercnt = NULL_TREE;
290038fd1498Szrj if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR)
290138fd1498Szrj for (tree c = gimple_omp_for_clauses (fd->for_stmt);
290238fd1498Szrj c; c = OMP_CLAUSE_CHAIN (c))
290338fd1498Szrj if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
290438fd1498Szrj && !OMP_CLAUSE_LINEAR_NO_COPYIN (c))
290538fd1498Szrj {
290638fd1498Szrj tree d = OMP_CLAUSE_DECL (c);
290738fd1498Szrj bool is_ref = omp_is_reference (d);
290838fd1498Szrj tree t = d, a, dest;
290938fd1498Szrj if (is_ref)
291038fd1498Szrj t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t);
291138fd1498Szrj tree type = TREE_TYPE (t);
291238fd1498Szrj if (POINTER_TYPE_P (type))
291338fd1498Szrj type = sizetype;
291438fd1498Szrj dest = unshare_expr (t);
291538fd1498Szrj tree v = create_tmp_var (TREE_TYPE (t), NULL);
291638fd1498Szrj expand_omp_build_assign (&gsif, v, t);
291738fd1498Szrj if (itercnt == NULL_TREE)
291838fd1498Szrj {
291938fd1498Szrj itercnt = startvar;
292038fd1498Szrj tree n1 = fd->loop.n1;
292138fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (itercnt)))
292238fd1498Szrj {
292338fd1498Szrj itercnt
292438fd1498Szrj = fold_convert (signed_type_for (TREE_TYPE (itercnt)),
292538fd1498Szrj itercnt);
292638fd1498Szrj n1 = fold_convert (TREE_TYPE (itercnt), n1);
292738fd1498Szrj }
292838fd1498Szrj itercnt = fold_build2 (MINUS_EXPR, TREE_TYPE (itercnt),
292938fd1498Szrj itercnt, n1);
293038fd1498Szrj itercnt = fold_build2 (EXACT_DIV_EXPR, TREE_TYPE (itercnt),
293138fd1498Szrj itercnt, fd->loop.step);
293238fd1498Szrj itercnt = force_gimple_operand_gsi (&gsi, itercnt, true,
293338fd1498Szrj NULL_TREE, false,
293438fd1498Szrj GSI_CONTINUE_LINKING);
293538fd1498Szrj }
293638fd1498Szrj a = fold_build2 (MULT_EXPR, type,
293738fd1498Szrj fold_convert (type, itercnt),
293838fd1498Szrj fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c)));
293938fd1498Szrj t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR
294038fd1498Szrj : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a);
294138fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
294238fd1498Szrj false, GSI_CONTINUE_LINKING);
294338fd1498Szrj assign_stmt = gimple_build_assign (dest, t);
294438fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
294538fd1498Szrj }
294638fd1498Szrj if (fd->collapse > 1)
294738fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
294838fd1498Szrj
294938fd1498Szrj if (fd->ordered)
295038fd1498Szrj {
295138fd1498Szrj /* Until now, counts array contained number of iterations or
295238fd1498Szrj variable containing it for ith loop. From now on, we need
295338fd1498Szrj those counts only for collapsed loops, and only for the 2nd
295438fd1498Szrj till the last collapsed one. Move those one element earlier,
295538fd1498Szrj we'll use counts[fd->collapse - 1] for the first source/sink
295638fd1498Szrj iteration counter and so on and counts[fd->ordered]
295738fd1498Szrj as the array holding the current counter values for
295838fd1498Szrj depend(source). */
295938fd1498Szrj if (fd->collapse > 1)
296038fd1498Szrj memmove (counts, counts + 1, (fd->collapse - 1) * sizeof (counts[0]));
296138fd1498Szrj if (broken_loop)
296238fd1498Szrj {
296338fd1498Szrj int i;
296438fd1498Szrj for (i = fd->collapse; i < fd->ordered; i++)
296538fd1498Szrj {
296638fd1498Szrj tree type = TREE_TYPE (fd->loops[i].v);
296738fd1498Szrj tree this_cond
296838fd1498Szrj = fold_build2 (fd->loops[i].cond_code, boolean_type_node,
296938fd1498Szrj fold_convert (type, fd->loops[i].n1),
297038fd1498Szrj fold_convert (type, fd->loops[i].n2));
297138fd1498Szrj if (!integer_onep (this_cond))
297238fd1498Szrj break;
297338fd1498Szrj }
297438fd1498Szrj if (i < fd->ordered)
297538fd1498Szrj {
297638fd1498Szrj cont_bb
297738fd1498Szrj = create_empty_bb (EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb);
297838fd1498Szrj add_bb_to_loop (cont_bb, l1_bb->loop_father);
297938fd1498Szrj gimple_stmt_iterator gsi = gsi_after_labels (cont_bb);
298038fd1498Szrj gimple *g = gimple_build_omp_continue (fd->loop.v, fd->loop.v);
298138fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
298238fd1498Szrj make_edge (cont_bb, l3_bb, EDGE_FALLTHRU);
298338fd1498Szrj make_edge (cont_bb, l1_bb, 0);
298438fd1498Szrj l2_bb = create_empty_bb (cont_bb);
298538fd1498Szrj broken_loop = false;
298638fd1498Szrj }
298738fd1498Szrj }
298838fd1498Szrj expand_omp_ordered_source_sink (region, fd, counts, cont_bb);
298938fd1498Szrj cont_bb = expand_omp_for_ordered_loops (fd, counts, cont_bb, l1_bb,
299038fd1498Szrj ordered_lastprivate);
299138fd1498Szrj if (counts[fd->collapse - 1])
299238fd1498Szrj {
299338fd1498Szrj gcc_assert (fd->collapse == 1);
299438fd1498Szrj gsi = gsi_last_bb (l0_bb);
299538fd1498Szrj expand_omp_build_assign (&gsi, counts[fd->collapse - 1],
299638fd1498Szrj istart0, true);
299738fd1498Szrj gsi = gsi_last_bb (cont_bb);
299838fd1498Szrj t = fold_build2 (PLUS_EXPR, fd->iter_type, counts[fd->collapse - 1],
299938fd1498Szrj build_int_cst (fd->iter_type, 1));
300038fd1498Szrj expand_omp_build_assign (&gsi, counts[fd->collapse - 1], t);
300138fd1498Szrj tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered],
300238fd1498Szrj size_zero_node, NULL_TREE, NULL_TREE);
300338fd1498Szrj expand_omp_build_assign (&gsi, aref, counts[fd->collapse - 1]);
300438fd1498Szrj t = counts[fd->collapse - 1];
300538fd1498Szrj }
300638fd1498Szrj else if (fd->collapse > 1)
300738fd1498Szrj t = fd->loop.v;
300838fd1498Szrj else
300938fd1498Szrj {
301038fd1498Szrj t = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[0].v),
301138fd1498Szrj fd->loops[0].v, fd->loops[0].n1);
301238fd1498Szrj t = fold_convert (fd->iter_type, t);
301338fd1498Szrj }
301438fd1498Szrj gsi = gsi_last_bb (l0_bb);
301538fd1498Szrj tree aref = build4 (ARRAY_REF, fd->iter_type, counts[fd->ordered],
301638fd1498Szrj size_zero_node, NULL_TREE, NULL_TREE);
301738fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
301838fd1498Szrj false, GSI_CONTINUE_LINKING);
301938fd1498Szrj expand_omp_build_assign (&gsi, aref, t, true);
302038fd1498Szrj }
302138fd1498Szrj
302238fd1498Szrj if (!broken_loop)
302338fd1498Szrj {
302438fd1498Szrj /* Code to control the increment and predicate for the sequential
302538fd1498Szrj loop goes in the CONT_BB. */
302638fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
302738fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
302838fd1498Szrj gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
302938fd1498Szrj vmain = gimple_omp_continue_control_use (cont_stmt);
303038fd1498Szrj vback = gimple_omp_continue_control_def (cont_stmt);
303138fd1498Szrj
303238fd1498Szrj if (!gimple_omp_for_combined_p (fd->for_stmt))
303338fd1498Szrj {
303438fd1498Szrj if (POINTER_TYPE_P (type))
303538fd1498Szrj t = fold_build_pointer_plus (vmain, fd->loop.step);
303638fd1498Szrj else
303738fd1498Szrj t = fold_build2 (PLUS_EXPR, type, vmain, fd->loop.step);
303838fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
303938fd1498Szrj DECL_P (vback)
304038fd1498Szrj && TREE_ADDRESSABLE (vback),
304138fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
304238fd1498Szrj assign_stmt = gimple_build_assign (vback, t);
304338fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
304438fd1498Szrj
304538fd1498Szrj if (fd->ordered && counts[fd->collapse - 1] == NULL_TREE)
304638fd1498Szrj {
3047*58e805e6Szrj tree tem;
304838fd1498Szrj if (fd->collapse > 1)
3049*58e805e6Szrj tem = fd->loop.v;
305038fd1498Szrj else
305138fd1498Szrj {
3052*58e805e6Szrj tem = fold_build2 (MINUS_EXPR, TREE_TYPE (fd->loops[0].v),
305338fd1498Szrj fd->loops[0].v, fd->loops[0].n1);
3054*58e805e6Szrj tem = fold_convert (fd->iter_type, tem);
305538fd1498Szrj }
305638fd1498Szrj tree aref = build4 (ARRAY_REF, fd->iter_type,
305738fd1498Szrj counts[fd->ordered], size_zero_node,
305838fd1498Szrj NULL_TREE, NULL_TREE);
3059*58e805e6Szrj tem = force_gimple_operand_gsi (&gsi, tem, true, NULL_TREE,
306038fd1498Szrj true, GSI_SAME_STMT);
3061*58e805e6Szrj expand_omp_build_assign (&gsi, aref, tem);
306238fd1498Szrj }
306338fd1498Szrj
306438fd1498Szrj t = build2 (fd->loop.cond_code, boolean_type_node,
306538fd1498Szrj DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback,
306638fd1498Szrj iend);
306738fd1498Szrj gcond *cond_stmt = gimple_build_cond_empty (t);
306838fd1498Szrj gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
306938fd1498Szrj }
307038fd1498Szrj
307138fd1498Szrj /* Remove GIMPLE_OMP_CONTINUE. */
307238fd1498Szrj gsi_remove (&gsi, true);
307338fd1498Szrj
307438fd1498Szrj if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
307538fd1498Szrj collapse_bb = extract_omp_for_update_vars (fd, cont_bb, l1_bb);
307638fd1498Szrj
307738fd1498Szrj /* Emit code to get the next parallel iteration in L2_BB. */
307838fd1498Szrj gsi = gsi_start_bb (l2_bb);
307938fd1498Szrj
308038fd1498Szrj t = build_call_expr (builtin_decl_explicit (next_fn), 2,
308138fd1498Szrj build_fold_addr_expr (istart0),
308238fd1498Szrj build_fold_addr_expr (iend0));
308338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
308438fd1498Szrj false, GSI_CONTINUE_LINKING);
308538fd1498Szrj if (TREE_TYPE (t) != boolean_type_node)
308638fd1498Szrj t = fold_build2 (NE_EXPR, boolean_type_node,
308738fd1498Szrj t, build_int_cst (TREE_TYPE (t), 0));
308838fd1498Szrj gcond *cond_stmt = gimple_build_cond_empty (t);
308938fd1498Szrj gsi_insert_after (&gsi, cond_stmt, GSI_CONTINUE_LINKING);
309038fd1498Szrj }
309138fd1498Szrj
309238fd1498Szrj /* Add the loop cleanup function. */
309338fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
309438fd1498Szrj if (gimple_omp_return_nowait_p (gsi_stmt (gsi)))
309538fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_NOWAIT);
309638fd1498Szrj else if (gimple_omp_return_lhs (gsi_stmt (gsi)))
309738fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END_CANCEL);
309838fd1498Szrj else
309938fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_LOOP_END);
310038fd1498Szrj gcall *call_stmt = gimple_build_call (t, 0);
310138fd1498Szrj if (gimple_omp_return_lhs (gsi_stmt (gsi)))
310238fd1498Szrj gimple_call_set_lhs (call_stmt, gimple_omp_return_lhs (gsi_stmt (gsi)));
310338fd1498Szrj gsi_insert_after (&gsi, call_stmt, GSI_SAME_STMT);
310438fd1498Szrj if (fd->ordered)
310538fd1498Szrj {
310638fd1498Szrj tree arr = counts[fd->ordered];
310738fd1498Szrj tree clobber = build_constructor (TREE_TYPE (arr), NULL);
310838fd1498Szrj TREE_THIS_VOLATILE (clobber) = 1;
310938fd1498Szrj gsi_insert_after (&gsi, gimple_build_assign (arr, clobber),
311038fd1498Szrj GSI_SAME_STMT);
311138fd1498Szrj }
311238fd1498Szrj gsi_remove (&gsi, true);
311338fd1498Szrj
311438fd1498Szrj /* Connect the new blocks. */
311538fd1498Szrj find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
311638fd1498Szrj find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
311738fd1498Szrj
311838fd1498Szrj if (!broken_loop)
311938fd1498Szrj {
312038fd1498Szrj gimple_seq phis;
312138fd1498Szrj
312238fd1498Szrj e = find_edge (cont_bb, l3_bb);
312338fd1498Szrj ne = make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
312438fd1498Szrj
312538fd1498Szrj phis = phi_nodes (l3_bb);
312638fd1498Szrj for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
312738fd1498Szrj {
312838fd1498Szrj gimple *phi = gsi_stmt (gsi);
312938fd1498Szrj SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, ne),
313038fd1498Szrj PHI_ARG_DEF_FROM_EDGE (phi, e));
313138fd1498Szrj }
313238fd1498Szrj remove_edge (e);
313338fd1498Szrj
313438fd1498Szrj make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
313538fd1498Szrj e = find_edge (cont_bb, l1_bb);
313638fd1498Szrj if (e == NULL)
313738fd1498Szrj {
313838fd1498Szrj e = BRANCH_EDGE (cont_bb);
313938fd1498Szrj gcc_assert (single_succ (e->dest) == l1_bb);
314038fd1498Szrj }
314138fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
314238fd1498Szrj {
314338fd1498Szrj remove_edge (e);
314438fd1498Szrj e = NULL;
314538fd1498Szrj }
314638fd1498Szrj else if (fd->collapse > 1)
314738fd1498Szrj {
314838fd1498Szrj remove_edge (e);
314938fd1498Szrj e = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
315038fd1498Szrj }
315138fd1498Szrj else
315238fd1498Szrj e->flags = EDGE_TRUE_VALUE;
315338fd1498Szrj if (e)
315438fd1498Szrj {
315538fd1498Szrj e->probability = profile_probability::guessed_always ().apply_scale (7, 8);
315638fd1498Szrj find_edge (cont_bb, l2_bb)->probability = e->probability.invert ();
315738fd1498Szrj }
315838fd1498Szrj else
315938fd1498Szrj {
316038fd1498Szrj e = find_edge (cont_bb, l2_bb);
316138fd1498Szrj e->flags = EDGE_FALLTHRU;
316238fd1498Szrj }
316338fd1498Szrj make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
316438fd1498Szrj
316538fd1498Szrj if (gimple_in_ssa_p (cfun))
316638fd1498Szrj {
316738fd1498Szrj /* Add phis to the outer loop that connect to the phis in the inner,
316838fd1498Szrj original loop, and move the loop entry value of the inner phi to
316938fd1498Szrj the loop entry value of the outer phi. */
317038fd1498Szrj gphi_iterator psi;
317138fd1498Szrj for (psi = gsi_start_phis (l3_bb); !gsi_end_p (psi); gsi_next (&psi))
317238fd1498Szrj {
317338fd1498Szrj source_location locus;
317438fd1498Szrj gphi *nphi;
317538fd1498Szrj gphi *exit_phi = psi.phi ();
317638fd1498Szrj
317738fd1498Szrj if (virtual_operand_p (gimple_phi_result (exit_phi)))
317838fd1498Szrj continue;
317938fd1498Szrj
318038fd1498Szrj edge l2_to_l3 = find_edge (l2_bb, l3_bb);
318138fd1498Szrj tree exit_res = PHI_ARG_DEF_FROM_EDGE (exit_phi, l2_to_l3);
318238fd1498Szrj
318338fd1498Szrj basic_block latch = BRANCH_EDGE (cont_bb)->dest;
318438fd1498Szrj edge latch_to_l1 = find_edge (latch, l1_bb);
318538fd1498Szrj gphi *inner_phi
318638fd1498Szrj = find_phi_with_arg_on_edge (exit_res, latch_to_l1);
318738fd1498Szrj
318838fd1498Szrj tree t = gimple_phi_result (exit_phi);
318938fd1498Szrj tree new_res = copy_ssa_name (t, NULL);
319038fd1498Szrj nphi = create_phi_node (new_res, l0_bb);
319138fd1498Szrj
319238fd1498Szrj edge l0_to_l1 = find_edge (l0_bb, l1_bb);
319338fd1498Szrj t = PHI_ARG_DEF_FROM_EDGE (inner_phi, l0_to_l1);
319438fd1498Szrj locus = gimple_phi_arg_location_from_edge (inner_phi, l0_to_l1);
319538fd1498Szrj edge entry_to_l0 = find_edge (entry_bb, l0_bb);
319638fd1498Szrj add_phi_arg (nphi, t, entry_to_l0, locus);
319738fd1498Szrj
319838fd1498Szrj edge l2_to_l0 = find_edge (l2_bb, l0_bb);
319938fd1498Szrj add_phi_arg (nphi, exit_res, l2_to_l0, UNKNOWN_LOCATION);
320038fd1498Szrj
320138fd1498Szrj add_phi_arg (inner_phi, new_res, l0_to_l1, UNKNOWN_LOCATION);
320238fd1498Szrj }
320338fd1498Szrj }
320438fd1498Szrj
320538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l2_bb,
320638fd1498Szrj recompute_dominator (CDI_DOMINATORS, l2_bb));
320738fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l3_bb,
320838fd1498Szrj recompute_dominator (CDI_DOMINATORS, l3_bb));
320938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l0_bb,
321038fd1498Szrj recompute_dominator (CDI_DOMINATORS, l0_bb));
321138fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l1_bb,
321238fd1498Szrj recompute_dominator (CDI_DOMINATORS, l1_bb));
321338fd1498Szrj
321438fd1498Szrj /* We enter expand_omp_for_generic with a loop. This original loop may
321538fd1498Szrj have its own loop struct, or it may be part of an outer loop struct
321638fd1498Szrj (which may be the fake loop). */
321738fd1498Szrj struct loop *outer_loop = entry_bb->loop_father;
321838fd1498Szrj bool orig_loop_has_loop_struct = l1_bb->loop_father != outer_loop;
321938fd1498Szrj
322038fd1498Szrj add_bb_to_loop (l2_bb, outer_loop);
322138fd1498Szrj
322238fd1498Szrj /* We've added a new loop around the original loop. Allocate the
322338fd1498Szrj corresponding loop struct. */
322438fd1498Szrj struct loop *new_loop = alloc_loop ();
322538fd1498Szrj new_loop->header = l0_bb;
322638fd1498Szrj new_loop->latch = l2_bb;
322738fd1498Szrj add_loop (new_loop, outer_loop);
322838fd1498Szrj
322938fd1498Szrj /* Allocate a loop structure for the original loop unless we already
323038fd1498Szrj had one. */
323138fd1498Szrj if (!orig_loop_has_loop_struct
323238fd1498Szrj && !gimple_omp_for_combined_p (fd->for_stmt))
323338fd1498Szrj {
323438fd1498Szrj struct loop *orig_loop = alloc_loop ();
323538fd1498Szrj orig_loop->header = l1_bb;
323638fd1498Szrj /* The loop may have multiple latches. */
323738fd1498Szrj add_loop (orig_loop, new_loop);
323838fd1498Szrj }
323938fd1498Szrj }
324038fd1498Szrj }
324138fd1498Szrj
324238fd1498Szrj /* A subroutine of expand_omp_for. Generate code for a parallel
324338fd1498Szrj loop with static schedule and no specified chunk size. Given
324438fd1498Szrj parameters:
324538fd1498Szrj
324638fd1498Szrj for (V = N1; V cond N2; V += STEP) BODY;
324738fd1498Szrj
324838fd1498Szrj where COND is "<" or ">", we generate pseudocode
324938fd1498Szrj
325038fd1498Szrj if ((__typeof (V)) -1 > 0 && N2 cond N1) goto L2;
325138fd1498Szrj if (cond is <)
325238fd1498Szrj adj = STEP - 1;
325338fd1498Szrj else
325438fd1498Szrj adj = STEP + 1;
325538fd1498Szrj if ((__typeof (V)) -1 > 0 && cond is >)
325638fd1498Szrj n = -(adj + N2 - N1) / -STEP;
325738fd1498Szrj else
325838fd1498Szrj n = (adj + N2 - N1) / STEP;
325938fd1498Szrj q = n / nthreads;
326038fd1498Szrj tt = n % nthreads;
326138fd1498Szrj if (threadid < tt) goto L3; else goto L4;
326238fd1498Szrj L3:
326338fd1498Szrj tt = 0;
326438fd1498Szrj q = q + 1;
326538fd1498Szrj L4:
326638fd1498Szrj s0 = q * threadid + tt;
326738fd1498Szrj e0 = s0 + q;
326838fd1498Szrj V = s0 * STEP + N1;
326938fd1498Szrj if (s0 >= e0) goto L2; else goto L0;
327038fd1498Szrj L0:
327138fd1498Szrj e = e0 * STEP + N1;
327238fd1498Szrj L1:
327338fd1498Szrj BODY;
327438fd1498Szrj V += STEP;
327538fd1498Szrj if (V cond e) goto L1;
327638fd1498Szrj L2:
327738fd1498Szrj */
327838fd1498Szrj
327938fd1498Szrj static void
expand_omp_for_static_nochunk(struct omp_region * region,struct omp_for_data * fd,gimple * inner_stmt)328038fd1498Szrj expand_omp_for_static_nochunk (struct omp_region *region,
328138fd1498Szrj struct omp_for_data *fd,
328238fd1498Szrj gimple *inner_stmt)
328338fd1498Szrj {
328438fd1498Szrj tree n, q, s0, e0, e, t, tt, nthreads, threadid;
328538fd1498Szrj tree type, itype, vmain, vback;
328638fd1498Szrj basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb;
328738fd1498Szrj basic_block body_bb, cont_bb, collapse_bb = NULL;
328838fd1498Szrj basic_block fin_bb;
328938fd1498Szrj gimple_stmt_iterator gsi;
329038fd1498Szrj edge ep;
329138fd1498Szrj bool broken_loop = region->cont == NULL;
329238fd1498Szrj tree *counts = NULL;
329338fd1498Szrj tree n1, n2, step;
329438fd1498Szrj
329538fd1498Szrj itype = type = TREE_TYPE (fd->loop.v);
329638fd1498Szrj if (POINTER_TYPE_P (type))
329738fd1498Szrj itype = signed_type_for (type);
329838fd1498Szrj
329938fd1498Szrj entry_bb = region->entry;
330038fd1498Szrj cont_bb = region->cont;
330138fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
330238fd1498Szrj fin_bb = BRANCH_EDGE (entry_bb)->dest;
330338fd1498Szrj gcc_assert (broken_loop
330438fd1498Szrj || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest));
330538fd1498Szrj seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb));
330638fd1498Szrj body_bb = single_succ (seq_start_bb);
330738fd1498Szrj if (!broken_loop)
330838fd1498Szrj {
330938fd1498Szrj gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb
331038fd1498Szrj || single_succ (BRANCH_EDGE (cont_bb)->dest) == body_bb);
331138fd1498Szrj gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
331238fd1498Szrj }
331338fd1498Szrj exit_bb = region->exit;
331438fd1498Szrj
331538fd1498Szrj /* Iteration space partitioning goes in ENTRY_BB. */
331638fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
331738fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
331838fd1498Szrj
331938fd1498Szrj if (fd->collapse > 1)
332038fd1498Szrj {
332138fd1498Szrj int first_zero_iter = -1, dummy = -1;
332238fd1498Szrj basic_block l2_dom_bb = NULL, dummy_bb = NULL;
332338fd1498Szrj
332438fd1498Szrj counts = XALLOCAVEC (tree, fd->collapse);
332538fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
332638fd1498Szrj fin_bb, first_zero_iter,
332738fd1498Szrj dummy_bb, dummy, l2_dom_bb);
332838fd1498Szrj t = NULL_TREE;
332938fd1498Szrj }
333038fd1498Szrj else if (gimple_omp_for_combined_into_p (fd->for_stmt))
333138fd1498Szrj t = integer_one_node;
333238fd1498Szrj else
333338fd1498Szrj t = fold_binary (fd->loop.cond_code, boolean_type_node,
333438fd1498Szrj fold_convert (type, fd->loop.n1),
333538fd1498Szrj fold_convert (type, fd->loop.n2));
333638fd1498Szrj if (fd->collapse == 1
333738fd1498Szrj && TYPE_UNSIGNED (type)
333838fd1498Szrj && (t == NULL_TREE || !integer_onep (t)))
333938fd1498Szrj {
334038fd1498Szrj n1 = fold_convert (type, unshare_expr (fd->loop.n1));
334138fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE,
334238fd1498Szrj true, GSI_SAME_STMT);
334338fd1498Szrj n2 = fold_convert (type, unshare_expr (fd->loop.n2));
334438fd1498Szrj n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE,
334538fd1498Szrj true, GSI_SAME_STMT);
334638fd1498Szrj gcond *cond_stmt = gimple_build_cond (fd->loop.cond_code, n1, n2,
334738fd1498Szrj NULL_TREE, NULL_TREE);
334838fd1498Szrj gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
334938fd1498Szrj if (walk_tree (gimple_cond_lhs_ptr (cond_stmt),
335038fd1498Szrj expand_omp_regimplify_p, NULL, NULL)
335138fd1498Szrj || walk_tree (gimple_cond_rhs_ptr (cond_stmt),
335238fd1498Szrj expand_omp_regimplify_p, NULL, NULL))
335338fd1498Szrj {
335438fd1498Szrj gsi = gsi_for_stmt (cond_stmt);
335538fd1498Szrj gimple_regimplify_operands (cond_stmt, &gsi);
335638fd1498Szrj }
335738fd1498Szrj ep = split_block (entry_bb, cond_stmt);
335838fd1498Szrj ep->flags = EDGE_TRUE_VALUE;
335938fd1498Szrj entry_bb = ep->dest;
336038fd1498Szrj ep->probability = profile_probability::very_likely ();
336138fd1498Szrj ep = make_edge (ep->src, fin_bb, EDGE_FALSE_VALUE);
336238fd1498Szrj ep->probability = profile_probability::very_unlikely ();
336338fd1498Szrj if (gimple_in_ssa_p (cfun))
336438fd1498Szrj {
336538fd1498Szrj int dest_idx = find_edge (entry_bb, fin_bb)->dest_idx;
336638fd1498Szrj for (gphi_iterator gpi = gsi_start_phis (fin_bb);
336738fd1498Szrj !gsi_end_p (gpi); gsi_next (&gpi))
336838fd1498Szrj {
336938fd1498Szrj gphi *phi = gpi.phi ();
337038fd1498Szrj add_phi_arg (phi, gimple_phi_arg_def (phi, dest_idx),
337138fd1498Szrj ep, UNKNOWN_LOCATION);
337238fd1498Szrj }
337338fd1498Szrj }
337438fd1498Szrj gsi = gsi_last_bb (entry_bb);
337538fd1498Szrj }
337638fd1498Szrj
337738fd1498Szrj switch (gimple_omp_for_kind (fd->for_stmt))
337838fd1498Szrj {
337938fd1498Szrj case GF_OMP_FOR_KIND_FOR:
338038fd1498Szrj nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
338138fd1498Szrj threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
338238fd1498Szrj break;
338338fd1498Szrj case GF_OMP_FOR_KIND_DISTRIBUTE:
338438fd1498Szrj nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS);
338538fd1498Szrj threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM);
338638fd1498Szrj break;
338738fd1498Szrj default:
338838fd1498Szrj gcc_unreachable ();
338938fd1498Szrj }
339038fd1498Szrj nthreads = build_call_expr (nthreads, 0);
339138fd1498Szrj nthreads = fold_convert (itype, nthreads);
339238fd1498Szrj nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE,
339338fd1498Szrj true, GSI_SAME_STMT);
339438fd1498Szrj threadid = build_call_expr (threadid, 0);
339538fd1498Szrj threadid = fold_convert (itype, threadid);
339638fd1498Szrj threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE,
339738fd1498Szrj true, GSI_SAME_STMT);
339838fd1498Szrj
339938fd1498Szrj n1 = fd->loop.n1;
340038fd1498Szrj n2 = fd->loop.n2;
340138fd1498Szrj step = fd->loop.step;
340238fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
340338fd1498Szrj {
340438fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
340538fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
340638fd1498Szrj gcc_assert (innerc);
340738fd1498Szrj n1 = OMP_CLAUSE_DECL (innerc);
340838fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
340938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
341038fd1498Szrj gcc_assert (innerc);
341138fd1498Szrj n2 = OMP_CLAUSE_DECL (innerc);
341238fd1498Szrj }
341338fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
341438fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
341538fd1498Szrj n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2),
341638fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
341738fd1498Szrj step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
341838fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
341938fd1498Szrj
342038fd1498Szrj t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
342138fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, step, t);
342238fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, t, n2);
342338fd1498Szrj t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
342438fd1498Szrj if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
342538fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype,
342638fd1498Szrj fold_build1 (NEGATE_EXPR, itype, t),
342738fd1498Szrj fold_build1 (NEGATE_EXPR, itype, step));
342838fd1498Szrj else
342938fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
343038fd1498Szrj t = fold_convert (itype, t);
343138fd1498Szrj n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
343238fd1498Szrj
343338fd1498Szrj q = create_tmp_reg (itype, "q");
343438fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype, n, nthreads);
343538fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, true, GSI_SAME_STMT);
343638fd1498Szrj gsi_insert_before (&gsi, gimple_build_assign (q, t), GSI_SAME_STMT);
343738fd1498Szrj
343838fd1498Szrj tt = create_tmp_reg (itype, "tt");
343938fd1498Szrj t = fold_build2 (TRUNC_MOD_EXPR, itype, n, nthreads);
344038fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, true, GSI_SAME_STMT);
344138fd1498Szrj gsi_insert_before (&gsi, gimple_build_assign (tt, t), GSI_SAME_STMT);
344238fd1498Szrj
344338fd1498Szrj t = build2 (LT_EXPR, boolean_type_node, threadid, tt);
344438fd1498Szrj gcond *cond_stmt = gimple_build_cond_empty (t);
344538fd1498Szrj gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
344638fd1498Szrj
344738fd1498Szrj second_bb = split_block (entry_bb, cond_stmt)->dest;
344838fd1498Szrj gsi = gsi_last_nondebug_bb (second_bb);
344938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
345038fd1498Szrj
345138fd1498Szrj gsi_insert_before (&gsi, gimple_build_assign (tt, build_int_cst (itype, 0)),
345238fd1498Szrj GSI_SAME_STMT);
345338fd1498Szrj gassign *assign_stmt
345438fd1498Szrj = gimple_build_assign (q, PLUS_EXPR, q, build_int_cst (itype, 1));
345538fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
345638fd1498Szrj
345738fd1498Szrj third_bb = split_block (second_bb, assign_stmt)->dest;
345838fd1498Szrj gsi = gsi_last_nondebug_bb (third_bb);
345938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
346038fd1498Szrj
346138fd1498Szrj t = build2 (MULT_EXPR, itype, q, threadid);
346238fd1498Szrj t = build2 (PLUS_EXPR, itype, t, tt);
346338fd1498Szrj s0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
346438fd1498Szrj
346538fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, s0, q);
346638fd1498Szrj e0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true, GSI_SAME_STMT);
346738fd1498Szrj
346838fd1498Szrj t = build2 (GE_EXPR, boolean_type_node, s0, e0);
346938fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
347038fd1498Szrj
347138fd1498Szrj /* Remove the GIMPLE_OMP_FOR statement. */
347238fd1498Szrj gsi_remove (&gsi, true);
347338fd1498Szrj
347438fd1498Szrj /* Setup code for sequential iteration goes in SEQ_START_BB. */
347538fd1498Szrj gsi = gsi_start_bb (seq_start_bb);
347638fd1498Szrj
347738fd1498Szrj tree startvar = fd->loop.v;
347838fd1498Szrj tree endvar = NULL_TREE;
347938fd1498Szrj
348038fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
348138fd1498Szrj {
348238fd1498Szrj tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL
348338fd1498Szrj ? gimple_omp_parallel_clauses (inner_stmt)
348438fd1498Szrj : gimple_omp_for_clauses (inner_stmt);
348538fd1498Szrj tree innerc = omp_find_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
348638fd1498Szrj gcc_assert (innerc);
348738fd1498Szrj startvar = OMP_CLAUSE_DECL (innerc);
348838fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
348938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
349038fd1498Szrj gcc_assert (innerc);
349138fd1498Szrj endvar = OMP_CLAUSE_DECL (innerc);
349238fd1498Szrj if (fd->collapse > 1 && TREE_CODE (fd->loop.n2) != INTEGER_CST
349338fd1498Szrj && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
349438fd1498Szrj {
349538fd1498Szrj int i;
349638fd1498Szrj for (i = 1; i < fd->collapse; i++)
349738fd1498Szrj {
349838fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
349938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
350038fd1498Szrj gcc_assert (innerc);
350138fd1498Szrj }
350238fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
350338fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
350438fd1498Szrj if (innerc)
350538fd1498Szrj {
350638fd1498Szrj /* If needed (distribute parallel for with lastprivate),
350738fd1498Szrj propagate down the total number of iterations. */
350838fd1498Szrj tree t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (innerc)),
350938fd1498Szrj fd->loop.n2);
351038fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, false,
351138fd1498Szrj GSI_CONTINUE_LINKING);
351238fd1498Szrj assign_stmt = gimple_build_assign (OMP_CLAUSE_DECL (innerc), t);
351338fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
351438fd1498Szrj }
351538fd1498Szrj }
351638fd1498Szrj }
351738fd1498Szrj t = fold_convert (itype, s0);
351838fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, step);
351938fd1498Szrj if (POINTER_TYPE_P (type))
352038fd1498Szrj t = fold_build_pointer_plus (n1, t);
352138fd1498Szrj else
352238fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
352338fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
352438fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
352538fd1498Szrj DECL_P (startvar)
352638fd1498Szrj && TREE_ADDRESSABLE (startvar),
352738fd1498Szrj NULL_TREE, false, GSI_CONTINUE_LINKING);
352838fd1498Szrj assign_stmt = gimple_build_assign (startvar, t);
352938fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
353038fd1498Szrj
353138fd1498Szrj t = fold_convert (itype, e0);
353238fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, step);
353338fd1498Szrj if (POINTER_TYPE_P (type))
353438fd1498Szrj t = fold_build_pointer_plus (n1, t);
353538fd1498Szrj else
353638fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
353738fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
353838fd1498Szrj e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
353938fd1498Szrj false, GSI_CONTINUE_LINKING);
354038fd1498Szrj if (endvar)
354138fd1498Szrj {
354238fd1498Szrj assign_stmt = gimple_build_assign (endvar, e);
354338fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
354438fd1498Szrj if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (e)))
354538fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, e);
354638fd1498Szrj else
354738fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e);
354838fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
354938fd1498Szrj }
355038fd1498Szrj /* Handle linear clause adjustments. */
355138fd1498Szrj tree itercnt = NULL_TREE;
355238fd1498Szrj if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR)
355338fd1498Szrj for (tree c = gimple_omp_for_clauses (fd->for_stmt);
355438fd1498Szrj c; c = OMP_CLAUSE_CHAIN (c))
355538fd1498Szrj if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
355638fd1498Szrj && !OMP_CLAUSE_LINEAR_NO_COPYIN (c))
355738fd1498Szrj {
355838fd1498Szrj tree d = OMP_CLAUSE_DECL (c);
355938fd1498Szrj bool is_ref = omp_is_reference (d);
356038fd1498Szrj tree t = d, a, dest;
356138fd1498Szrj if (is_ref)
356238fd1498Szrj t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t);
356338fd1498Szrj if (itercnt == NULL_TREE)
356438fd1498Szrj {
356538fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
356638fd1498Szrj {
356738fd1498Szrj itercnt = fold_build2 (MINUS_EXPR, itype,
356838fd1498Szrj fold_convert (itype, n1),
356938fd1498Szrj fold_convert (itype, fd->loop.n1));
357038fd1498Szrj itercnt = fold_build2 (EXACT_DIV_EXPR, itype, itercnt, step);
357138fd1498Szrj itercnt = fold_build2 (PLUS_EXPR, itype, itercnt, s0);
357238fd1498Szrj itercnt = force_gimple_operand_gsi (&gsi, itercnt, true,
357338fd1498Szrj NULL_TREE, false,
357438fd1498Szrj GSI_CONTINUE_LINKING);
357538fd1498Szrj }
357638fd1498Szrj else
357738fd1498Szrj itercnt = s0;
357838fd1498Szrj }
357938fd1498Szrj tree type = TREE_TYPE (t);
358038fd1498Szrj if (POINTER_TYPE_P (type))
358138fd1498Szrj type = sizetype;
358238fd1498Szrj a = fold_build2 (MULT_EXPR, type,
358338fd1498Szrj fold_convert (type, itercnt),
358438fd1498Szrj fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c)));
358538fd1498Szrj dest = unshare_expr (t);
358638fd1498Szrj t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR
358738fd1498Szrj : POINTER_PLUS_EXPR, TREE_TYPE (t), t, a);
358838fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
358938fd1498Szrj false, GSI_CONTINUE_LINKING);
359038fd1498Szrj assign_stmt = gimple_build_assign (dest, t);
359138fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
359238fd1498Szrj }
359338fd1498Szrj if (fd->collapse > 1)
359438fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
359538fd1498Szrj
359638fd1498Szrj if (!broken_loop)
359738fd1498Szrj {
359838fd1498Szrj /* The code controlling the sequential loop replaces the
359938fd1498Szrj GIMPLE_OMP_CONTINUE. */
360038fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
360138fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
360238fd1498Szrj gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
360338fd1498Szrj vmain = gimple_omp_continue_control_use (cont_stmt);
360438fd1498Szrj vback = gimple_omp_continue_control_def (cont_stmt);
360538fd1498Szrj
360638fd1498Szrj if (!gimple_omp_for_combined_p (fd->for_stmt))
360738fd1498Szrj {
360838fd1498Szrj if (POINTER_TYPE_P (type))
360938fd1498Szrj t = fold_build_pointer_plus (vmain, step);
361038fd1498Szrj else
361138fd1498Szrj t = fold_build2 (PLUS_EXPR, type, vmain, step);
361238fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
361338fd1498Szrj DECL_P (vback)
361438fd1498Szrj && TREE_ADDRESSABLE (vback),
361538fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
361638fd1498Szrj assign_stmt = gimple_build_assign (vback, t);
361738fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
361838fd1498Szrj
361938fd1498Szrj t = build2 (fd->loop.cond_code, boolean_type_node,
362038fd1498Szrj DECL_P (vback) && TREE_ADDRESSABLE (vback)
362138fd1498Szrj ? t : vback, e);
362238fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
362338fd1498Szrj }
362438fd1498Szrj
362538fd1498Szrj /* Remove the GIMPLE_OMP_CONTINUE statement. */
362638fd1498Szrj gsi_remove (&gsi, true);
362738fd1498Szrj
362838fd1498Szrj if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
362938fd1498Szrj collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb);
363038fd1498Szrj }
363138fd1498Szrj
363238fd1498Szrj /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
363338fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
363438fd1498Szrj if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
363538fd1498Szrj {
363638fd1498Szrj t = gimple_omp_return_lhs (gsi_stmt (gsi));
363738fd1498Szrj gsi_insert_after (&gsi, omp_build_barrier (t), GSI_SAME_STMT);
363838fd1498Szrj }
363938fd1498Szrj gsi_remove (&gsi, true);
364038fd1498Szrj
364138fd1498Szrj /* Connect all the blocks. */
364238fd1498Szrj ep = make_edge (entry_bb, third_bb, EDGE_FALSE_VALUE);
364338fd1498Szrj ep->probability = profile_probability::guessed_always ().apply_scale (3, 4);
364438fd1498Szrj ep = find_edge (entry_bb, second_bb);
364538fd1498Szrj ep->flags = EDGE_TRUE_VALUE;
364638fd1498Szrj ep->probability = profile_probability::guessed_always ().apply_scale (1, 4);
364738fd1498Szrj find_edge (third_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
364838fd1498Szrj find_edge (third_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
364938fd1498Szrj
365038fd1498Szrj if (!broken_loop)
365138fd1498Szrj {
365238fd1498Szrj ep = find_edge (cont_bb, body_bb);
365338fd1498Szrj if (ep == NULL)
365438fd1498Szrj {
365538fd1498Szrj ep = BRANCH_EDGE (cont_bb);
365638fd1498Szrj gcc_assert (single_succ (ep->dest) == body_bb);
365738fd1498Szrj }
365838fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
365938fd1498Szrj {
366038fd1498Szrj remove_edge (ep);
366138fd1498Szrj ep = NULL;
366238fd1498Szrj }
366338fd1498Szrj else if (fd->collapse > 1)
366438fd1498Szrj {
366538fd1498Szrj remove_edge (ep);
366638fd1498Szrj ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
366738fd1498Szrj }
366838fd1498Szrj else
366938fd1498Szrj ep->flags = EDGE_TRUE_VALUE;
367038fd1498Szrj find_edge (cont_bb, fin_bb)->flags
367138fd1498Szrj = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
367238fd1498Szrj }
367338fd1498Szrj
367438fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, second_bb, entry_bb);
367538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, third_bb, entry_bb);
367638fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, third_bb);
367738fd1498Szrj
367838fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, body_bb,
367938fd1498Szrj recompute_dominator (CDI_DOMINATORS, body_bb));
368038fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, fin_bb,
368138fd1498Szrj recompute_dominator (CDI_DOMINATORS, fin_bb));
368238fd1498Szrj
368338fd1498Szrj struct loop *loop = body_bb->loop_father;
368438fd1498Szrj if (loop != entry_bb->loop_father)
368538fd1498Szrj {
368638fd1498Szrj gcc_assert (broken_loop || loop->header == body_bb);
368738fd1498Szrj gcc_assert (broken_loop
368838fd1498Szrj || loop->latch == region->cont
368938fd1498Szrj || single_pred (loop->latch) == region->cont);
369038fd1498Szrj return;
369138fd1498Szrj }
369238fd1498Szrj
369338fd1498Szrj if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt))
369438fd1498Szrj {
369538fd1498Szrj loop = alloc_loop ();
369638fd1498Szrj loop->header = body_bb;
369738fd1498Szrj if (collapse_bb == NULL)
369838fd1498Szrj loop->latch = cont_bb;
369938fd1498Szrj add_loop (loop, body_bb->loop_father);
370038fd1498Szrj }
370138fd1498Szrj }
370238fd1498Szrj
370338fd1498Szrj /* Return phi in E->DEST with ARG on edge E. */
370438fd1498Szrj
370538fd1498Szrj static gphi *
find_phi_with_arg_on_edge(tree arg,edge e)370638fd1498Szrj find_phi_with_arg_on_edge (tree arg, edge e)
370738fd1498Szrj {
370838fd1498Szrj basic_block bb = e->dest;
370938fd1498Szrj
371038fd1498Szrj for (gphi_iterator gpi = gsi_start_phis (bb);
371138fd1498Szrj !gsi_end_p (gpi);
371238fd1498Szrj gsi_next (&gpi))
371338fd1498Szrj {
371438fd1498Szrj gphi *phi = gpi.phi ();
371538fd1498Szrj if (PHI_ARG_DEF_FROM_EDGE (phi, e) == arg)
371638fd1498Szrj return phi;
371738fd1498Szrj }
371838fd1498Szrj
371938fd1498Szrj return NULL;
372038fd1498Szrj }
372138fd1498Szrj
372238fd1498Szrj /* A subroutine of expand_omp_for. Generate code for a parallel
372338fd1498Szrj loop with static schedule and a specified chunk size. Given
372438fd1498Szrj parameters:
372538fd1498Szrj
372638fd1498Szrj for (V = N1; V cond N2; V += STEP) BODY;
372738fd1498Szrj
372838fd1498Szrj where COND is "<" or ">", we generate pseudocode
372938fd1498Szrj
373038fd1498Szrj if ((__typeof (V)) -1 > 0 && N2 cond N1) goto L2;
373138fd1498Szrj if (cond is <)
373238fd1498Szrj adj = STEP - 1;
373338fd1498Szrj else
373438fd1498Szrj adj = STEP + 1;
373538fd1498Szrj if ((__typeof (V)) -1 > 0 && cond is >)
373638fd1498Szrj n = -(adj + N2 - N1) / -STEP;
373738fd1498Szrj else
373838fd1498Szrj n = (adj + N2 - N1) / STEP;
373938fd1498Szrj trip = 0;
374038fd1498Szrj V = threadid * CHUNK * STEP + N1; -- this extra definition of V is
374138fd1498Szrj here so that V is defined
374238fd1498Szrj if the loop is not entered
374338fd1498Szrj L0:
374438fd1498Szrj s0 = (trip * nthreads + threadid) * CHUNK;
374538fd1498Szrj e0 = min (s0 + CHUNK, n);
374638fd1498Szrj if (s0 < n) goto L1; else goto L4;
374738fd1498Szrj L1:
374838fd1498Szrj V = s0 * STEP + N1;
374938fd1498Szrj e = e0 * STEP + N1;
375038fd1498Szrj L2:
375138fd1498Szrj BODY;
375238fd1498Szrj V += STEP;
375338fd1498Szrj if (V cond e) goto L2; else goto L3;
375438fd1498Szrj L3:
375538fd1498Szrj trip += 1;
375638fd1498Szrj goto L0;
375738fd1498Szrj L4:
375838fd1498Szrj */
375938fd1498Szrj
376038fd1498Szrj static void
expand_omp_for_static_chunk(struct omp_region * region,struct omp_for_data * fd,gimple * inner_stmt)376138fd1498Szrj expand_omp_for_static_chunk (struct omp_region *region,
376238fd1498Szrj struct omp_for_data *fd, gimple *inner_stmt)
376338fd1498Szrj {
376438fd1498Szrj tree n, s0, e0, e, t;
376538fd1498Szrj tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
376638fd1498Szrj tree type, itype, vmain, vback, vextra;
376738fd1498Szrj basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
376838fd1498Szrj basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb;
376938fd1498Szrj gimple_stmt_iterator gsi;
377038fd1498Szrj edge se;
377138fd1498Szrj bool broken_loop = region->cont == NULL;
377238fd1498Szrj tree *counts = NULL;
377338fd1498Szrj tree n1, n2, step;
377438fd1498Szrj
377538fd1498Szrj itype = type = TREE_TYPE (fd->loop.v);
377638fd1498Szrj if (POINTER_TYPE_P (type))
377738fd1498Szrj itype = signed_type_for (type);
377838fd1498Szrj
377938fd1498Szrj entry_bb = region->entry;
378038fd1498Szrj se = split_block (entry_bb, last_stmt (entry_bb));
378138fd1498Szrj entry_bb = se->src;
378238fd1498Szrj iter_part_bb = se->dest;
378338fd1498Szrj cont_bb = region->cont;
378438fd1498Szrj gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2);
378538fd1498Szrj fin_bb = BRANCH_EDGE (iter_part_bb)->dest;
378638fd1498Szrj gcc_assert (broken_loop
378738fd1498Szrj || fin_bb == FALLTHRU_EDGE (cont_bb)->dest);
378838fd1498Szrj seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb));
378938fd1498Szrj body_bb = single_succ (seq_start_bb);
379038fd1498Szrj if (!broken_loop)
379138fd1498Szrj {
379238fd1498Szrj gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb
379338fd1498Szrj || single_succ (BRANCH_EDGE (cont_bb)->dest) == body_bb);
379438fd1498Szrj gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
379538fd1498Szrj trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
379638fd1498Szrj }
379738fd1498Szrj exit_bb = region->exit;
379838fd1498Szrj
379938fd1498Szrj /* Trip and adjustment setup goes in ENTRY_BB. */
380038fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
380138fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
380238fd1498Szrj
380338fd1498Szrj if (fd->collapse > 1)
380438fd1498Szrj {
380538fd1498Szrj int first_zero_iter = -1, dummy = -1;
380638fd1498Szrj basic_block l2_dom_bb = NULL, dummy_bb = NULL;
380738fd1498Szrj
380838fd1498Szrj counts = XALLOCAVEC (tree, fd->collapse);
380938fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
381038fd1498Szrj fin_bb, first_zero_iter,
381138fd1498Szrj dummy_bb, dummy, l2_dom_bb);
381238fd1498Szrj t = NULL_TREE;
381338fd1498Szrj }
381438fd1498Szrj else if (gimple_omp_for_combined_into_p (fd->for_stmt))
381538fd1498Szrj t = integer_one_node;
381638fd1498Szrj else
381738fd1498Szrj t = fold_binary (fd->loop.cond_code, boolean_type_node,
381838fd1498Szrj fold_convert (type, fd->loop.n1),
381938fd1498Szrj fold_convert (type, fd->loop.n2));
382038fd1498Szrj if (fd->collapse == 1
382138fd1498Szrj && TYPE_UNSIGNED (type)
382238fd1498Szrj && (t == NULL_TREE || !integer_onep (t)))
382338fd1498Szrj {
382438fd1498Szrj n1 = fold_convert (type, unshare_expr (fd->loop.n1));
382538fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, n1, true, NULL_TREE,
382638fd1498Szrj true, GSI_SAME_STMT);
382738fd1498Szrj n2 = fold_convert (type, unshare_expr (fd->loop.n2));
382838fd1498Szrj n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE,
382938fd1498Szrj true, GSI_SAME_STMT);
383038fd1498Szrj gcond *cond_stmt = gimple_build_cond (fd->loop.cond_code, n1, n2,
383138fd1498Szrj NULL_TREE, NULL_TREE);
383238fd1498Szrj gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
383338fd1498Szrj if (walk_tree (gimple_cond_lhs_ptr (cond_stmt),
383438fd1498Szrj expand_omp_regimplify_p, NULL, NULL)
383538fd1498Szrj || walk_tree (gimple_cond_rhs_ptr (cond_stmt),
383638fd1498Szrj expand_omp_regimplify_p, NULL, NULL))
383738fd1498Szrj {
383838fd1498Szrj gsi = gsi_for_stmt (cond_stmt);
383938fd1498Szrj gimple_regimplify_operands (cond_stmt, &gsi);
384038fd1498Szrj }
384138fd1498Szrj se = split_block (entry_bb, cond_stmt);
384238fd1498Szrj se->flags = EDGE_TRUE_VALUE;
384338fd1498Szrj entry_bb = se->dest;
384438fd1498Szrj se->probability = profile_probability::very_likely ();
384538fd1498Szrj se = make_edge (se->src, fin_bb, EDGE_FALSE_VALUE);
384638fd1498Szrj se->probability = profile_probability::very_unlikely ();
384738fd1498Szrj if (gimple_in_ssa_p (cfun))
384838fd1498Szrj {
384938fd1498Szrj int dest_idx = find_edge (iter_part_bb, fin_bb)->dest_idx;
385038fd1498Szrj for (gphi_iterator gpi = gsi_start_phis (fin_bb);
385138fd1498Szrj !gsi_end_p (gpi); gsi_next (&gpi))
385238fd1498Szrj {
385338fd1498Szrj gphi *phi = gpi.phi ();
385438fd1498Szrj add_phi_arg (phi, gimple_phi_arg_def (phi, dest_idx),
385538fd1498Szrj se, UNKNOWN_LOCATION);
385638fd1498Szrj }
385738fd1498Szrj }
385838fd1498Szrj gsi = gsi_last_bb (entry_bb);
385938fd1498Szrj }
386038fd1498Szrj
386138fd1498Szrj switch (gimple_omp_for_kind (fd->for_stmt))
386238fd1498Szrj {
386338fd1498Szrj case GF_OMP_FOR_KIND_FOR:
386438fd1498Szrj nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
386538fd1498Szrj threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
386638fd1498Szrj break;
386738fd1498Szrj case GF_OMP_FOR_KIND_DISTRIBUTE:
386838fd1498Szrj nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS);
386938fd1498Szrj threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM);
387038fd1498Szrj break;
387138fd1498Szrj default:
387238fd1498Szrj gcc_unreachable ();
387338fd1498Szrj }
387438fd1498Szrj nthreads = build_call_expr (nthreads, 0);
387538fd1498Szrj nthreads = fold_convert (itype, nthreads);
387638fd1498Szrj nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE,
387738fd1498Szrj true, GSI_SAME_STMT);
387838fd1498Szrj threadid = build_call_expr (threadid, 0);
387938fd1498Szrj threadid = fold_convert (itype, threadid);
388038fd1498Szrj threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE,
388138fd1498Szrj true, GSI_SAME_STMT);
388238fd1498Szrj
388338fd1498Szrj n1 = fd->loop.n1;
388438fd1498Szrj n2 = fd->loop.n2;
388538fd1498Szrj step = fd->loop.step;
388638fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
388738fd1498Szrj {
388838fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
388938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
389038fd1498Szrj gcc_assert (innerc);
389138fd1498Szrj n1 = OMP_CLAUSE_DECL (innerc);
389238fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
389338fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
389438fd1498Szrj gcc_assert (innerc);
389538fd1498Szrj n2 = OMP_CLAUSE_DECL (innerc);
389638fd1498Szrj }
389738fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
389838fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
389938fd1498Szrj n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2),
390038fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
390138fd1498Szrj step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
390238fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
390338fd1498Szrj tree chunk_size = fold_convert (itype, fd->chunk_size);
390438fd1498Szrj chunk_size = omp_adjust_chunk_size (chunk_size, fd->simd_schedule);
390538fd1498Szrj chunk_size
390638fd1498Szrj = force_gimple_operand_gsi (&gsi, chunk_size, true, NULL_TREE, true,
390738fd1498Szrj GSI_SAME_STMT);
390838fd1498Szrj
390938fd1498Szrj t = build_int_cst (itype, (fd->loop.cond_code == LT_EXPR ? -1 : 1));
391038fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, step, t);
391138fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, t, n2);
391238fd1498Szrj t = fold_build2 (MINUS_EXPR, itype, t, fold_convert (itype, n1));
391338fd1498Szrj if (TYPE_UNSIGNED (itype) && fd->loop.cond_code == GT_EXPR)
391438fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype,
391538fd1498Szrj fold_build1 (NEGATE_EXPR, itype, t),
391638fd1498Szrj fold_build1 (NEGATE_EXPR, itype, step));
391738fd1498Szrj else
391838fd1498Szrj t = fold_build2 (TRUNC_DIV_EXPR, itype, t, step);
391938fd1498Szrj t = fold_convert (itype, t);
392038fd1498Szrj n = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
392138fd1498Szrj true, GSI_SAME_STMT);
392238fd1498Szrj
392338fd1498Szrj trip_var = create_tmp_reg (itype, ".trip");
392438fd1498Szrj if (gimple_in_ssa_p (cfun))
392538fd1498Szrj {
392638fd1498Szrj trip_init = make_ssa_name (trip_var);
392738fd1498Szrj trip_main = make_ssa_name (trip_var);
392838fd1498Szrj trip_back = make_ssa_name (trip_var);
392938fd1498Szrj }
393038fd1498Szrj else
393138fd1498Szrj {
393238fd1498Szrj trip_init = trip_var;
393338fd1498Szrj trip_main = trip_var;
393438fd1498Szrj trip_back = trip_var;
393538fd1498Szrj }
393638fd1498Szrj
393738fd1498Szrj gassign *assign_stmt
393838fd1498Szrj = gimple_build_assign (trip_init, build_int_cst (itype, 0));
393938fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
394038fd1498Szrj
394138fd1498Szrj t = fold_build2 (MULT_EXPR, itype, threadid, chunk_size);
394238fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, step);
394338fd1498Szrj if (POINTER_TYPE_P (type))
394438fd1498Szrj t = fold_build_pointer_plus (n1, t);
394538fd1498Szrj else
394638fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
394738fd1498Szrj vextra = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
394838fd1498Szrj true, GSI_SAME_STMT);
394938fd1498Szrj
395038fd1498Szrj /* Remove the GIMPLE_OMP_FOR. */
395138fd1498Szrj gsi_remove (&gsi, true);
395238fd1498Szrj
395338fd1498Szrj gimple_stmt_iterator gsif = gsi;
395438fd1498Szrj
395538fd1498Szrj /* Iteration space partitioning goes in ITER_PART_BB. */
395638fd1498Szrj gsi = gsi_last_bb (iter_part_bb);
395738fd1498Szrj
395838fd1498Szrj t = fold_build2 (MULT_EXPR, itype, trip_main, nthreads);
395938fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, t, threadid);
396038fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, chunk_size);
396138fd1498Szrj s0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
396238fd1498Szrj false, GSI_CONTINUE_LINKING);
396338fd1498Szrj
396438fd1498Szrj t = fold_build2 (PLUS_EXPR, itype, s0, chunk_size);
396538fd1498Szrj t = fold_build2 (MIN_EXPR, itype, t, n);
396638fd1498Szrj e0 = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
396738fd1498Szrj false, GSI_CONTINUE_LINKING);
396838fd1498Szrj
396938fd1498Szrj t = build2 (LT_EXPR, boolean_type_node, s0, n);
397038fd1498Szrj gsi_insert_after (&gsi, gimple_build_cond_empty (t), GSI_CONTINUE_LINKING);
397138fd1498Szrj
397238fd1498Szrj /* Setup code for sequential iteration goes in SEQ_START_BB. */
397338fd1498Szrj gsi = gsi_start_bb (seq_start_bb);
397438fd1498Szrj
397538fd1498Szrj tree startvar = fd->loop.v;
397638fd1498Szrj tree endvar = NULL_TREE;
397738fd1498Szrj
397838fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
397938fd1498Szrj {
398038fd1498Szrj tree clauses = gimple_code (inner_stmt) == GIMPLE_OMP_PARALLEL
398138fd1498Szrj ? gimple_omp_parallel_clauses (inner_stmt)
398238fd1498Szrj : gimple_omp_for_clauses (inner_stmt);
398338fd1498Szrj tree innerc = omp_find_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
398438fd1498Szrj gcc_assert (innerc);
398538fd1498Szrj startvar = OMP_CLAUSE_DECL (innerc);
398638fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
398738fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
398838fd1498Szrj gcc_assert (innerc);
398938fd1498Szrj endvar = OMP_CLAUSE_DECL (innerc);
399038fd1498Szrj if (fd->collapse > 1 && TREE_CODE (fd->loop.n2) != INTEGER_CST
399138fd1498Szrj && gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE)
399238fd1498Szrj {
399338fd1498Szrj int i;
399438fd1498Szrj for (i = 1; i < fd->collapse; i++)
399538fd1498Szrj {
399638fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
399738fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
399838fd1498Szrj gcc_assert (innerc);
399938fd1498Szrj }
400038fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
400138fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
400238fd1498Szrj if (innerc)
400338fd1498Szrj {
400438fd1498Szrj /* If needed (distribute parallel for with lastprivate),
400538fd1498Szrj propagate down the total number of iterations. */
400638fd1498Szrj tree t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (innerc)),
400738fd1498Szrj fd->loop.n2);
400838fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, false, NULL_TREE, false,
400938fd1498Szrj GSI_CONTINUE_LINKING);
401038fd1498Szrj assign_stmt = gimple_build_assign (OMP_CLAUSE_DECL (innerc), t);
401138fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
401238fd1498Szrj }
401338fd1498Szrj }
401438fd1498Szrj }
401538fd1498Szrj
401638fd1498Szrj t = fold_convert (itype, s0);
401738fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, step);
401838fd1498Szrj if (POINTER_TYPE_P (type))
401938fd1498Szrj t = fold_build_pointer_plus (n1, t);
402038fd1498Szrj else
402138fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
402238fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
402338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
402438fd1498Szrj DECL_P (startvar)
402538fd1498Szrj && TREE_ADDRESSABLE (startvar),
402638fd1498Szrj NULL_TREE, false, GSI_CONTINUE_LINKING);
402738fd1498Szrj assign_stmt = gimple_build_assign (startvar, t);
402838fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
402938fd1498Szrj
403038fd1498Szrj t = fold_convert (itype, e0);
403138fd1498Szrj t = fold_build2 (MULT_EXPR, itype, t, step);
403238fd1498Szrj if (POINTER_TYPE_P (type))
403338fd1498Szrj t = fold_build_pointer_plus (n1, t);
403438fd1498Szrj else
403538fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
403638fd1498Szrj t = fold_convert (TREE_TYPE (startvar), t);
403738fd1498Szrj e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
403838fd1498Szrj false, GSI_CONTINUE_LINKING);
403938fd1498Szrj if (endvar)
404038fd1498Szrj {
404138fd1498Szrj assign_stmt = gimple_build_assign (endvar, e);
404238fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
404338fd1498Szrj if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (e)))
404438fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, e);
404538fd1498Szrj else
404638fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e);
404738fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
404838fd1498Szrj }
404938fd1498Szrj /* Handle linear clause adjustments. */
405038fd1498Szrj tree itercnt = NULL_TREE, itercntbias = NULL_TREE;
405138fd1498Szrj if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_FOR)
405238fd1498Szrj for (tree c = gimple_omp_for_clauses (fd->for_stmt);
405338fd1498Szrj c; c = OMP_CLAUSE_CHAIN (c))
405438fd1498Szrj if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
405538fd1498Szrj && !OMP_CLAUSE_LINEAR_NO_COPYIN (c))
405638fd1498Szrj {
405738fd1498Szrj tree d = OMP_CLAUSE_DECL (c);
405838fd1498Szrj bool is_ref = omp_is_reference (d);
405938fd1498Szrj tree t = d, a, dest;
406038fd1498Szrj if (is_ref)
406138fd1498Szrj t = build_simple_mem_ref_loc (OMP_CLAUSE_LOCATION (c), t);
406238fd1498Szrj tree type = TREE_TYPE (t);
406338fd1498Szrj if (POINTER_TYPE_P (type))
406438fd1498Szrj type = sizetype;
406538fd1498Szrj dest = unshare_expr (t);
406638fd1498Szrj tree v = create_tmp_var (TREE_TYPE (t), NULL);
406738fd1498Szrj expand_omp_build_assign (&gsif, v, t);
406838fd1498Szrj if (itercnt == NULL_TREE)
406938fd1498Szrj {
407038fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
407138fd1498Szrj {
407238fd1498Szrj itercntbias
407338fd1498Szrj = fold_build2 (MINUS_EXPR, itype, fold_convert (itype, n1),
407438fd1498Szrj fold_convert (itype, fd->loop.n1));
407538fd1498Szrj itercntbias = fold_build2 (EXACT_DIV_EXPR, itype,
407638fd1498Szrj itercntbias, step);
407738fd1498Szrj itercntbias
407838fd1498Szrj = force_gimple_operand_gsi (&gsif, itercntbias, true,
407938fd1498Szrj NULL_TREE, true,
408038fd1498Szrj GSI_SAME_STMT);
408138fd1498Szrj itercnt = fold_build2 (PLUS_EXPR, itype, itercntbias, s0);
408238fd1498Szrj itercnt = force_gimple_operand_gsi (&gsi, itercnt, true,
408338fd1498Szrj NULL_TREE, false,
408438fd1498Szrj GSI_CONTINUE_LINKING);
408538fd1498Szrj }
408638fd1498Szrj else
408738fd1498Szrj itercnt = s0;
408838fd1498Szrj }
408938fd1498Szrj a = fold_build2 (MULT_EXPR, type,
409038fd1498Szrj fold_convert (type, itercnt),
409138fd1498Szrj fold_convert (type, OMP_CLAUSE_LINEAR_STEP (c)));
409238fd1498Szrj t = fold_build2 (type == TREE_TYPE (t) ? PLUS_EXPR
409338fd1498Szrj : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a);
409438fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
409538fd1498Szrj false, GSI_CONTINUE_LINKING);
409638fd1498Szrj assign_stmt = gimple_build_assign (dest, t);
409738fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
409838fd1498Szrj }
409938fd1498Szrj if (fd->collapse > 1)
410038fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
410138fd1498Szrj
410238fd1498Szrj if (!broken_loop)
410338fd1498Szrj {
410438fd1498Szrj /* The code controlling the sequential loop goes in CONT_BB,
410538fd1498Szrj replacing the GIMPLE_OMP_CONTINUE. */
410638fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
410738fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
410838fd1498Szrj vmain = gimple_omp_continue_control_use (cont_stmt);
410938fd1498Szrj vback = gimple_omp_continue_control_def (cont_stmt);
411038fd1498Szrj
411138fd1498Szrj if (!gimple_omp_for_combined_p (fd->for_stmt))
411238fd1498Szrj {
411338fd1498Szrj if (POINTER_TYPE_P (type))
411438fd1498Szrj t = fold_build_pointer_plus (vmain, step);
411538fd1498Szrj else
411638fd1498Szrj t = fold_build2 (PLUS_EXPR, type, vmain, step);
411738fd1498Szrj if (DECL_P (vback) && TREE_ADDRESSABLE (vback))
411838fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
411938fd1498Szrj true, GSI_SAME_STMT);
412038fd1498Szrj assign_stmt = gimple_build_assign (vback, t);
412138fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
412238fd1498Szrj
412338fd1498Szrj if (tree_int_cst_equal (fd->chunk_size, integer_one_node))
412438fd1498Szrj t = build2 (EQ_EXPR, boolean_type_node,
412538fd1498Szrj build_int_cst (itype, 0),
412638fd1498Szrj build_int_cst (itype, 1));
412738fd1498Szrj else
412838fd1498Szrj t = build2 (fd->loop.cond_code, boolean_type_node,
412938fd1498Szrj DECL_P (vback) && TREE_ADDRESSABLE (vback)
413038fd1498Szrj ? t : vback, e);
413138fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
413238fd1498Szrj }
413338fd1498Szrj
413438fd1498Szrj /* Remove GIMPLE_OMP_CONTINUE. */
413538fd1498Szrj gsi_remove (&gsi, true);
413638fd1498Szrj
413738fd1498Szrj if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
413838fd1498Szrj collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb);
413938fd1498Szrj
414038fd1498Szrj /* Trip update code goes into TRIP_UPDATE_BB. */
414138fd1498Szrj gsi = gsi_start_bb (trip_update_bb);
414238fd1498Szrj
414338fd1498Szrj t = build_int_cst (itype, 1);
414438fd1498Szrj t = build2 (PLUS_EXPR, itype, trip_main, t);
414538fd1498Szrj assign_stmt = gimple_build_assign (trip_back, t);
414638fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
414738fd1498Szrj }
414838fd1498Szrj
414938fd1498Szrj /* Replace the GIMPLE_OMP_RETURN with a barrier, or nothing. */
415038fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
415138fd1498Szrj if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
415238fd1498Szrj {
415338fd1498Szrj t = gimple_omp_return_lhs (gsi_stmt (gsi));
415438fd1498Szrj gsi_insert_after (&gsi, omp_build_barrier (t), GSI_SAME_STMT);
415538fd1498Szrj }
415638fd1498Szrj gsi_remove (&gsi, true);
415738fd1498Szrj
415838fd1498Szrj /* Connect the new blocks. */
415938fd1498Szrj find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
416038fd1498Szrj find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
416138fd1498Szrj
416238fd1498Szrj if (!broken_loop)
416338fd1498Szrj {
416438fd1498Szrj se = find_edge (cont_bb, body_bb);
416538fd1498Szrj if (se == NULL)
416638fd1498Szrj {
416738fd1498Szrj se = BRANCH_EDGE (cont_bb);
416838fd1498Szrj gcc_assert (single_succ (se->dest) == body_bb);
416938fd1498Szrj }
417038fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
417138fd1498Szrj {
417238fd1498Szrj remove_edge (se);
417338fd1498Szrj se = NULL;
417438fd1498Szrj }
417538fd1498Szrj else if (fd->collapse > 1)
417638fd1498Szrj {
417738fd1498Szrj remove_edge (se);
417838fd1498Szrj se = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
417938fd1498Szrj }
418038fd1498Szrj else
418138fd1498Szrj se->flags = EDGE_TRUE_VALUE;
418238fd1498Szrj find_edge (cont_bb, trip_update_bb)->flags
418338fd1498Szrj = se ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
418438fd1498Szrj
418538fd1498Szrj redirect_edge_and_branch (single_succ_edge (trip_update_bb),
418638fd1498Szrj iter_part_bb);
418738fd1498Szrj }
418838fd1498Szrj
418938fd1498Szrj if (gimple_in_ssa_p (cfun))
419038fd1498Szrj {
419138fd1498Szrj gphi_iterator psi;
419238fd1498Szrj gphi *phi;
419338fd1498Szrj edge re, ene;
419438fd1498Szrj edge_var_map *vm;
419538fd1498Szrj size_t i;
419638fd1498Szrj
419738fd1498Szrj gcc_assert (fd->collapse == 1 && !broken_loop);
419838fd1498Szrj
419938fd1498Szrj /* When we redirect the edge from trip_update_bb to iter_part_bb, we
420038fd1498Szrj remove arguments of the phi nodes in fin_bb. We need to create
420138fd1498Szrj appropriate phi nodes in iter_part_bb instead. */
420238fd1498Szrj se = find_edge (iter_part_bb, fin_bb);
420338fd1498Szrj re = single_succ_edge (trip_update_bb);
420438fd1498Szrj vec<edge_var_map> *head = redirect_edge_var_map_vector (re);
420538fd1498Szrj ene = single_succ_edge (entry_bb);
420638fd1498Szrj
420738fd1498Szrj psi = gsi_start_phis (fin_bb);
420838fd1498Szrj for (i = 0; !gsi_end_p (psi) && head->iterate (i, &vm);
420938fd1498Szrj gsi_next (&psi), ++i)
421038fd1498Szrj {
421138fd1498Szrj gphi *nphi;
421238fd1498Szrj source_location locus;
421338fd1498Szrj
421438fd1498Szrj phi = psi.phi ();
421538fd1498Szrj if (operand_equal_p (gimple_phi_arg_def (phi, 0),
421638fd1498Szrj redirect_edge_var_map_def (vm), 0))
421738fd1498Szrj continue;
421838fd1498Szrj
421938fd1498Szrj t = gimple_phi_result (phi);
422038fd1498Szrj gcc_assert (t == redirect_edge_var_map_result (vm));
422138fd1498Szrj
422238fd1498Szrj if (!single_pred_p (fin_bb))
422338fd1498Szrj t = copy_ssa_name (t, phi);
422438fd1498Szrj
422538fd1498Szrj nphi = create_phi_node (t, iter_part_bb);
422638fd1498Szrj
422738fd1498Szrj t = PHI_ARG_DEF_FROM_EDGE (phi, se);
422838fd1498Szrj locus = gimple_phi_arg_location_from_edge (phi, se);
422938fd1498Szrj
423038fd1498Szrj /* A special case -- fd->loop.v is not yet computed in
423138fd1498Szrj iter_part_bb, we need to use vextra instead. */
423238fd1498Szrj if (t == fd->loop.v)
423338fd1498Szrj t = vextra;
423438fd1498Szrj add_phi_arg (nphi, t, ene, locus);
423538fd1498Szrj locus = redirect_edge_var_map_location (vm);
423638fd1498Szrj tree back_arg = redirect_edge_var_map_def (vm);
423738fd1498Szrj add_phi_arg (nphi, back_arg, re, locus);
423838fd1498Szrj edge ce = find_edge (cont_bb, body_bb);
423938fd1498Szrj if (ce == NULL)
424038fd1498Szrj {
424138fd1498Szrj ce = BRANCH_EDGE (cont_bb);
424238fd1498Szrj gcc_assert (single_succ (ce->dest) == body_bb);
424338fd1498Szrj ce = single_succ_edge (ce->dest);
424438fd1498Szrj }
424538fd1498Szrj gphi *inner_loop_phi = find_phi_with_arg_on_edge (back_arg, ce);
424638fd1498Szrj gcc_assert (inner_loop_phi != NULL);
424738fd1498Szrj add_phi_arg (inner_loop_phi, gimple_phi_result (nphi),
424838fd1498Szrj find_edge (seq_start_bb, body_bb), locus);
424938fd1498Szrj
425038fd1498Szrj if (!single_pred_p (fin_bb))
425138fd1498Szrj add_phi_arg (phi, gimple_phi_result (nphi), se, locus);
425238fd1498Szrj }
425338fd1498Szrj gcc_assert (gsi_end_p (psi) && (head == NULL || i == head->length ()));
425438fd1498Szrj redirect_edge_var_map_clear (re);
425538fd1498Szrj if (single_pred_p (fin_bb))
425638fd1498Szrj while (1)
425738fd1498Szrj {
425838fd1498Szrj psi = gsi_start_phis (fin_bb);
425938fd1498Szrj if (gsi_end_p (psi))
426038fd1498Szrj break;
426138fd1498Szrj remove_phi_node (&psi, false);
426238fd1498Szrj }
426338fd1498Szrj
426438fd1498Szrj /* Make phi node for trip. */
426538fd1498Szrj phi = create_phi_node (trip_main, iter_part_bb);
426638fd1498Szrj add_phi_arg (phi, trip_back, single_succ_edge (trip_update_bb),
426738fd1498Szrj UNKNOWN_LOCATION);
426838fd1498Szrj add_phi_arg (phi, trip_init, single_succ_edge (entry_bb),
426938fd1498Szrj UNKNOWN_LOCATION);
427038fd1498Szrj }
427138fd1498Szrj
427238fd1498Szrj if (!broken_loop)
427338fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
427438fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, iter_part_bb,
427538fd1498Szrj recompute_dominator (CDI_DOMINATORS, iter_part_bb));
427638fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, fin_bb,
427738fd1498Szrj recompute_dominator (CDI_DOMINATORS, fin_bb));
427838fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, seq_start_bb,
427938fd1498Szrj recompute_dominator (CDI_DOMINATORS, seq_start_bb));
428038fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, body_bb,
428138fd1498Szrj recompute_dominator (CDI_DOMINATORS, body_bb));
428238fd1498Szrj
428338fd1498Szrj if (!broken_loop)
428438fd1498Szrj {
428538fd1498Szrj struct loop *loop = body_bb->loop_father;
428638fd1498Szrj struct loop *trip_loop = alloc_loop ();
428738fd1498Szrj trip_loop->header = iter_part_bb;
428838fd1498Szrj trip_loop->latch = trip_update_bb;
428938fd1498Szrj add_loop (trip_loop, iter_part_bb->loop_father);
429038fd1498Szrj
429138fd1498Szrj if (loop != entry_bb->loop_father)
429238fd1498Szrj {
429338fd1498Szrj gcc_assert (loop->header == body_bb);
429438fd1498Szrj gcc_assert (loop->latch == region->cont
429538fd1498Szrj || single_pred (loop->latch) == region->cont);
429638fd1498Szrj trip_loop->inner = loop;
429738fd1498Szrj return;
429838fd1498Szrj }
429938fd1498Szrj
430038fd1498Szrj if (!gimple_omp_for_combined_p (fd->for_stmt))
430138fd1498Szrj {
430238fd1498Szrj loop = alloc_loop ();
430338fd1498Szrj loop->header = body_bb;
430438fd1498Szrj if (collapse_bb == NULL)
430538fd1498Szrj loop->latch = cont_bb;
430638fd1498Szrj add_loop (loop, trip_loop);
430738fd1498Szrj }
430838fd1498Szrj }
430938fd1498Szrj }
431038fd1498Szrj
431138fd1498Szrj /* A subroutine of expand_omp_for. Generate code for a simd non-worksharing
431238fd1498Szrj loop. Given parameters:
431338fd1498Szrj
431438fd1498Szrj for (V = N1; V cond N2; V += STEP) BODY;
431538fd1498Szrj
431638fd1498Szrj where COND is "<" or ">", we generate pseudocode
431738fd1498Szrj
431838fd1498Szrj V = N1;
431938fd1498Szrj goto L1;
432038fd1498Szrj L0:
432138fd1498Szrj BODY;
432238fd1498Szrj V += STEP;
432338fd1498Szrj L1:
432438fd1498Szrj if (V cond N2) goto L0; else goto L2;
432538fd1498Szrj L2:
432638fd1498Szrj
432738fd1498Szrj For collapsed loops, given parameters:
432838fd1498Szrj collapse(3)
432938fd1498Szrj for (V1 = N11; V1 cond1 N12; V1 += STEP1)
433038fd1498Szrj for (V2 = N21; V2 cond2 N22; V2 += STEP2)
433138fd1498Szrj for (V3 = N31; V3 cond3 N32; V3 += STEP3)
433238fd1498Szrj BODY;
433338fd1498Szrj
433438fd1498Szrj we generate pseudocode
433538fd1498Szrj
433638fd1498Szrj if (cond3 is <)
433738fd1498Szrj adj = STEP3 - 1;
433838fd1498Szrj else
433938fd1498Szrj adj = STEP3 + 1;
434038fd1498Szrj count3 = (adj + N32 - N31) / STEP3;
434138fd1498Szrj if (cond2 is <)
434238fd1498Szrj adj = STEP2 - 1;
434338fd1498Szrj else
434438fd1498Szrj adj = STEP2 + 1;
434538fd1498Szrj count2 = (adj + N22 - N21) / STEP2;
434638fd1498Szrj if (cond1 is <)
434738fd1498Szrj adj = STEP1 - 1;
434838fd1498Szrj else
434938fd1498Szrj adj = STEP1 + 1;
435038fd1498Szrj count1 = (adj + N12 - N11) / STEP1;
435138fd1498Szrj count = count1 * count2 * count3;
435238fd1498Szrj V = 0;
435338fd1498Szrj V1 = N11;
435438fd1498Szrj V2 = N21;
435538fd1498Szrj V3 = N31;
435638fd1498Szrj goto L1;
435738fd1498Szrj L0:
435838fd1498Szrj BODY;
435938fd1498Szrj V += 1;
436038fd1498Szrj V3 += STEP3;
436138fd1498Szrj V2 += (V3 cond3 N32) ? 0 : STEP2;
436238fd1498Szrj V3 = (V3 cond3 N32) ? V3 : N31;
436338fd1498Szrj V1 += (V2 cond2 N22) ? 0 : STEP1;
436438fd1498Szrj V2 = (V2 cond2 N22) ? V2 : N21;
436538fd1498Szrj L1:
436638fd1498Szrj if (V < count) goto L0; else goto L2;
436738fd1498Szrj L2:
436838fd1498Szrj
436938fd1498Szrj */
437038fd1498Szrj
437138fd1498Szrj static void
expand_omp_simd(struct omp_region * region,struct omp_for_data * fd)437238fd1498Szrj expand_omp_simd (struct omp_region *region, struct omp_for_data *fd)
437338fd1498Szrj {
437438fd1498Szrj tree type, t;
437538fd1498Szrj basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb, l2_bb, l2_dom_bb;
437638fd1498Szrj gimple_stmt_iterator gsi;
437738fd1498Szrj gimple *stmt;
437838fd1498Szrj gcond *cond_stmt;
437938fd1498Szrj bool broken_loop = region->cont == NULL;
438038fd1498Szrj edge e, ne;
438138fd1498Szrj tree *counts = NULL;
438238fd1498Szrj int i;
438338fd1498Szrj int safelen_int = INT_MAX;
438438fd1498Szrj tree safelen = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
438538fd1498Szrj OMP_CLAUSE_SAFELEN);
438638fd1498Szrj tree simduid = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
438738fd1498Szrj OMP_CLAUSE__SIMDUID_);
438838fd1498Szrj tree n1, n2;
438938fd1498Szrj
439038fd1498Szrj if (safelen)
439138fd1498Szrj {
439238fd1498Szrj poly_uint64 val;
439338fd1498Szrj safelen = OMP_CLAUSE_SAFELEN_EXPR (safelen);
439438fd1498Szrj if (!poly_int_tree_p (safelen, &val))
439538fd1498Szrj safelen_int = 0;
439638fd1498Szrj else
439738fd1498Szrj safelen_int = MIN (constant_lower_bound (val), INT_MAX);
439838fd1498Szrj if (safelen_int == 1)
439938fd1498Szrj safelen_int = 0;
440038fd1498Szrj }
440138fd1498Szrj type = TREE_TYPE (fd->loop.v);
440238fd1498Szrj entry_bb = region->entry;
440338fd1498Szrj cont_bb = region->cont;
440438fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
440538fd1498Szrj gcc_assert (broken_loop
440638fd1498Szrj || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
440738fd1498Szrj l0_bb = FALLTHRU_EDGE (entry_bb)->dest;
440838fd1498Szrj if (!broken_loop)
440938fd1498Szrj {
441038fd1498Szrj gcc_assert (BRANCH_EDGE (cont_bb)->dest == l0_bb);
441138fd1498Szrj gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
441238fd1498Szrj l1_bb = split_block (cont_bb, last_stmt (cont_bb))->dest;
441338fd1498Szrj l2_bb = BRANCH_EDGE (entry_bb)->dest;
441438fd1498Szrj }
441538fd1498Szrj else
441638fd1498Szrj {
441738fd1498Szrj BRANCH_EDGE (entry_bb)->flags &= ~EDGE_ABNORMAL;
441838fd1498Szrj l1_bb = split_edge (BRANCH_EDGE (entry_bb));
441938fd1498Szrj l2_bb = single_succ (l1_bb);
442038fd1498Szrj }
442138fd1498Szrj exit_bb = region->exit;
442238fd1498Szrj l2_dom_bb = NULL;
442338fd1498Szrj
442438fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
442538fd1498Szrj
442638fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
442738fd1498Szrj /* Not needed in SSA form right now. */
442838fd1498Szrj gcc_assert (!gimple_in_ssa_p (cfun));
442938fd1498Szrj if (fd->collapse > 1)
443038fd1498Szrj {
443138fd1498Szrj int first_zero_iter = -1, dummy = -1;
443238fd1498Szrj basic_block zero_iter_bb = l2_bb, dummy_bb = NULL;
443338fd1498Szrj
443438fd1498Szrj counts = XALLOCAVEC (tree, fd->collapse);
443538fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
443638fd1498Szrj zero_iter_bb, first_zero_iter,
443738fd1498Szrj dummy_bb, dummy, l2_dom_bb);
443838fd1498Szrj }
443938fd1498Szrj if (l2_dom_bb == NULL)
444038fd1498Szrj l2_dom_bb = l1_bb;
444138fd1498Szrj
444238fd1498Szrj n1 = fd->loop.n1;
444338fd1498Szrj n2 = fd->loop.n2;
444438fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
444538fd1498Szrj {
444638fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
444738fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
444838fd1498Szrj gcc_assert (innerc);
444938fd1498Szrj n1 = OMP_CLAUSE_DECL (innerc);
445038fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
445138fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
445238fd1498Szrj gcc_assert (innerc);
445338fd1498Szrj n2 = OMP_CLAUSE_DECL (innerc);
445438fd1498Szrj }
445538fd1498Szrj tree step = fd->loop.step;
445638fd1498Szrj
445738fd1498Szrj bool is_simt = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
445838fd1498Szrj OMP_CLAUSE__SIMT_);
445938fd1498Szrj if (is_simt)
446038fd1498Szrj {
446138fd1498Szrj cfun->curr_properties &= ~PROP_gimple_lomp_dev;
446238fd1498Szrj is_simt = safelen_int > 1;
446338fd1498Szrj }
446438fd1498Szrj tree simt_lane = NULL_TREE, simt_maxlane = NULL_TREE;
446538fd1498Szrj if (is_simt)
446638fd1498Szrj {
446738fd1498Szrj simt_lane = create_tmp_var (unsigned_type_node);
446838fd1498Szrj gimple *g = gimple_build_call_internal (IFN_GOMP_SIMT_LANE, 0);
446938fd1498Szrj gimple_call_set_lhs (g, simt_lane);
447038fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
447138fd1498Szrj tree offset = fold_build2 (MULT_EXPR, TREE_TYPE (step), step,
447238fd1498Szrj fold_convert (TREE_TYPE (step), simt_lane));
447338fd1498Szrj n1 = fold_convert (type, n1);
447438fd1498Szrj if (POINTER_TYPE_P (type))
447538fd1498Szrj n1 = fold_build_pointer_plus (n1, offset);
447638fd1498Szrj else
447738fd1498Szrj n1 = fold_build2 (PLUS_EXPR, type, n1, fold_convert (type, offset));
447838fd1498Szrj
447938fd1498Szrj /* Collapsed loops not handled for SIMT yet: limit to one lane only. */
448038fd1498Szrj if (fd->collapse > 1)
448138fd1498Szrj simt_maxlane = build_one_cst (unsigned_type_node);
448238fd1498Szrj else if (safelen_int < omp_max_simt_vf ())
448338fd1498Szrj simt_maxlane = build_int_cst (unsigned_type_node, safelen_int);
448438fd1498Szrj tree vf
448538fd1498Szrj = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_GOMP_SIMT_VF,
448638fd1498Szrj unsigned_type_node, 0);
448738fd1498Szrj if (simt_maxlane)
448838fd1498Szrj vf = fold_build2 (MIN_EXPR, unsigned_type_node, vf, simt_maxlane);
448938fd1498Szrj vf = fold_convert (TREE_TYPE (step), vf);
449038fd1498Szrj step = fold_build2 (MULT_EXPR, TREE_TYPE (step), step, vf);
449138fd1498Szrj }
449238fd1498Szrj
449338fd1498Szrj expand_omp_build_assign (&gsi, fd->loop.v, fold_convert (type, n1));
449438fd1498Szrj if (fd->collapse > 1)
449538fd1498Szrj {
449638fd1498Szrj if (gimple_omp_for_combined_into_p (fd->for_stmt))
449738fd1498Szrj {
449838fd1498Szrj gsi_prev (&gsi);
449938fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, NULL, n1);
450038fd1498Szrj gsi_next (&gsi);
450138fd1498Szrj }
450238fd1498Szrj else
450338fd1498Szrj for (i = 0; i < fd->collapse; i++)
450438fd1498Szrj {
450538fd1498Szrj tree itype = TREE_TYPE (fd->loops[i].v);
450638fd1498Szrj if (POINTER_TYPE_P (itype))
450738fd1498Szrj itype = signed_type_for (itype);
450838fd1498Szrj t = fold_convert (TREE_TYPE (fd->loops[i].v), fd->loops[i].n1);
450938fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v, t);
451038fd1498Szrj }
451138fd1498Szrj }
451238fd1498Szrj
451338fd1498Szrj /* Remove the GIMPLE_OMP_FOR statement. */
451438fd1498Szrj gsi_remove (&gsi, true);
451538fd1498Szrj
451638fd1498Szrj if (!broken_loop)
451738fd1498Szrj {
451838fd1498Szrj /* Code to control the increment goes in the CONT_BB. */
451938fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
452038fd1498Szrj stmt = gsi_stmt (gsi);
452138fd1498Szrj gcc_assert (gimple_code (stmt) == GIMPLE_OMP_CONTINUE);
452238fd1498Szrj
452338fd1498Szrj if (POINTER_TYPE_P (type))
452438fd1498Szrj t = fold_build_pointer_plus (fd->loop.v, step);
452538fd1498Szrj else
452638fd1498Szrj t = fold_build2 (PLUS_EXPR, type, fd->loop.v, step);
452738fd1498Szrj expand_omp_build_assign (&gsi, fd->loop.v, t);
452838fd1498Szrj
452938fd1498Szrj if (fd->collapse > 1)
453038fd1498Szrj {
453138fd1498Szrj i = fd->collapse - 1;
453238fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)))
453338fd1498Szrj {
453438fd1498Szrj t = fold_convert (sizetype, fd->loops[i].step);
453538fd1498Szrj t = fold_build_pointer_plus (fd->loops[i].v, t);
453638fd1498Szrj }
453738fd1498Szrj else
453838fd1498Szrj {
453938fd1498Szrj t = fold_convert (TREE_TYPE (fd->loops[i].v),
454038fd1498Szrj fd->loops[i].step);
454138fd1498Szrj t = fold_build2 (PLUS_EXPR, TREE_TYPE (fd->loops[i].v),
454238fd1498Szrj fd->loops[i].v, t);
454338fd1498Szrj }
454438fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v, t);
454538fd1498Szrj
454638fd1498Szrj for (i = fd->collapse - 1; i > 0; i--)
454738fd1498Szrj {
454838fd1498Szrj tree itype = TREE_TYPE (fd->loops[i].v);
454938fd1498Szrj tree itype2 = TREE_TYPE (fd->loops[i - 1].v);
455038fd1498Szrj if (POINTER_TYPE_P (itype2))
455138fd1498Szrj itype2 = signed_type_for (itype2);
455238fd1498Szrj t = fold_convert (itype2, fd->loops[i - 1].step);
455338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true,
455438fd1498Szrj GSI_SAME_STMT);
455538fd1498Szrj t = build3 (COND_EXPR, itype2,
455638fd1498Szrj build2 (fd->loops[i].cond_code, boolean_type_node,
455738fd1498Szrj fd->loops[i].v,
455838fd1498Szrj fold_convert (itype, fd->loops[i].n2)),
455938fd1498Szrj build_int_cst (itype2, 0), t);
456038fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i - 1].v)))
456138fd1498Szrj t = fold_build_pointer_plus (fd->loops[i - 1].v, t);
456238fd1498Szrj else
456338fd1498Szrj t = fold_build2 (PLUS_EXPR, itype2, fd->loops[i - 1].v, t);
456438fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i - 1].v, t);
456538fd1498Szrj
456638fd1498Szrj t = fold_convert (itype, fd->loops[i].n1);
456738fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, true,
456838fd1498Szrj GSI_SAME_STMT);
456938fd1498Szrj t = build3 (COND_EXPR, itype,
457038fd1498Szrj build2 (fd->loops[i].cond_code, boolean_type_node,
457138fd1498Szrj fd->loops[i].v,
457238fd1498Szrj fold_convert (itype, fd->loops[i].n2)),
457338fd1498Szrj fd->loops[i].v, t);
457438fd1498Szrj expand_omp_build_assign (&gsi, fd->loops[i].v, t);
457538fd1498Szrj }
457638fd1498Szrj }
457738fd1498Szrj
457838fd1498Szrj /* Remove GIMPLE_OMP_CONTINUE. */
457938fd1498Szrj gsi_remove (&gsi, true);
458038fd1498Szrj }
458138fd1498Szrj
458238fd1498Szrj /* Emit the condition in L1_BB. */
458338fd1498Szrj gsi = gsi_start_bb (l1_bb);
458438fd1498Szrj
458538fd1498Szrj t = fold_convert (type, n2);
458638fd1498Szrj t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
458738fd1498Szrj false, GSI_CONTINUE_LINKING);
458838fd1498Szrj tree v = fd->loop.v;
458938fd1498Szrj if (DECL_P (v) && TREE_ADDRESSABLE (v))
459038fd1498Szrj v = force_gimple_operand_gsi (&gsi, v, true, NULL_TREE,
459138fd1498Szrj false, GSI_CONTINUE_LINKING);
459238fd1498Szrj t = build2 (fd->loop.cond_code, boolean_type_node, v, t);
459338fd1498Szrj cond_stmt = gimple_build_cond_empty (t);
459438fd1498Szrj gsi_insert_after (&gsi, cond_stmt, GSI_CONTINUE_LINKING);
459538fd1498Szrj if (walk_tree (gimple_cond_lhs_ptr (cond_stmt), expand_omp_regimplify_p,
459638fd1498Szrj NULL, NULL)
459738fd1498Szrj || walk_tree (gimple_cond_rhs_ptr (cond_stmt), expand_omp_regimplify_p,
459838fd1498Szrj NULL, NULL))
459938fd1498Szrj {
460038fd1498Szrj gsi = gsi_for_stmt (cond_stmt);
460138fd1498Szrj gimple_regimplify_operands (cond_stmt, &gsi);
460238fd1498Szrj }
460338fd1498Szrj
460438fd1498Szrj /* Add 'V -= STEP * (SIMT_VF - 1)' after the loop. */
460538fd1498Szrj if (is_simt)
460638fd1498Szrj {
460738fd1498Szrj gsi = gsi_start_bb (l2_bb);
460838fd1498Szrj step = fold_build2 (MINUS_EXPR, TREE_TYPE (step), fd->loop.step, step);
460938fd1498Szrj if (POINTER_TYPE_P (type))
461038fd1498Szrj t = fold_build_pointer_plus (fd->loop.v, step);
461138fd1498Szrj else
461238fd1498Szrj t = fold_build2 (PLUS_EXPR, type, fd->loop.v, step);
461338fd1498Szrj expand_omp_build_assign (&gsi, fd->loop.v, t);
461438fd1498Szrj }
461538fd1498Szrj
461638fd1498Szrj /* Remove GIMPLE_OMP_RETURN. */
461738fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
461838fd1498Szrj gsi_remove (&gsi, true);
461938fd1498Szrj
462038fd1498Szrj /* Connect the new blocks. */
462138fd1498Szrj remove_edge (FALLTHRU_EDGE (entry_bb));
462238fd1498Szrj
462338fd1498Szrj if (!broken_loop)
462438fd1498Szrj {
462538fd1498Szrj remove_edge (BRANCH_EDGE (entry_bb));
462638fd1498Szrj make_edge (entry_bb, l1_bb, EDGE_FALLTHRU);
462738fd1498Szrj
462838fd1498Szrj e = BRANCH_EDGE (l1_bb);
462938fd1498Szrj ne = FALLTHRU_EDGE (l1_bb);
463038fd1498Szrj e->flags = EDGE_TRUE_VALUE;
463138fd1498Szrj }
463238fd1498Szrj else
463338fd1498Szrj {
463438fd1498Szrj single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
463538fd1498Szrj
463638fd1498Szrj ne = single_succ_edge (l1_bb);
463738fd1498Szrj e = make_edge (l1_bb, l0_bb, EDGE_TRUE_VALUE);
463838fd1498Szrj
463938fd1498Szrj }
464038fd1498Szrj ne->flags = EDGE_FALSE_VALUE;
464138fd1498Szrj e->probability = profile_probability::guessed_always ().apply_scale (7, 8);
464238fd1498Szrj ne->probability = e->probability.invert ();
464338fd1498Szrj
464438fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l1_bb, entry_bb);
464538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l0_bb, l1_bb);
464638fd1498Szrj
464738fd1498Szrj if (simt_maxlane)
464838fd1498Szrj {
464938fd1498Szrj cond_stmt = gimple_build_cond (LT_EXPR, simt_lane, simt_maxlane,
465038fd1498Szrj NULL_TREE, NULL_TREE);
465138fd1498Szrj gsi = gsi_last_bb (entry_bb);
465238fd1498Szrj gsi_insert_after (&gsi, cond_stmt, GSI_NEW_STMT);
465338fd1498Szrj make_edge (entry_bb, l2_bb, EDGE_FALSE_VALUE);
465438fd1498Szrj FALLTHRU_EDGE (entry_bb)->flags = EDGE_TRUE_VALUE;
465538fd1498Szrj FALLTHRU_EDGE (entry_bb)->probability
465638fd1498Szrj = profile_probability::guessed_always ().apply_scale (7, 8);
465738fd1498Szrj BRANCH_EDGE (entry_bb)->probability
465838fd1498Szrj = FALLTHRU_EDGE (entry_bb)->probability.invert ();
465938fd1498Szrj l2_dom_bb = entry_bb;
466038fd1498Szrj }
466138fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, l2_bb, l2_dom_bb);
466238fd1498Szrj
466338fd1498Szrj if (!broken_loop)
466438fd1498Szrj {
466538fd1498Szrj struct loop *loop = alloc_loop ();
466638fd1498Szrj loop->header = l1_bb;
466738fd1498Szrj loop->latch = cont_bb;
466838fd1498Szrj add_loop (loop, l1_bb->loop_father);
466938fd1498Szrj loop->safelen = safelen_int;
467038fd1498Szrj if (simduid)
467138fd1498Szrj {
467238fd1498Szrj loop->simduid = OMP_CLAUSE__SIMDUID__DECL (simduid);
467338fd1498Szrj cfun->has_simduid_loops = true;
467438fd1498Szrj }
467538fd1498Szrj /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
467638fd1498Szrj the loop. */
467738fd1498Szrj if ((flag_tree_loop_vectorize
467838fd1498Szrj || !global_options_set.x_flag_tree_loop_vectorize)
467938fd1498Szrj && flag_tree_loop_optimize
468038fd1498Szrj && loop->safelen > 1)
468138fd1498Szrj {
468238fd1498Szrj loop->force_vectorize = true;
468338fd1498Szrj cfun->has_force_vectorize_loops = true;
468438fd1498Szrj }
468538fd1498Szrj }
468638fd1498Szrj else if (simduid)
468738fd1498Szrj cfun->has_simduid_loops = true;
468838fd1498Szrj }
468938fd1498Szrj
469038fd1498Szrj /* Taskloop construct is represented after gimplification with
469138fd1498Szrj two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched
469238fd1498Szrj in between them. This routine expands the outer GIMPLE_OMP_FOR,
469338fd1498Szrj which should just compute all the needed loop temporaries
469438fd1498Szrj for GIMPLE_OMP_TASK. */
469538fd1498Szrj
469638fd1498Szrj static void
expand_omp_taskloop_for_outer(struct omp_region * region,struct omp_for_data * fd,gimple * inner_stmt)469738fd1498Szrj expand_omp_taskloop_for_outer (struct omp_region *region,
469838fd1498Szrj struct omp_for_data *fd,
469938fd1498Szrj gimple *inner_stmt)
470038fd1498Szrj {
470138fd1498Szrj tree type, bias = NULL_TREE;
470238fd1498Szrj basic_block entry_bb, cont_bb, exit_bb;
470338fd1498Szrj gimple_stmt_iterator gsi;
470438fd1498Szrj gassign *assign_stmt;
470538fd1498Szrj tree *counts = NULL;
470638fd1498Szrj int i;
470738fd1498Szrj
470838fd1498Szrj gcc_assert (inner_stmt);
470938fd1498Szrj gcc_assert (region->cont);
471038fd1498Szrj gcc_assert (gimple_code (inner_stmt) == GIMPLE_OMP_TASK
471138fd1498Szrj && gimple_omp_task_taskloop_p (inner_stmt));
471238fd1498Szrj type = TREE_TYPE (fd->loop.v);
471338fd1498Szrj
471438fd1498Szrj /* See if we need to bias by LLONG_MIN. */
471538fd1498Szrj if (fd->iter_type == long_long_unsigned_type_node
471638fd1498Szrj && TREE_CODE (type) == INTEGER_TYPE
471738fd1498Szrj && !TYPE_UNSIGNED (type))
471838fd1498Szrj {
471938fd1498Szrj tree n1, n2;
472038fd1498Szrj
472138fd1498Szrj if (fd->loop.cond_code == LT_EXPR)
472238fd1498Szrj {
472338fd1498Szrj n1 = fd->loop.n1;
472438fd1498Szrj n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
472538fd1498Szrj }
472638fd1498Szrj else
472738fd1498Szrj {
472838fd1498Szrj n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
472938fd1498Szrj n2 = fd->loop.n1;
473038fd1498Szrj }
473138fd1498Szrj if (TREE_CODE (n1) != INTEGER_CST
473238fd1498Szrj || TREE_CODE (n2) != INTEGER_CST
473338fd1498Szrj || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
473438fd1498Szrj bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
473538fd1498Szrj }
473638fd1498Szrj
473738fd1498Szrj entry_bb = region->entry;
473838fd1498Szrj cont_bb = region->cont;
473938fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
474038fd1498Szrj gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
474138fd1498Szrj exit_bb = region->exit;
474238fd1498Szrj
474338fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
474438fd1498Szrj gimple *for_stmt = gsi_stmt (gsi);
474538fd1498Szrj gcc_assert (gimple_code (for_stmt) == GIMPLE_OMP_FOR);
474638fd1498Szrj if (fd->collapse > 1)
474738fd1498Szrj {
474838fd1498Szrj int first_zero_iter = -1, dummy = -1;
474938fd1498Szrj basic_block zero_iter_bb = NULL, dummy_bb = NULL, l2_dom_bb = NULL;
475038fd1498Szrj
475138fd1498Szrj counts = XALLOCAVEC (tree, fd->collapse);
475238fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
475338fd1498Szrj zero_iter_bb, first_zero_iter,
475438fd1498Szrj dummy_bb, dummy, l2_dom_bb);
475538fd1498Szrj
475638fd1498Szrj if (zero_iter_bb)
475738fd1498Szrj {
475838fd1498Szrj /* Some counts[i] vars might be uninitialized if
475938fd1498Szrj some loop has zero iterations. But the body shouldn't
476038fd1498Szrj be executed in that case, so just avoid uninit warnings. */
476138fd1498Szrj for (i = first_zero_iter; i < fd->collapse; i++)
476238fd1498Szrj if (SSA_VAR_P (counts[i]))
476338fd1498Szrj TREE_NO_WARNING (counts[i]) = 1;
476438fd1498Szrj gsi_prev (&gsi);
476538fd1498Szrj edge e = split_block (entry_bb, gsi_stmt (gsi));
476638fd1498Szrj entry_bb = e->dest;
476738fd1498Szrj make_edge (zero_iter_bb, entry_bb, EDGE_FALLTHRU);
476838fd1498Szrj gsi = gsi_last_bb (entry_bb);
476938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, entry_bb,
477038fd1498Szrj get_immediate_dominator (CDI_DOMINATORS,
477138fd1498Szrj zero_iter_bb));
477238fd1498Szrj }
477338fd1498Szrj }
477438fd1498Szrj
477538fd1498Szrj tree t0, t1;
477638fd1498Szrj t1 = fd->loop.n2;
477738fd1498Szrj t0 = fd->loop.n1;
477838fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (t0))
477938fd1498Szrj && TYPE_PRECISION (TREE_TYPE (t0))
478038fd1498Szrj != TYPE_PRECISION (fd->iter_type))
478138fd1498Szrj {
478238fd1498Szrj /* Avoid casting pointers to integer of a different size. */
478338fd1498Szrj tree itype = signed_type_for (type);
478438fd1498Szrj t1 = fold_convert (fd->iter_type, fold_convert (itype, t1));
478538fd1498Szrj t0 = fold_convert (fd->iter_type, fold_convert (itype, t0));
478638fd1498Szrj }
478738fd1498Szrj else
478838fd1498Szrj {
478938fd1498Szrj t1 = fold_convert (fd->iter_type, t1);
479038fd1498Szrj t0 = fold_convert (fd->iter_type, t0);
479138fd1498Szrj }
479238fd1498Szrj if (bias)
479338fd1498Szrj {
479438fd1498Szrj t1 = fold_build2 (PLUS_EXPR, fd->iter_type, t1, bias);
479538fd1498Szrj t0 = fold_build2 (PLUS_EXPR, fd->iter_type, t0, bias);
479638fd1498Szrj }
479738fd1498Szrj
479838fd1498Szrj tree innerc = omp_find_clause (gimple_omp_task_clauses (inner_stmt),
479938fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
480038fd1498Szrj gcc_assert (innerc);
480138fd1498Szrj tree startvar = OMP_CLAUSE_DECL (innerc);
480238fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_);
480338fd1498Szrj gcc_assert (innerc);
480438fd1498Szrj tree endvar = OMP_CLAUSE_DECL (innerc);
480538fd1498Szrj if (fd->collapse > 1 && TREE_CODE (fd->loop.n2) != INTEGER_CST)
480638fd1498Szrj {
480738fd1498Szrj gcc_assert (innerc);
480838fd1498Szrj for (i = 1; i < fd->collapse; i++)
480938fd1498Szrj {
481038fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
481138fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
481238fd1498Szrj gcc_assert (innerc);
481338fd1498Szrj }
481438fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
481538fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
481638fd1498Szrj if (innerc)
481738fd1498Szrj {
481838fd1498Szrj /* If needed (inner taskloop has lastprivate clause), propagate
481938fd1498Szrj down the total number of iterations. */
482038fd1498Szrj tree t = force_gimple_operand_gsi (&gsi, fd->loop.n2, false,
482138fd1498Szrj NULL_TREE, false,
482238fd1498Szrj GSI_CONTINUE_LINKING);
482338fd1498Szrj assign_stmt = gimple_build_assign (OMP_CLAUSE_DECL (innerc), t);
482438fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
482538fd1498Szrj }
482638fd1498Szrj }
482738fd1498Szrj
482838fd1498Szrj t0 = force_gimple_operand_gsi (&gsi, t0, false, NULL_TREE, false,
482938fd1498Szrj GSI_CONTINUE_LINKING);
483038fd1498Szrj assign_stmt = gimple_build_assign (startvar, t0);
483138fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
483238fd1498Szrj
483338fd1498Szrj t1 = force_gimple_operand_gsi (&gsi, t1, false, NULL_TREE, false,
483438fd1498Szrj GSI_CONTINUE_LINKING);
483538fd1498Szrj assign_stmt = gimple_build_assign (endvar, t1);
483638fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
483738fd1498Szrj if (fd->collapse > 1)
483838fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
483938fd1498Szrj
484038fd1498Szrj /* Remove the GIMPLE_OMP_FOR statement. */
484138fd1498Szrj gsi = gsi_for_stmt (for_stmt);
484238fd1498Szrj gsi_remove (&gsi, true);
484338fd1498Szrj
484438fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
484538fd1498Szrj gsi_remove (&gsi, true);
484638fd1498Szrj
484738fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
484838fd1498Szrj gsi_remove (&gsi, true);
484938fd1498Szrj
485038fd1498Szrj FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
485138fd1498Szrj remove_edge (BRANCH_EDGE (entry_bb));
485238fd1498Szrj FALLTHRU_EDGE (cont_bb)->probability = profile_probability::always ();
485338fd1498Szrj remove_edge (BRANCH_EDGE (cont_bb));
485438fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, exit_bb, cont_bb);
485538fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, region->entry,
485638fd1498Szrj recompute_dominator (CDI_DOMINATORS, region->entry));
485738fd1498Szrj }
485838fd1498Szrj
485938fd1498Szrj /* Taskloop construct is represented after gimplification with
486038fd1498Szrj two GIMPLE_OMP_FOR constructs with GIMPLE_OMP_TASK sandwiched
486138fd1498Szrj in between them. This routine expands the inner GIMPLE_OMP_FOR.
486238fd1498Szrj GOMP_taskloop{,_ull} function arranges for each task to be given just
486338fd1498Szrj a single range of iterations. */
486438fd1498Szrj
486538fd1498Szrj static void
expand_omp_taskloop_for_inner(struct omp_region * region,struct omp_for_data * fd,gimple * inner_stmt)486638fd1498Szrj expand_omp_taskloop_for_inner (struct omp_region *region,
486738fd1498Szrj struct omp_for_data *fd,
486838fd1498Szrj gimple *inner_stmt)
486938fd1498Szrj {
487038fd1498Szrj tree e, t, type, itype, vmain, vback, bias = NULL_TREE;
487138fd1498Szrj basic_block entry_bb, exit_bb, body_bb, cont_bb, collapse_bb = NULL;
487238fd1498Szrj basic_block fin_bb;
487338fd1498Szrj gimple_stmt_iterator gsi;
487438fd1498Szrj edge ep;
487538fd1498Szrj bool broken_loop = region->cont == NULL;
487638fd1498Szrj tree *counts = NULL;
487738fd1498Szrj tree n1, n2, step;
487838fd1498Szrj
487938fd1498Szrj itype = type = TREE_TYPE (fd->loop.v);
488038fd1498Szrj if (POINTER_TYPE_P (type))
488138fd1498Szrj itype = signed_type_for (type);
488238fd1498Szrj
488338fd1498Szrj /* See if we need to bias by LLONG_MIN. */
488438fd1498Szrj if (fd->iter_type == long_long_unsigned_type_node
488538fd1498Szrj && TREE_CODE (type) == INTEGER_TYPE
488638fd1498Szrj && !TYPE_UNSIGNED (type))
488738fd1498Szrj {
488838fd1498Szrj tree n1, n2;
488938fd1498Szrj
489038fd1498Szrj if (fd->loop.cond_code == LT_EXPR)
489138fd1498Szrj {
489238fd1498Szrj n1 = fd->loop.n1;
489338fd1498Szrj n2 = fold_build2 (PLUS_EXPR, type, fd->loop.n2, fd->loop.step);
489438fd1498Szrj }
489538fd1498Szrj else
489638fd1498Szrj {
489738fd1498Szrj n1 = fold_build2 (MINUS_EXPR, type, fd->loop.n2, fd->loop.step);
489838fd1498Szrj n2 = fd->loop.n1;
489938fd1498Szrj }
490038fd1498Szrj if (TREE_CODE (n1) != INTEGER_CST
490138fd1498Szrj || TREE_CODE (n2) != INTEGER_CST
490238fd1498Szrj || ((tree_int_cst_sgn (n1) < 0) ^ (tree_int_cst_sgn (n2) < 0)))
490338fd1498Szrj bias = fold_convert (fd->iter_type, TYPE_MIN_VALUE (type));
490438fd1498Szrj }
490538fd1498Szrj
490638fd1498Szrj entry_bb = region->entry;
490738fd1498Szrj cont_bb = region->cont;
490838fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
490938fd1498Szrj fin_bb = BRANCH_EDGE (entry_bb)->dest;
491038fd1498Szrj gcc_assert (broken_loop
491138fd1498Szrj || (fin_bb == FALLTHRU_EDGE (cont_bb)->dest));
491238fd1498Szrj body_bb = FALLTHRU_EDGE (entry_bb)->dest;
491338fd1498Szrj if (!broken_loop)
491438fd1498Szrj {
491538fd1498Szrj gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
491638fd1498Szrj gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
491738fd1498Szrj }
491838fd1498Szrj exit_bb = region->exit;
491938fd1498Szrj
492038fd1498Szrj /* Iteration space partitioning goes in ENTRY_BB. */
492138fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
492238fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
492338fd1498Szrj
492438fd1498Szrj if (fd->collapse > 1)
492538fd1498Szrj {
492638fd1498Szrj int first_zero_iter = -1, dummy = -1;
492738fd1498Szrj basic_block l2_dom_bb = NULL, dummy_bb = NULL;
492838fd1498Szrj
492938fd1498Szrj counts = XALLOCAVEC (tree, fd->collapse);
493038fd1498Szrj expand_omp_for_init_counts (fd, &gsi, entry_bb, counts,
493138fd1498Szrj fin_bb, first_zero_iter,
493238fd1498Szrj dummy_bb, dummy, l2_dom_bb);
493338fd1498Szrj t = NULL_TREE;
493438fd1498Szrj }
493538fd1498Szrj else
493638fd1498Szrj t = integer_one_node;
493738fd1498Szrj
493838fd1498Szrj step = fd->loop.step;
493938fd1498Szrj tree innerc = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
494038fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
494138fd1498Szrj gcc_assert (innerc);
494238fd1498Szrj n1 = OMP_CLAUSE_DECL (innerc);
494338fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc), OMP_CLAUSE__LOOPTEMP_);
494438fd1498Szrj gcc_assert (innerc);
494538fd1498Szrj n2 = OMP_CLAUSE_DECL (innerc);
494638fd1498Szrj if (bias)
494738fd1498Szrj {
494838fd1498Szrj n1 = fold_build2 (PLUS_EXPR, fd->iter_type, n1, bias);
494938fd1498Szrj n2 = fold_build2 (PLUS_EXPR, fd->iter_type, n2, bias);
495038fd1498Szrj }
495138fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
495238fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
495338fd1498Szrj n2 = force_gimple_operand_gsi (&gsi, fold_convert (itype, n2),
495438fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
495538fd1498Szrj step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
495638fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
495738fd1498Szrj
495838fd1498Szrj tree startvar = fd->loop.v;
495938fd1498Szrj tree endvar = NULL_TREE;
496038fd1498Szrj
496138fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
496238fd1498Szrj {
496338fd1498Szrj tree clauses = gimple_omp_for_clauses (inner_stmt);
496438fd1498Szrj tree innerc = omp_find_clause (clauses, OMP_CLAUSE__LOOPTEMP_);
496538fd1498Szrj gcc_assert (innerc);
496638fd1498Szrj startvar = OMP_CLAUSE_DECL (innerc);
496738fd1498Szrj innerc = omp_find_clause (OMP_CLAUSE_CHAIN (innerc),
496838fd1498Szrj OMP_CLAUSE__LOOPTEMP_);
496938fd1498Szrj gcc_assert (innerc);
497038fd1498Szrj endvar = OMP_CLAUSE_DECL (innerc);
497138fd1498Szrj }
497238fd1498Szrj t = fold_convert (TREE_TYPE (startvar), n1);
497338fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
497438fd1498Szrj DECL_P (startvar)
497538fd1498Szrj && TREE_ADDRESSABLE (startvar),
497638fd1498Szrj NULL_TREE, false, GSI_CONTINUE_LINKING);
497738fd1498Szrj gimple *assign_stmt = gimple_build_assign (startvar, t);
497838fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
497938fd1498Szrj
498038fd1498Szrj t = fold_convert (TREE_TYPE (startvar), n2);
498138fd1498Szrj e = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
498238fd1498Szrj false, GSI_CONTINUE_LINKING);
498338fd1498Szrj if (endvar)
498438fd1498Szrj {
498538fd1498Szrj assign_stmt = gimple_build_assign (endvar, e);
498638fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
498738fd1498Szrj if (useless_type_conversion_p (TREE_TYPE (fd->loop.v), TREE_TYPE (e)))
498838fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, e);
498938fd1498Szrj else
499038fd1498Szrj assign_stmt = gimple_build_assign (fd->loop.v, NOP_EXPR, e);
499138fd1498Szrj gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
499238fd1498Szrj }
499338fd1498Szrj if (fd->collapse > 1)
499438fd1498Szrj expand_omp_for_init_vars (fd, &gsi, counts, inner_stmt, startvar);
499538fd1498Szrj
499638fd1498Szrj if (!broken_loop)
499738fd1498Szrj {
499838fd1498Szrj /* The code controlling the sequential loop replaces the
499938fd1498Szrj GIMPLE_OMP_CONTINUE. */
500038fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
500138fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
500238fd1498Szrj gcc_assert (gimple_code (cont_stmt) == GIMPLE_OMP_CONTINUE);
500338fd1498Szrj vmain = gimple_omp_continue_control_use (cont_stmt);
500438fd1498Szrj vback = gimple_omp_continue_control_def (cont_stmt);
500538fd1498Szrj
500638fd1498Szrj if (!gimple_omp_for_combined_p (fd->for_stmt))
500738fd1498Szrj {
500838fd1498Szrj if (POINTER_TYPE_P (type))
500938fd1498Szrj t = fold_build_pointer_plus (vmain, step);
501038fd1498Szrj else
501138fd1498Szrj t = fold_build2 (PLUS_EXPR, type, vmain, step);
501238fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
501338fd1498Szrj DECL_P (vback)
501438fd1498Szrj && TREE_ADDRESSABLE (vback),
501538fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
501638fd1498Szrj assign_stmt = gimple_build_assign (vback, t);
501738fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
501838fd1498Szrj
501938fd1498Szrj t = build2 (fd->loop.cond_code, boolean_type_node,
502038fd1498Szrj DECL_P (vback) && TREE_ADDRESSABLE (vback)
502138fd1498Szrj ? t : vback, e);
502238fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (t), GSI_SAME_STMT);
502338fd1498Szrj }
502438fd1498Szrj
502538fd1498Szrj /* Remove the GIMPLE_OMP_CONTINUE statement. */
502638fd1498Szrj gsi_remove (&gsi, true);
502738fd1498Szrj
502838fd1498Szrj if (fd->collapse > 1 && !gimple_omp_for_combined_p (fd->for_stmt))
502938fd1498Szrj collapse_bb = extract_omp_for_update_vars (fd, cont_bb, body_bb);
503038fd1498Szrj }
503138fd1498Szrj
503238fd1498Szrj /* Remove the GIMPLE_OMP_FOR statement. */
503338fd1498Szrj gsi = gsi_for_stmt (fd->for_stmt);
503438fd1498Szrj gsi_remove (&gsi, true);
503538fd1498Szrj
503638fd1498Szrj /* Remove the GIMPLE_OMP_RETURN statement. */
503738fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
503838fd1498Szrj gsi_remove (&gsi, true);
503938fd1498Szrj
504038fd1498Szrj FALLTHRU_EDGE (entry_bb)->probability = profile_probability::always ();
504138fd1498Szrj if (!broken_loop)
504238fd1498Szrj remove_edge (BRANCH_EDGE (entry_bb));
504338fd1498Szrj else
504438fd1498Szrj {
504538fd1498Szrj remove_edge_and_dominated_blocks (BRANCH_EDGE (entry_bb));
504638fd1498Szrj region->outer->cont = NULL;
504738fd1498Szrj }
504838fd1498Szrj
504938fd1498Szrj /* Connect all the blocks. */
505038fd1498Szrj if (!broken_loop)
505138fd1498Szrj {
505238fd1498Szrj ep = find_edge (cont_bb, body_bb);
505338fd1498Szrj if (gimple_omp_for_combined_p (fd->for_stmt))
505438fd1498Szrj {
505538fd1498Szrj remove_edge (ep);
505638fd1498Szrj ep = NULL;
505738fd1498Szrj }
505838fd1498Szrj else if (fd->collapse > 1)
505938fd1498Szrj {
506038fd1498Szrj remove_edge (ep);
506138fd1498Szrj ep = make_edge (cont_bb, collapse_bb, EDGE_TRUE_VALUE);
506238fd1498Szrj }
506338fd1498Szrj else
506438fd1498Szrj ep->flags = EDGE_TRUE_VALUE;
506538fd1498Szrj find_edge (cont_bb, fin_bb)->flags
506638fd1498Szrj = ep ? EDGE_FALSE_VALUE : EDGE_FALLTHRU;
506738fd1498Szrj }
506838fd1498Szrj
506938fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, body_bb,
507038fd1498Szrj recompute_dominator (CDI_DOMINATORS, body_bb));
507138fd1498Szrj if (!broken_loop)
507238fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, fin_bb,
507338fd1498Szrj recompute_dominator (CDI_DOMINATORS, fin_bb));
507438fd1498Szrj
507538fd1498Szrj if (!broken_loop && !gimple_omp_for_combined_p (fd->for_stmt))
507638fd1498Szrj {
507738fd1498Szrj struct loop *loop = alloc_loop ();
507838fd1498Szrj loop->header = body_bb;
507938fd1498Szrj if (collapse_bb == NULL)
508038fd1498Szrj loop->latch = cont_bb;
508138fd1498Szrj add_loop (loop, body_bb->loop_father);
508238fd1498Szrj }
508338fd1498Szrj }
508438fd1498Szrj
508538fd1498Szrj /* A subroutine of expand_omp_for. Generate code for an OpenACC
508638fd1498Szrj partitioned loop. The lowering here is abstracted, in that the
508738fd1498Szrj loop parameters are passed through internal functions, which are
508838fd1498Szrj further lowered by oacc_device_lower, once we get to the target
508938fd1498Szrj compiler. The loop is of the form:
509038fd1498Szrj
509138fd1498Szrj for (V = B; V LTGT E; V += S) {BODY}
509238fd1498Szrj
509338fd1498Szrj where LTGT is < or >. We may have a specified chunking size, CHUNKING
509438fd1498Szrj (constant 0 for no chunking) and we will have a GWV partitioning
509538fd1498Szrj mask, specifying dimensions over which the loop is to be
509638fd1498Szrj partitioned (see note below). We generate code that looks like
509738fd1498Szrj (this ignores tiling):
509838fd1498Szrj
509938fd1498Szrj <entry_bb> [incoming FALL->body, BRANCH->exit]
510038fd1498Szrj typedef signedintify (typeof (V)) T; // underlying signed integral type
510138fd1498Szrj T range = E - B;
510238fd1498Szrj T chunk_no = 0;
510338fd1498Szrj T DIR = LTGT == '<' ? +1 : -1;
510438fd1498Szrj T chunk_max = GOACC_LOOP_CHUNK (dir, range, S, CHUNK_SIZE, GWV);
510538fd1498Szrj T step = GOACC_LOOP_STEP (dir, range, S, CHUNK_SIZE, GWV);
510638fd1498Szrj
510738fd1498Szrj <head_bb> [created by splitting end of entry_bb]
510838fd1498Szrj T offset = GOACC_LOOP_OFFSET (dir, range, S, CHUNK_SIZE, GWV, chunk_no);
510938fd1498Szrj T bound = GOACC_LOOP_BOUND (dir, range, S, CHUNK_SIZE, GWV, offset);
511038fd1498Szrj if (!(offset LTGT bound)) goto bottom_bb;
511138fd1498Szrj
511238fd1498Szrj <body_bb> [incoming]
511338fd1498Szrj V = B + offset;
511438fd1498Szrj {BODY}
511538fd1498Szrj
511638fd1498Szrj <cont_bb> [incoming, may == body_bb FALL->exit_bb, BRANCH->body_bb]
511738fd1498Szrj offset += step;
511838fd1498Szrj if (offset LTGT bound) goto body_bb; [*]
511938fd1498Szrj
512038fd1498Szrj <bottom_bb> [created by splitting start of exit_bb] insert BRANCH->head_bb
512138fd1498Szrj chunk_no++;
512238fd1498Szrj if (chunk < chunk_max) goto head_bb;
512338fd1498Szrj
512438fd1498Szrj <exit_bb> [incoming]
512538fd1498Szrj V = B + ((range -/+ 1) / S +/- 1) * S [*]
512638fd1498Szrj
512738fd1498Szrj [*] Needed if V live at end of loop. */
512838fd1498Szrj
512938fd1498Szrj static void
expand_oacc_for(struct omp_region * region,struct omp_for_data * fd)513038fd1498Szrj expand_oacc_for (struct omp_region *region, struct omp_for_data *fd)
513138fd1498Szrj {
513238fd1498Szrj tree v = fd->loop.v;
513338fd1498Szrj enum tree_code cond_code = fd->loop.cond_code;
513438fd1498Szrj enum tree_code plus_code = PLUS_EXPR;
513538fd1498Szrj
513638fd1498Szrj tree chunk_size = integer_minus_one_node;
513738fd1498Szrj tree gwv = integer_zero_node;
513838fd1498Szrj tree iter_type = TREE_TYPE (v);
513938fd1498Szrj tree diff_type = iter_type;
514038fd1498Szrj tree plus_type = iter_type;
514138fd1498Szrj struct oacc_collapse *counts = NULL;
514238fd1498Szrj
514338fd1498Szrj gcc_checking_assert (gimple_omp_for_kind (fd->for_stmt)
514438fd1498Szrj == GF_OMP_FOR_KIND_OACC_LOOP);
514538fd1498Szrj gcc_assert (!gimple_omp_for_combined_into_p (fd->for_stmt));
514638fd1498Szrj gcc_assert (cond_code == LT_EXPR || cond_code == GT_EXPR);
514738fd1498Szrj
514838fd1498Szrj if (POINTER_TYPE_P (iter_type))
514938fd1498Szrj {
515038fd1498Szrj plus_code = POINTER_PLUS_EXPR;
515138fd1498Szrj plus_type = sizetype;
515238fd1498Szrj }
515338fd1498Szrj if (POINTER_TYPE_P (diff_type) || TYPE_UNSIGNED (diff_type))
515438fd1498Szrj diff_type = signed_type_for (diff_type);
515538fd1498Szrj if (TYPE_PRECISION (diff_type) < TYPE_PRECISION (integer_type_node))
515638fd1498Szrj diff_type = integer_type_node;
515738fd1498Szrj
515838fd1498Szrj basic_block entry_bb = region->entry; /* BB ending in OMP_FOR */
515938fd1498Szrj basic_block exit_bb = region->exit; /* BB ending in OMP_RETURN */
516038fd1498Szrj basic_block cont_bb = region->cont; /* BB ending in OMP_CONTINUE */
516138fd1498Szrj basic_block bottom_bb = NULL;
516238fd1498Szrj
516338fd1498Szrj /* entry_bb has two sucessors; the branch edge is to the exit
516438fd1498Szrj block, fallthrough edge to body. */
516538fd1498Szrj gcc_assert (EDGE_COUNT (entry_bb->succs) == 2
516638fd1498Szrj && BRANCH_EDGE (entry_bb)->dest == exit_bb);
516738fd1498Szrj
516838fd1498Szrj /* If cont_bb non-NULL, it has 2 successors. The branch successor is
516938fd1498Szrj body_bb, or to a block whose only successor is the body_bb. Its
517038fd1498Szrj fallthrough successor is the final block (same as the branch
517138fd1498Szrj successor of the entry_bb). */
517238fd1498Szrj if (cont_bb)
517338fd1498Szrj {
517438fd1498Szrj basic_block body_bb = FALLTHRU_EDGE (entry_bb)->dest;
517538fd1498Szrj basic_block bed = BRANCH_EDGE (cont_bb)->dest;
517638fd1498Szrj
517738fd1498Szrj gcc_assert (FALLTHRU_EDGE (cont_bb)->dest == exit_bb);
517838fd1498Szrj gcc_assert (bed == body_bb || single_succ_edge (bed)->dest == body_bb);
517938fd1498Szrj }
518038fd1498Szrj else
518138fd1498Szrj gcc_assert (!gimple_in_ssa_p (cfun));
518238fd1498Szrj
518338fd1498Szrj /* The exit block only has entry_bb and cont_bb as predecessors. */
518438fd1498Szrj gcc_assert (EDGE_COUNT (exit_bb->preds) == 1 + (cont_bb != NULL));
518538fd1498Szrj
518638fd1498Szrj tree chunk_no;
518738fd1498Szrj tree chunk_max = NULL_TREE;
518838fd1498Szrj tree bound, offset;
518938fd1498Szrj tree step = create_tmp_var (diff_type, ".step");
519038fd1498Szrj bool up = cond_code == LT_EXPR;
519138fd1498Szrj tree dir = build_int_cst (diff_type, up ? +1 : -1);
519238fd1498Szrj bool chunking = !gimple_in_ssa_p (cfun);
519338fd1498Szrj bool negating;
519438fd1498Szrj
519538fd1498Szrj /* Tiling vars. */
519638fd1498Szrj tree tile_size = NULL_TREE;
519738fd1498Szrj tree element_s = NULL_TREE;
519838fd1498Szrj tree e_bound = NULL_TREE, e_offset = NULL_TREE, e_step = NULL_TREE;
519938fd1498Szrj basic_block elem_body_bb = NULL;
520038fd1498Szrj basic_block elem_cont_bb = NULL;
520138fd1498Szrj
520238fd1498Szrj /* SSA instances. */
520338fd1498Szrj tree offset_incr = NULL_TREE;
520438fd1498Szrj tree offset_init = NULL_TREE;
520538fd1498Szrj
520638fd1498Szrj gimple_stmt_iterator gsi;
520738fd1498Szrj gassign *ass;
520838fd1498Szrj gcall *call;
520938fd1498Szrj gimple *stmt;
521038fd1498Szrj tree expr;
521138fd1498Szrj location_t loc;
521238fd1498Szrj edge split, be, fte;
521338fd1498Szrj
521438fd1498Szrj /* Split the end of entry_bb to create head_bb. */
521538fd1498Szrj split = split_block (entry_bb, last_stmt (entry_bb));
521638fd1498Szrj basic_block head_bb = split->dest;
521738fd1498Szrj entry_bb = split->src;
521838fd1498Szrj
521938fd1498Szrj /* Chunk setup goes at end of entry_bb, replacing the omp_for. */
522038fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
522138fd1498Szrj gomp_for *for_stmt = as_a <gomp_for *> (gsi_stmt (gsi));
522238fd1498Szrj loc = gimple_location (for_stmt);
522338fd1498Szrj
522438fd1498Szrj if (gimple_in_ssa_p (cfun))
522538fd1498Szrj {
522638fd1498Szrj offset_init = gimple_omp_for_index (for_stmt, 0);
522738fd1498Szrj gcc_assert (integer_zerop (fd->loop.n1));
522838fd1498Szrj /* The SSA parallelizer does gang parallelism. */
522938fd1498Szrj gwv = build_int_cst (integer_type_node, GOMP_DIM_MASK (GOMP_DIM_GANG));
523038fd1498Szrj }
523138fd1498Szrj
523238fd1498Szrj if (fd->collapse > 1 || fd->tiling)
523338fd1498Szrj {
523438fd1498Szrj gcc_assert (!gimple_in_ssa_p (cfun) && up);
523538fd1498Szrj counts = XALLOCAVEC (struct oacc_collapse, fd->collapse);
523638fd1498Szrj tree total = expand_oacc_collapse_init (fd, &gsi, counts,
523738fd1498Szrj TREE_TYPE (fd->loop.n2), loc);
523838fd1498Szrj
523938fd1498Szrj if (SSA_VAR_P (fd->loop.n2))
524038fd1498Szrj {
524138fd1498Szrj total = force_gimple_operand_gsi (&gsi, total, false, NULL_TREE,
524238fd1498Szrj true, GSI_SAME_STMT);
524338fd1498Szrj ass = gimple_build_assign (fd->loop.n2, total);
524438fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
524538fd1498Szrj }
524638fd1498Szrj }
524738fd1498Szrj
524838fd1498Szrj tree b = fd->loop.n1;
524938fd1498Szrj tree e = fd->loop.n2;
525038fd1498Szrj tree s = fd->loop.step;
525138fd1498Szrj
525238fd1498Szrj b = force_gimple_operand_gsi (&gsi, b, true, NULL_TREE, true, GSI_SAME_STMT);
525338fd1498Szrj e = force_gimple_operand_gsi (&gsi, e, true, NULL_TREE, true, GSI_SAME_STMT);
525438fd1498Szrj
525538fd1498Szrj /* Convert the step, avoiding possible unsigned->signed overflow. */
525638fd1498Szrj negating = !up && TYPE_UNSIGNED (TREE_TYPE (s));
525738fd1498Szrj if (negating)
525838fd1498Szrj s = fold_build1 (NEGATE_EXPR, TREE_TYPE (s), s);
525938fd1498Szrj s = fold_convert (diff_type, s);
526038fd1498Szrj if (negating)
526138fd1498Szrj s = fold_build1 (NEGATE_EXPR, diff_type, s);
526238fd1498Szrj s = force_gimple_operand_gsi (&gsi, s, true, NULL_TREE, true, GSI_SAME_STMT);
526338fd1498Szrj
526438fd1498Szrj if (!chunking)
526538fd1498Szrj chunk_size = integer_zero_node;
526638fd1498Szrj expr = fold_convert (diff_type, chunk_size);
526738fd1498Szrj chunk_size = force_gimple_operand_gsi (&gsi, expr, true,
526838fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
526938fd1498Szrj
527038fd1498Szrj if (fd->tiling)
527138fd1498Szrj {
527238fd1498Szrj /* Determine the tile size and element step,
527338fd1498Szrj modify the outer loop step size. */
527438fd1498Szrj tile_size = create_tmp_var (diff_type, ".tile_size");
527538fd1498Szrj expr = build_int_cst (diff_type, 1);
527638fd1498Szrj for (int ix = 0; ix < fd->collapse; ix++)
527738fd1498Szrj expr = fold_build2 (MULT_EXPR, diff_type, counts[ix].tile, expr);
527838fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, true,
527938fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
528038fd1498Szrj ass = gimple_build_assign (tile_size, expr);
528138fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
528238fd1498Szrj
528338fd1498Szrj element_s = create_tmp_var (diff_type, ".element_s");
528438fd1498Szrj ass = gimple_build_assign (element_s, s);
528538fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
528638fd1498Szrj
528738fd1498Szrj expr = fold_build2 (MULT_EXPR, diff_type, s, tile_size);
528838fd1498Szrj s = force_gimple_operand_gsi (&gsi, expr, true,
528938fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
529038fd1498Szrj }
529138fd1498Szrj
529238fd1498Szrj /* Determine the range, avoiding possible unsigned->signed overflow. */
529338fd1498Szrj negating = !up && TYPE_UNSIGNED (iter_type);
529438fd1498Szrj expr = fold_build2 (MINUS_EXPR, plus_type,
529538fd1498Szrj fold_convert (plus_type, negating ? b : e),
529638fd1498Szrj fold_convert (plus_type, negating ? e : b));
529738fd1498Szrj expr = fold_convert (diff_type, expr);
529838fd1498Szrj if (negating)
529938fd1498Szrj expr = fold_build1 (NEGATE_EXPR, diff_type, expr);
530038fd1498Szrj tree range = force_gimple_operand_gsi (&gsi, expr, true,
530138fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
530238fd1498Szrj
530338fd1498Szrj chunk_no = build_int_cst (diff_type, 0);
530438fd1498Szrj if (chunking)
530538fd1498Szrj {
530638fd1498Szrj gcc_assert (!gimple_in_ssa_p (cfun));
530738fd1498Szrj
530838fd1498Szrj expr = chunk_no;
530938fd1498Szrj chunk_max = create_tmp_var (diff_type, ".chunk_max");
531038fd1498Szrj chunk_no = create_tmp_var (diff_type, ".chunk_no");
531138fd1498Szrj
531238fd1498Szrj ass = gimple_build_assign (chunk_no, expr);
531338fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
531438fd1498Szrj
531538fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 6,
531638fd1498Szrj build_int_cst (integer_type_node,
531738fd1498Szrj IFN_GOACC_LOOP_CHUNKS),
531838fd1498Szrj dir, range, s, chunk_size, gwv);
531938fd1498Szrj gimple_call_set_lhs (call, chunk_max);
532038fd1498Szrj gimple_set_location (call, loc);
532138fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
532238fd1498Szrj }
532338fd1498Szrj else
532438fd1498Szrj chunk_size = chunk_no;
532538fd1498Szrj
532638fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 6,
532738fd1498Szrj build_int_cst (integer_type_node,
532838fd1498Szrj IFN_GOACC_LOOP_STEP),
532938fd1498Szrj dir, range, s, chunk_size, gwv);
533038fd1498Szrj gimple_call_set_lhs (call, step);
533138fd1498Szrj gimple_set_location (call, loc);
533238fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
533338fd1498Szrj
533438fd1498Szrj /* Remove the GIMPLE_OMP_FOR. */
533538fd1498Szrj gsi_remove (&gsi, true);
533638fd1498Szrj
533738fd1498Szrj /* Fixup edges from head_bb. */
533838fd1498Szrj be = BRANCH_EDGE (head_bb);
533938fd1498Szrj fte = FALLTHRU_EDGE (head_bb);
534038fd1498Szrj be->flags |= EDGE_FALSE_VALUE;
534138fd1498Szrj fte->flags ^= EDGE_FALLTHRU | EDGE_TRUE_VALUE;
534238fd1498Szrj
534338fd1498Szrj basic_block body_bb = fte->dest;
534438fd1498Szrj
534538fd1498Szrj if (gimple_in_ssa_p (cfun))
534638fd1498Szrj {
534738fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
534838fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
534938fd1498Szrj
535038fd1498Szrj offset = gimple_omp_continue_control_use (cont_stmt);
535138fd1498Szrj offset_incr = gimple_omp_continue_control_def (cont_stmt);
535238fd1498Szrj }
535338fd1498Szrj else
535438fd1498Szrj {
535538fd1498Szrj offset = create_tmp_var (diff_type, ".offset");
535638fd1498Szrj offset_init = offset_incr = offset;
535738fd1498Szrj }
535838fd1498Szrj bound = create_tmp_var (TREE_TYPE (offset), ".bound");
535938fd1498Szrj
536038fd1498Szrj /* Loop offset & bound go into head_bb. */
536138fd1498Szrj gsi = gsi_start_bb (head_bb);
536238fd1498Szrj
536338fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 7,
536438fd1498Szrj build_int_cst (integer_type_node,
536538fd1498Szrj IFN_GOACC_LOOP_OFFSET),
536638fd1498Szrj dir, range, s,
536738fd1498Szrj chunk_size, gwv, chunk_no);
536838fd1498Szrj gimple_call_set_lhs (call, offset_init);
536938fd1498Szrj gimple_set_location (call, loc);
537038fd1498Szrj gsi_insert_after (&gsi, call, GSI_CONTINUE_LINKING);
537138fd1498Szrj
537238fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 7,
537338fd1498Szrj build_int_cst (integer_type_node,
537438fd1498Szrj IFN_GOACC_LOOP_BOUND),
537538fd1498Szrj dir, range, s,
537638fd1498Szrj chunk_size, gwv, offset_init);
537738fd1498Szrj gimple_call_set_lhs (call, bound);
537838fd1498Szrj gimple_set_location (call, loc);
537938fd1498Szrj gsi_insert_after (&gsi, call, GSI_CONTINUE_LINKING);
538038fd1498Szrj
538138fd1498Szrj expr = build2 (cond_code, boolean_type_node, offset_init, bound);
538238fd1498Szrj gsi_insert_after (&gsi, gimple_build_cond_empty (expr),
538338fd1498Szrj GSI_CONTINUE_LINKING);
538438fd1498Szrj
538538fd1498Szrj /* V assignment goes into body_bb. */
538638fd1498Szrj if (!gimple_in_ssa_p (cfun))
538738fd1498Szrj {
538838fd1498Szrj gsi = gsi_start_bb (body_bb);
538938fd1498Szrj
539038fd1498Szrj expr = build2 (plus_code, iter_type, b,
539138fd1498Szrj fold_convert (plus_type, offset));
539238fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, false, NULL_TREE,
539338fd1498Szrj true, GSI_SAME_STMT);
539438fd1498Szrj ass = gimple_build_assign (v, expr);
539538fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
539638fd1498Szrj
539738fd1498Szrj if (fd->collapse > 1 || fd->tiling)
539838fd1498Szrj expand_oacc_collapse_vars (fd, false, &gsi, counts, v);
539938fd1498Szrj
540038fd1498Szrj if (fd->tiling)
540138fd1498Szrj {
540238fd1498Szrj /* Determine the range of the element loop -- usually simply
540338fd1498Szrj the tile_size, but could be smaller if the final
540438fd1498Szrj iteration of the outer loop is a partial tile. */
540538fd1498Szrj tree e_range = create_tmp_var (diff_type, ".e_range");
540638fd1498Szrj
540738fd1498Szrj expr = build2 (MIN_EXPR, diff_type,
540838fd1498Szrj build2 (MINUS_EXPR, diff_type, bound, offset),
540938fd1498Szrj build2 (MULT_EXPR, diff_type, tile_size,
541038fd1498Szrj element_s));
541138fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, false, NULL_TREE,
541238fd1498Szrj true, GSI_SAME_STMT);
541338fd1498Szrj ass = gimple_build_assign (e_range, expr);
541438fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
541538fd1498Szrj
541638fd1498Szrj /* Determine bound, offset & step of inner loop. */
541738fd1498Szrj e_bound = create_tmp_var (diff_type, ".e_bound");
541838fd1498Szrj e_offset = create_tmp_var (diff_type, ".e_offset");
541938fd1498Szrj e_step = create_tmp_var (diff_type, ".e_step");
542038fd1498Szrj
542138fd1498Szrj /* Mark these as element loops. */
542238fd1498Szrj tree t, e_gwv = integer_minus_one_node;
542338fd1498Szrj tree chunk = build_int_cst (diff_type, 0); /* Never chunked. */
542438fd1498Szrj
542538fd1498Szrj t = build_int_cst (integer_type_node, IFN_GOACC_LOOP_OFFSET);
542638fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 7, t, dir, e_range,
542738fd1498Szrj element_s, chunk, e_gwv, chunk);
542838fd1498Szrj gimple_call_set_lhs (call, e_offset);
542938fd1498Szrj gimple_set_location (call, loc);
543038fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
543138fd1498Szrj
543238fd1498Szrj t = build_int_cst (integer_type_node, IFN_GOACC_LOOP_BOUND);
543338fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 7, t, dir, e_range,
543438fd1498Szrj element_s, chunk, e_gwv, e_offset);
543538fd1498Szrj gimple_call_set_lhs (call, e_bound);
543638fd1498Szrj gimple_set_location (call, loc);
543738fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
543838fd1498Szrj
543938fd1498Szrj t = build_int_cst (integer_type_node, IFN_GOACC_LOOP_STEP);
544038fd1498Szrj call = gimple_build_call_internal (IFN_GOACC_LOOP, 6, t, dir, e_range,
544138fd1498Szrj element_s, chunk, e_gwv);
544238fd1498Szrj gimple_call_set_lhs (call, e_step);
544338fd1498Szrj gimple_set_location (call, loc);
544438fd1498Szrj gsi_insert_before (&gsi, call, GSI_SAME_STMT);
544538fd1498Szrj
544638fd1498Szrj /* Add test and split block. */
544738fd1498Szrj expr = build2 (cond_code, boolean_type_node, e_offset, e_bound);
544838fd1498Szrj stmt = gimple_build_cond_empty (expr);
544938fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
545038fd1498Szrj split = split_block (body_bb, stmt);
545138fd1498Szrj elem_body_bb = split->dest;
545238fd1498Szrj if (cont_bb == body_bb)
545338fd1498Szrj cont_bb = elem_body_bb;
545438fd1498Szrj body_bb = split->src;
545538fd1498Szrj
545638fd1498Szrj split->flags ^= EDGE_FALLTHRU | EDGE_TRUE_VALUE;
545738fd1498Szrj
545838fd1498Szrj /* Add a dummy exit for the tiled block when cont_bb is missing. */
545938fd1498Szrj if (cont_bb == NULL)
546038fd1498Szrj {
546138fd1498Szrj edge e = make_edge (body_bb, exit_bb, EDGE_FALSE_VALUE);
546238fd1498Szrj e->probability = profile_probability::even ();
546338fd1498Szrj split->probability = profile_probability::even ();
546438fd1498Szrj }
546538fd1498Szrj
546638fd1498Szrj /* Initialize the user's loop vars. */
546738fd1498Szrj gsi = gsi_start_bb (elem_body_bb);
546838fd1498Szrj expand_oacc_collapse_vars (fd, true, &gsi, counts, e_offset);
546938fd1498Szrj }
547038fd1498Szrj }
547138fd1498Szrj
547238fd1498Szrj /* Loop increment goes into cont_bb. If this is not a loop, we
547338fd1498Szrj will have spawned threads as if it was, and each one will
547438fd1498Szrj execute one iteration. The specification is not explicit about
547538fd1498Szrj whether such constructs are ill-formed or not, and they can
547638fd1498Szrj occur, especially when noreturn routines are involved. */
547738fd1498Szrj if (cont_bb)
547838fd1498Szrj {
547938fd1498Szrj gsi = gsi_last_nondebug_bb (cont_bb);
548038fd1498Szrj gomp_continue *cont_stmt = as_a <gomp_continue *> (gsi_stmt (gsi));
548138fd1498Szrj loc = gimple_location (cont_stmt);
548238fd1498Szrj
548338fd1498Szrj if (fd->tiling)
548438fd1498Szrj {
548538fd1498Szrj /* Insert element loop increment and test. */
548638fd1498Szrj expr = build2 (PLUS_EXPR, diff_type, e_offset, e_step);
548738fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, false, NULL_TREE,
548838fd1498Szrj true, GSI_SAME_STMT);
548938fd1498Szrj ass = gimple_build_assign (e_offset, expr);
549038fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
549138fd1498Szrj expr = build2 (cond_code, boolean_type_node, e_offset, e_bound);
549238fd1498Szrj
549338fd1498Szrj stmt = gimple_build_cond_empty (expr);
549438fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
549538fd1498Szrj split = split_block (cont_bb, stmt);
549638fd1498Szrj elem_cont_bb = split->src;
549738fd1498Szrj cont_bb = split->dest;
549838fd1498Szrj
549938fd1498Szrj split->flags ^= EDGE_FALLTHRU | EDGE_FALSE_VALUE;
550038fd1498Szrj split->probability = profile_probability::unlikely ().guessed ();
550138fd1498Szrj edge latch_edge
550238fd1498Szrj = make_edge (elem_cont_bb, elem_body_bb, EDGE_TRUE_VALUE);
550338fd1498Szrj latch_edge->probability = profile_probability::likely ().guessed ();
550438fd1498Szrj
550538fd1498Szrj edge skip_edge = make_edge (body_bb, cont_bb, EDGE_FALSE_VALUE);
550638fd1498Szrj skip_edge->probability = profile_probability::unlikely ().guessed ();
550738fd1498Szrj edge loop_entry_edge = EDGE_SUCC (body_bb, 1 - skip_edge->dest_idx);
550838fd1498Szrj loop_entry_edge->probability
550938fd1498Szrj = profile_probability::likely ().guessed ();
551038fd1498Szrj
551138fd1498Szrj gsi = gsi_for_stmt (cont_stmt);
551238fd1498Szrj }
551338fd1498Szrj
551438fd1498Szrj /* Increment offset. */
551538fd1498Szrj if (gimple_in_ssa_p (cfun))
551638fd1498Szrj expr = build2 (plus_code, iter_type, offset,
551738fd1498Szrj fold_convert (plus_type, step));
551838fd1498Szrj else
551938fd1498Szrj expr = build2 (PLUS_EXPR, diff_type, offset, step);
552038fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, false, NULL_TREE,
552138fd1498Szrj true, GSI_SAME_STMT);
552238fd1498Szrj ass = gimple_build_assign (offset_incr, expr);
552338fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
552438fd1498Szrj expr = build2 (cond_code, boolean_type_node, offset_incr, bound);
552538fd1498Szrj gsi_insert_before (&gsi, gimple_build_cond_empty (expr), GSI_SAME_STMT);
552638fd1498Szrj
552738fd1498Szrj /* Remove the GIMPLE_OMP_CONTINUE. */
552838fd1498Szrj gsi_remove (&gsi, true);
552938fd1498Szrj
553038fd1498Szrj /* Fixup edges from cont_bb. */
553138fd1498Szrj be = BRANCH_EDGE (cont_bb);
553238fd1498Szrj fte = FALLTHRU_EDGE (cont_bb);
553338fd1498Szrj be->flags |= EDGE_TRUE_VALUE;
553438fd1498Szrj fte->flags ^= EDGE_FALLTHRU | EDGE_FALSE_VALUE;
553538fd1498Szrj
553638fd1498Szrj if (chunking)
553738fd1498Szrj {
553838fd1498Szrj /* Split the beginning of exit_bb to make bottom_bb. We
553938fd1498Szrj need to insert a nop at the start, because splitting is
554038fd1498Szrj after a stmt, not before. */
554138fd1498Szrj gsi = gsi_start_bb (exit_bb);
554238fd1498Szrj stmt = gimple_build_nop ();
554338fd1498Szrj gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
554438fd1498Szrj split = split_block (exit_bb, stmt);
554538fd1498Szrj bottom_bb = split->src;
554638fd1498Szrj exit_bb = split->dest;
554738fd1498Szrj gsi = gsi_last_bb (bottom_bb);
554838fd1498Szrj
554938fd1498Szrj /* Chunk increment and test goes into bottom_bb. */
555038fd1498Szrj expr = build2 (PLUS_EXPR, diff_type, chunk_no,
555138fd1498Szrj build_int_cst (diff_type, 1));
555238fd1498Szrj ass = gimple_build_assign (chunk_no, expr);
555338fd1498Szrj gsi_insert_after (&gsi, ass, GSI_CONTINUE_LINKING);
555438fd1498Szrj
555538fd1498Szrj /* Chunk test at end of bottom_bb. */
555638fd1498Szrj expr = build2 (LT_EXPR, boolean_type_node, chunk_no, chunk_max);
555738fd1498Szrj gsi_insert_after (&gsi, gimple_build_cond_empty (expr),
555838fd1498Szrj GSI_CONTINUE_LINKING);
555938fd1498Szrj
556038fd1498Szrj /* Fixup edges from bottom_bb. */
556138fd1498Szrj split->flags ^= EDGE_FALLTHRU | EDGE_FALSE_VALUE;
556238fd1498Szrj split->probability = profile_probability::unlikely ().guessed ();
556338fd1498Szrj edge latch_edge = make_edge (bottom_bb, head_bb, EDGE_TRUE_VALUE);
556438fd1498Szrj latch_edge->probability = profile_probability::likely ().guessed ();
556538fd1498Szrj }
556638fd1498Szrj }
556738fd1498Szrj
556838fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
556938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
557038fd1498Szrj loc = gimple_location (gsi_stmt (gsi));
557138fd1498Szrj
557238fd1498Szrj if (!gimple_in_ssa_p (cfun))
557338fd1498Szrj {
557438fd1498Szrj /* Insert the final value of V, in case it is live. This is the
557538fd1498Szrj value for the only thread that survives past the join. */
557638fd1498Szrj expr = fold_build2 (MINUS_EXPR, diff_type, range, dir);
557738fd1498Szrj expr = fold_build2 (PLUS_EXPR, diff_type, expr, s);
557838fd1498Szrj expr = fold_build2 (TRUNC_DIV_EXPR, diff_type, expr, s);
557938fd1498Szrj expr = fold_build2 (MULT_EXPR, diff_type, expr, s);
558038fd1498Szrj expr = build2 (plus_code, iter_type, b, fold_convert (plus_type, expr));
558138fd1498Szrj expr = force_gimple_operand_gsi (&gsi, expr, false, NULL_TREE,
558238fd1498Szrj true, GSI_SAME_STMT);
558338fd1498Szrj ass = gimple_build_assign (v, expr);
558438fd1498Szrj gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
558538fd1498Szrj }
558638fd1498Szrj
558738fd1498Szrj /* Remove the OMP_RETURN. */
558838fd1498Szrj gsi_remove (&gsi, true);
558938fd1498Szrj
559038fd1498Szrj if (cont_bb)
559138fd1498Szrj {
559238fd1498Szrj /* We now have one, two or three nested loops. Update the loop
559338fd1498Szrj structures. */
559438fd1498Szrj struct loop *parent = entry_bb->loop_father;
559538fd1498Szrj struct loop *body = body_bb->loop_father;
559638fd1498Szrj
559738fd1498Szrj if (chunking)
559838fd1498Szrj {
559938fd1498Szrj struct loop *chunk_loop = alloc_loop ();
560038fd1498Szrj chunk_loop->header = head_bb;
560138fd1498Szrj chunk_loop->latch = bottom_bb;
560238fd1498Szrj add_loop (chunk_loop, parent);
560338fd1498Szrj parent = chunk_loop;
560438fd1498Szrj }
560538fd1498Szrj else if (parent != body)
560638fd1498Szrj {
560738fd1498Szrj gcc_assert (body->header == body_bb);
560838fd1498Szrj gcc_assert (body->latch == cont_bb
560938fd1498Szrj || single_pred (body->latch) == cont_bb);
561038fd1498Szrj parent = NULL;
561138fd1498Szrj }
561238fd1498Szrj
561338fd1498Szrj if (parent)
561438fd1498Szrj {
561538fd1498Szrj struct loop *body_loop = alloc_loop ();
561638fd1498Szrj body_loop->header = body_bb;
561738fd1498Szrj body_loop->latch = cont_bb;
561838fd1498Szrj add_loop (body_loop, parent);
561938fd1498Szrj
562038fd1498Szrj if (fd->tiling)
562138fd1498Szrj {
562238fd1498Szrj /* Insert tiling's element loop. */
562338fd1498Szrj struct loop *inner_loop = alloc_loop ();
562438fd1498Szrj inner_loop->header = elem_body_bb;
562538fd1498Szrj inner_loop->latch = elem_cont_bb;
562638fd1498Szrj add_loop (inner_loop, body_loop);
562738fd1498Szrj }
562838fd1498Szrj }
562938fd1498Szrj }
563038fd1498Szrj }
563138fd1498Szrj
563238fd1498Szrj /* Expand the OMP loop defined by REGION. */
563338fd1498Szrj
563438fd1498Szrj static void
expand_omp_for(struct omp_region * region,gimple * inner_stmt)563538fd1498Szrj expand_omp_for (struct omp_region *region, gimple *inner_stmt)
563638fd1498Szrj {
563738fd1498Szrj struct omp_for_data fd;
563838fd1498Szrj struct omp_for_data_loop *loops;
563938fd1498Szrj
564038fd1498Szrj loops
564138fd1498Szrj = (struct omp_for_data_loop *)
564238fd1498Szrj alloca (gimple_omp_for_collapse (last_stmt (region->entry))
564338fd1498Szrj * sizeof (struct omp_for_data_loop));
564438fd1498Szrj omp_extract_for_data (as_a <gomp_for *> (last_stmt (region->entry)),
564538fd1498Szrj &fd, loops);
564638fd1498Szrj region->sched_kind = fd.sched_kind;
564738fd1498Szrj region->sched_modifiers = fd.sched_modifiers;
564838fd1498Szrj
564938fd1498Szrj gcc_assert (EDGE_COUNT (region->entry->succs) == 2);
565038fd1498Szrj BRANCH_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
565138fd1498Szrj FALLTHRU_EDGE (region->entry)->flags &= ~EDGE_ABNORMAL;
565238fd1498Szrj if (region->cont)
565338fd1498Szrj {
565438fd1498Szrj gcc_assert (EDGE_COUNT (region->cont->succs) == 2);
565538fd1498Szrj BRANCH_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
565638fd1498Szrj FALLTHRU_EDGE (region->cont)->flags &= ~EDGE_ABNORMAL;
565738fd1498Szrj }
565838fd1498Szrj else
565938fd1498Szrj /* If there isn't a continue then this is a degerate case where
566038fd1498Szrj the introduction of abnormal edges during lowering will prevent
566138fd1498Szrj original loops from being detected. Fix that up. */
566238fd1498Szrj loops_state_set (LOOPS_NEED_FIXUP);
566338fd1498Szrj
566438fd1498Szrj if (gimple_omp_for_kind (fd.for_stmt) & GF_OMP_FOR_SIMD)
566538fd1498Szrj expand_omp_simd (region, &fd);
566638fd1498Szrj else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
566738fd1498Szrj {
566838fd1498Szrj gcc_assert (!inner_stmt);
566938fd1498Szrj expand_oacc_for (region, &fd);
567038fd1498Szrj }
567138fd1498Szrj else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_TASKLOOP)
567238fd1498Szrj {
567338fd1498Szrj if (gimple_omp_for_combined_into_p (fd.for_stmt))
567438fd1498Szrj expand_omp_taskloop_for_inner (region, &fd, inner_stmt);
567538fd1498Szrj else
567638fd1498Szrj expand_omp_taskloop_for_outer (region, &fd, inner_stmt);
567738fd1498Szrj }
567838fd1498Szrj else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
567938fd1498Szrj && !fd.have_ordered)
568038fd1498Szrj {
568138fd1498Szrj if (fd.chunk_size == NULL)
568238fd1498Szrj expand_omp_for_static_nochunk (region, &fd, inner_stmt);
568338fd1498Szrj else
568438fd1498Szrj expand_omp_for_static_chunk (region, &fd, inner_stmt);
568538fd1498Szrj }
568638fd1498Szrj else
568738fd1498Szrj {
568838fd1498Szrj int fn_index, start_ix, next_ix;
568938fd1498Szrj
569038fd1498Szrj gcc_assert (gimple_omp_for_kind (fd.for_stmt)
569138fd1498Szrj == GF_OMP_FOR_KIND_FOR);
569238fd1498Szrj if (fd.chunk_size == NULL
569338fd1498Szrj && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
569438fd1498Szrj fd.chunk_size = integer_zero_node;
569538fd1498Szrj gcc_assert (fd.sched_kind != OMP_CLAUSE_SCHEDULE_AUTO);
569638fd1498Szrj switch (fd.sched_kind)
569738fd1498Szrj {
569838fd1498Szrj case OMP_CLAUSE_SCHEDULE_RUNTIME:
569938fd1498Szrj fn_index = 3;
570038fd1498Szrj break;
570138fd1498Szrj case OMP_CLAUSE_SCHEDULE_DYNAMIC:
570238fd1498Szrj case OMP_CLAUSE_SCHEDULE_GUIDED:
570338fd1498Szrj if ((fd.sched_modifiers & OMP_CLAUSE_SCHEDULE_NONMONOTONIC)
570438fd1498Szrj && !fd.ordered
570538fd1498Szrj && !fd.have_ordered)
570638fd1498Szrj {
570738fd1498Szrj fn_index = 3 + fd.sched_kind;
570838fd1498Szrj break;
570938fd1498Szrj }
571038fd1498Szrj /* FALLTHRU */
571138fd1498Szrj default:
571238fd1498Szrj fn_index = fd.sched_kind;
571338fd1498Szrj break;
571438fd1498Szrj }
571538fd1498Szrj if (!fd.ordered)
571638fd1498Szrj fn_index += fd.have_ordered * 6;
571738fd1498Szrj if (fd.ordered)
571838fd1498Szrj start_ix = ((int)BUILT_IN_GOMP_LOOP_DOACROSS_STATIC_START) + fn_index;
571938fd1498Szrj else
572038fd1498Szrj start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index;
572138fd1498Szrj next_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_NEXT) + fn_index;
572238fd1498Szrj if (fd.iter_type == long_long_unsigned_type_node)
572338fd1498Szrj {
572438fd1498Szrj start_ix += ((int)BUILT_IN_GOMP_LOOP_ULL_STATIC_START
572538fd1498Szrj - (int)BUILT_IN_GOMP_LOOP_STATIC_START);
572638fd1498Szrj next_ix += ((int)BUILT_IN_GOMP_LOOP_ULL_STATIC_NEXT
572738fd1498Szrj - (int)BUILT_IN_GOMP_LOOP_STATIC_NEXT);
572838fd1498Szrj }
572938fd1498Szrj expand_omp_for_generic (region, &fd, (enum built_in_function) start_ix,
573038fd1498Szrj (enum built_in_function) next_ix, inner_stmt);
573138fd1498Szrj }
573238fd1498Szrj
573338fd1498Szrj if (gimple_in_ssa_p (cfun))
573438fd1498Szrj update_ssa (TODO_update_ssa_only_virtuals);
573538fd1498Szrj }
573638fd1498Szrj
573738fd1498Szrj /* Expand code for an OpenMP sections directive. In pseudo code, we generate
573838fd1498Szrj
573938fd1498Szrj v = GOMP_sections_start (n);
574038fd1498Szrj L0:
574138fd1498Szrj switch (v)
574238fd1498Szrj {
574338fd1498Szrj case 0:
574438fd1498Szrj goto L2;
574538fd1498Szrj case 1:
574638fd1498Szrj section 1;
574738fd1498Szrj goto L1;
574838fd1498Szrj case 2:
574938fd1498Szrj ...
575038fd1498Szrj case n:
575138fd1498Szrj ...
575238fd1498Szrj default:
575338fd1498Szrj abort ();
575438fd1498Szrj }
575538fd1498Szrj L1:
575638fd1498Szrj v = GOMP_sections_next ();
575738fd1498Szrj goto L0;
575838fd1498Szrj L2:
575938fd1498Szrj reduction;
576038fd1498Szrj
576138fd1498Szrj If this is a combined parallel sections, replace the call to
576238fd1498Szrj GOMP_sections_start with call to GOMP_sections_next. */
576338fd1498Szrj
576438fd1498Szrj static void
expand_omp_sections(struct omp_region * region)576538fd1498Szrj expand_omp_sections (struct omp_region *region)
576638fd1498Szrj {
576738fd1498Szrj tree t, u, vin = NULL, vmain, vnext, l2;
576838fd1498Szrj unsigned len;
576938fd1498Szrj basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
577038fd1498Szrj gimple_stmt_iterator si, switch_si;
577138fd1498Szrj gomp_sections *sections_stmt;
577238fd1498Szrj gimple *stmt;
577338fd1498Szrj gomp_continue *cont;
577438fd1498Szrj edge_iterator ei;
577538fd1498Szrj edge e;
577638fd1498Szrj struct omp_region *inner;
577738fd1498Szrj unsigned i, casei;
577838fd1498Szrj bool exit_reachable = region->cont != NULL;
577938fd1498Szrj
578038fd1498Szrj gcc_assert (region->exit != NULL);
578138fd1498Szrj entry_bb = region->entry;
578238fd1498Szrj l0_bb = single_succ (entry_bb);
578338fd1498Szrj l1_bb = region->cont;
578438fd1498Szrj l2_bb = region->exit;
578538fd1498Szrj if (single_pred_p (l2_bb) && single_pred (l2_bb) == l0_bb)
578638fd1498Szrj l2 = gimple_block_label (l2_bb);
578738fd1498Szrj else
578838fd1498Szrj {
578938fd1498Szrj /* This can happen if there are reductions. */
579038fd1498Szrj len = EDGE_COUNT (l0_bb->succs);
579138fd1498Szrj gcc_assert (len > 0);
579238fd1498Szrj e = EDGE_SUCC (l0_bb, len - 1);
579338fd1498Szrj si = gsi_last_nondebug_bb (e->dest);
579438fd1498Szrj l2 = NULL_TREE;
579538fd1498Szrj if (gsi_end_p (si)
579638fd1498Szrj || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
579738fd1498Szrj l2 = gimple_block_label (e->dest);
579838fd1498Szrj else
579938fd1498Szrj FOR_EACH_EDGE (e, ei, l0_bb->succs)
580038fd1498Szrj {
580138fd1498Szrj si = gsi_last_nondebug_bb (e->dest);
580238fd1498Szrj if (gsi_end_p (si)
580338fd1498Szrj || gimple_code (gsi_stmt (si)) != GIMPLE_OMP_SECTION)
580438fd1498Szrj {
580538fd1498Szrj l2 = gimple_block_label (e->dest);
580638fd1498Szrj break;
580738fd1498Szrj }
580838fd1498Szrj }
580938fd1498Szrj }
581038fd1498Szrj if (exit_reachable)
581138fd1498Szrj default_bb = create_empty_bb (l1_bb->prev_bb);
581238fd1498Szrj else
581338fd1498Szrj default_bb = create_empty_bb (l0_bb);
581438fd1498Szrj
581538fd1498Szrj /* We will build a switch() with enough cases for all the
581638fd1498Szrj GIMPLE_OMP_SECTION regions, a '0' case to handle the end of more work
581738fd1498Szrj and a default case to abort if something goes wrong. */
581838fd1498Szrj len = EDGE_COUNT (l0_bb->succs);
581938fd1498Szrj
582038fd1498Szrj /* Use vec::quick_push on label_vec throughout, since we know the size
582138fd1498Szrj in advance. */
582238fd1498Szrj auto_vec<tree> label_vec (len);
582338fd1498Szrj
582438fd1498Szrj /* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
582538fd1498Szrj GIMPLE_OMP_SECTIONS statement. */
582638fd1498Szrj si = gsi_last_nondebug_bb (entry_bb);
582738fd1498Szrj sections_stmt = as_a <gomp_sections *> (gsi_stmt (si));
582838fd1498Szrj gcc_assert (gimple_code (sections_stmt) == GIMPLE_OMP_SECTIONS);
582938fd1498Szrj vin = gimple_omp_sections_control (sections_stmt);
583038fd1498Szrj if (!is_combined_parallel (region))
583138fd1498Szrj {
583238fd1498Szrj /* If we are not inside a combined parallel+sections region,
583338fd1498Szrj call GOMP_sections_start. */
583438fd1498Szrj t = build_int_cst (unsigned_type_node, len - 1);
583538fd1498Szrj u = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_START);
583638fd1498Szrj stmt = gimple_build_call (u, 1, t);
583738fd1498Szrj }
583838fd1498Szrj else
583938fd1498Szrj {
584038fd1498Szrj /* Otherwise, call GOMP_sections_next. */
584138fd1498Szrj u = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
584238fd1498Szrj stmt = gimple_build_call (u, 0);
584338fd1498Szrj }
584438fd1498Szrj gimple_call_set_lhs (stmt, vin);
584538fd1498Szrj gsi_insert_after (&si, stmt, GSI_SAME_STMT);
584638fd1498Szrj gsi_remove (&si, true);
584738fd1498Szrj
584838fd1498Szrj /* The switch() statement replacing GIMPLE_OMP_SECTIONS_SWITCH goes in
584938fd1498Szrj L0_BB. */
585038fd1498Szrj switch_si = gsi_last_nondebug_bb (l0_bb);
585138fd1498Szrj gcc_assert (gimple_code (gsi_stmt (switch_si)) == GIMPLE_OMP_SECTIONS_SWITCH);
585238fd1498Szrj if (exit_reachable)
585338fd1498Szrj {
585438fd1498Szrj cont = as_a <gomp_continue *> (last_stmt (l1_bb));
585538fd1498Szrj gcc_assert (gimple_code (cont) == GIMPLE_OMP_CONTINUE);
585638fd1498Szrj vmain = gimple_omp_continue_control_use (cont);
585738fd1498Szrj vnext = gimple_omp_continue_control_def (cont);
585838fd1498Szrj }
585938fd1498Szrj else
586038fd1498Szrj {
586138fd1498Szrj vmain = vin;
586238fd1498Szrj vnext = NULL_TREE;
586338fd1498Szrj }
586438fd1498Szrj
586538fd1498Szrj t = build_case_label (build_int_cst (unsigned_type_node, 0), NULL, l2);
586638fd1498Szrj label_vec.quick_push (t);
586738fd1498Szrj i = 1;
586838fd1498Szrj
586938fd1498Szrj /* Convert each GIMPLE_OMP_SECTION into a CASE_LABEL_EXPR. */
587038fd1498Szrj for (inner = region->inner, casei = 1;
587138fd1498Szrj inner;
587238fd1498Szrj inner = inner->next, i++, casei++)
587338fd1498Szrj {
587438fd1498Szrj basic_block s_entry_bb, s_exit_bb;
587538fd1498Szrj
587638fd1498Szrj /* Skip optional reduction region. */
587738fd1498Szrj if (inner->type == GIMPLE_OMP_ATOMIC_LOAD)
587838fd1498Szrj {
587938fd1498Szrj --i;
588038fd1498Szrj --casei;
588138fd1498Szrj continue;
588238fd1498Szrj }
588338fd1498Szrj
588438fd1498Szrj s_entry_bb = inner->entry;
588538fd1498Szrj s_exit_bb = inner->exit;
588638fd1498Szrj
588738fd1498Szrj t = gimple_block_label (s_entry_bb);
588838fd1498Szrj u = build_int_cst (unsigned_type_node, casei);
588938fd1498Szrj u = build_case_label (u, NULL, t);
589038fd1498Szrj label_vec.quick_push (u);
589138fd1498Szrj
589238fd1498Szrj si = gsi_last_nondebug_bb (s_entry_bb);
589338fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SECTION);
589438fd1498Szrj gcc_assert (i < len || gimple_omp_section_last_p (gsi_stmt (si)));
589538fd1498Szrj gsi_remove (&si, true);
589638fd1498Szrj single_succ_edge (s_entry_bb)->flags = EDGE_FALLTHRU;
589738fd1498Szrj
589838fd1498Szrj if (s_exit_bb == NULL)
589938fd1498Szrj continue;
590038fd1498Szrj
590138fd1498Szrj si = gsi_last_nondebug_bb (s_exit_bb);
590238fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
590338fd1498Szrj gsi_remove (&si, true);
590438fd1498Szrj
590538fd1498Szrj single_succ_edge (s_exit_bb)->flags = EDGE_FALLTHRU;
590638fd1498Szrj }
590738fd1498Szrj
590838fd1498Szrj /* Error handling code goes in DEFAULT_BB. */
590938fd1498Szrj t = gimple_block_label (default_bb);
591038fd1498Szrj u = build_case_label (NULL, NULL, t);
591138fd1498Szrj make_edge (l0_bb, default_bb, 0);
591238fd1498Szrj add_bb_to_loop (default_bb, current_loops->tree_root);
591338fd1498Szrj
591438fd1498Szrj stmt = gimple_build_switch (vmain, u, label_vec);
591538fd1498Szrj gsi_insert_after (&switch_si, stmt, GSI_SAME_STMT);
591638fd1498Szrj gsi_remove (&switch_si, true);
591738fd1498Szrj
591838fd1498Szrj si = gsi_start_bb (default_bb);
591938fd1498Szrj stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
592038fd1498Szrj gsi_insert_after (&si, stmt, GSI_CONTINUE_LINKING);
592138fd1498Szrj
592238fd1498Szrj if (exit_reachable)
592338fd1498Szrj {
592438fd1498Szrj tree bfn_decl;
592538fd1498Szrj
592638fd1498Szrj /* Code to get the next section goes in L1_BB. */
592738fd1498Szrj si = gsi_last_nondebug_bb (l1_bb);
592838fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CONTINUE);
592938fd1498Szrj
593038fd1498Szrj bfn_decl = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_NEXT);
593138fd1498Szrj stmt = gimple_build_call (bfn_decl, 0);
593238fd1498Szrj gimple_call_set_lhs (stmt, vnext);
593338fd1498Szrj gsi_insert_after (&si, stmt, GSI_SAME_STMT);
593438fd1498Szrj gsi_remove (&si, true);
593538fd1498Szrj
593638fd1498Szrj single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
593738fd1498Szrj }
593838fd1498Szrj
593938fd1498Szrj /* Cleanup function replaces GIMPLE_OMP_RETURN in EXIT_BB. */
594038fd1498Szrj si = gsi_last_nondebug_bb (l2_bb);
594138fd1498Szrj if (gimple_omp_return_nowait_p (gsi_stmt (si)))
594238fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_NOWAIT);
594338fd1498Szrj else if (gimple_omp_return_lhs (gsi_stmt (si)))
594438fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END_CANCEL);
594538fd1498Szrj else
594638fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_SECTIONS_END);
594738fd1498Szrj stmt = gimple_build_call (t, 0);
594838fd1498Szrj if (gimple_omp_return_lhs (gsi_stmt (si)))
594938fd1498Szrj gimple_call_set_lhs (stmt, gimple_omp_return_lhs (gsi_stmt (si)));
595038fd1498Szrj gsi_insert_after (&si, stmt, GSI_SAME_STMT);
595138fd1498Szrj gsi_remove (&si, true);
595238fd1498Szrj
595338fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb);
595438fd1498Szrj }
595538fd1498Szrj
595638fd1498Szrj /* Expand code for an OpenMP single directive. We've already expanded
595738fd1498Szrj much of the code, here we simply place the GOMP_barrier call. */
595838fd1498Szrj
595938fd1498Szrj static void
expand_omp_single(struct omp_region * region)596038fd1498Szrj expand_omp_single (struct omp_region *region)
596138fd1498Szrj {
596238fd1498Szrj basic_block entry_bb, exit_bb;
596338fd1498Szrj gimple_stmt_iterator si;
596438fd1498Szrj
596538fd1498Szrj entry_bb = region->entry;
596638fd1498Szrj exit_bb = region->exit;
596738fd1498Szrj
596838fd1498Szrj si = gsi_last_nondebug_bb (entry_bb);
596938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE);
597038fd1498Szrj gsi_remove (&si, true);
597138fd1498Szrj single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
597238fd1498Szrj
597338fd1498Szrj si = gsi_last_nondebug_bb (exit_bb);
597438fd1498Szrj if (!gimple_omp_return_nowait_p (gsi_stmt (si)))
597538fd1498Szrj {
597638fd1498Szrj tree t = gimple_omp_return_lhs (gsi_stmt (si));
597738fd1498Szrj gsi_insert_after (&si, omp_build_barrier (t), GSI_SAME_STMT);
597838fd1498Szrj }
597938fd1498Szrj gsi_remove (&si, true);
598038fd1498Szrj single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
598138fd1498Szrj }
598238fd1498Szrj
598338fd1498Szrj /* Generic expansion for OpenMP synchronization directives: master,
598438fd1498Szrj ordered and critical. All we need to do here is remove the entry
598538fd1498Szrj and exit markers for REGION. */
598638fd1498Szrj
598738fd1498Szrj static void
expand_omp_synch(struct omp_region * region)598838fd1498Szrj expand_omp_synch (struct omp_region *region)
598938fd1498Szrj {
599038fd1498Szrj basic_block entry_bb, exit_bb;
599138fd1498Szrj gimple_stmt_iterator si;
599238fd1498Szrj
599338fd1498Szrj entry_bb = region->entry;
599438fd1498Szrj exit_bb = region->exit;
599538fd1498Szrj
599638fd1498Szrj si = gsi_last_nondebug_bb (entry_bb);
599738fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
599838fd1498Szrj || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
599938fd1498Szrj || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
600038fd1498Szrj || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
600138fd1498Szrj || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
600238fd1498Szrj || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TEAMS);
600338fd1498Szrj gsi_remove (&si, true);
600438fd1498Szrj single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
600538fd1498Szrj
600638fd1498Szrj if (exit_bb)
600738fd1498Szrj {
600838fd1498Szrj si = gsi_last_nondebug_bb (exit_bb);
600938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_RETURN);
601038fd1498Szrj gsi_remove (&si, true);
601138fd1498Szrj single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
601238fd1498Szrj }
601338fd1498Szrj }
601438fd1498Szrj
601538fd1498Szrj /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
601638fd1498Szrj operation as a normal volatile load. */
601738fd1498Szrj
601838fd1498Szrj static bool
expand_omp_atomic_load(basic_block load_bb,tree addr,tree loaded_val,int index)601938fd1498Szrj expand_omp_atomic_load (basic_block load_bb, tree addr,
602038fd1498Szrj tree loaded_val, int index)
602138fd1498Szrj {
602238fd1498Szrj enum built_in_function tmpbase;
602338fd1498Szrj gimple_stmt_iterator gsi;
602438fd1498Szrj basic_block store_bb;
602538fd1498Szrj location_t loc;
602638fd1498Szrj gimple *stmt;
602738fd1498Szrj tree decl, call, type, itype;
602838fd1498Szrj
602938fd1498Szrj gsi = gsi_last_nondebug_bb (load_bb);
603038fd1498Szrj stmt = gsi_stmt (gsi);
603138fd1498Szrj gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
603238fd1498Szrj loc = gimple_location (stmt);
603338fd1498Szrj
603438fd1498Szrj /* ??? If the target does not implement atomic_load_optab[mode], and mode
603538fd1498Szrj is smaller than word size, then expand_atomic_load assumes that the load
603638fd1498Szrj is atomic. We could avoid the builtin entirely in this case. */
603738fd1498Szrj
603838fd1498Szrj tmpbase = (enum built_in_function) (BUILT_IN_ATOMIC_LOAD_N + index + 1);
603938fd1498Szrj decl = builtin_decl_explicit (tmpbase);
604038fd1498Szrj if (decl == NULL_TREE)
604138fd1498Szrj return false;
604238fd1498Szrj
604338fd1498Szrj type = TREE_TYPE (loaded_val);
604438fd1498Szrj itype = TREE_TYPE (TREE_TYPE (decl));
604538fd1498Szrj
604638fd1498Szrj call = build_call_expr_loc (loc, decl, 2, addr,
604738fd1498Szrj build_int_cst (NULL,
604838fd1498Szrj gimple_omp_atomic_seq_cst_p (stmt)
604938fd1498Szrj ? MEMMODEL_SEQ_CST
605038fd1498Szrj : MEMMODEL_RELAXED));
605138fd1498Szrj if (!useless_type_conversion_p (type, itype))
605238fd1498Szrj call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
605338fd1498Szrj call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
605438fd1498Szrj
605538fd1498Szrj force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
605638fd1498Szrj gsi_remove (&gsi, true);
605738fd1498Szrj
605838fd1498Szrj store_bb = single_succ (load_bb);
605938fd1498Szrj gsi = gsi_last_nondebug_bb (store_bb);
606038fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
606138fd1498Szrj gsi_remove (&gsi, true);
606238fd1498Szrj
606338fd1498Szrj if (gimple_in_ssa_p (cfun))
606438fd1498Szrj update_ssa (TODO_update_ssa_no_phi);
606538fd1498Szrj
606638fd1498Szrj return true;
606738fd1498Szrj }
606838fd1498Szrj
606938fd1498Szrj /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
607038fd1498Szrj operation as a normal volatile store. */
607138fd1498Szrj
607238fd1498Szrj static bool
expand_omp_atomic_store(basic_block load_bb,tree addr,tree loaded_val,tree stored_val,int index)607338fd1498Szrj expand_omp_atomic_store (basic_block load_bb, tree addr,
607438fd1498Szrj tree loaded_val, tree stored_val, int index)
607538fd1498Szrj {
607638fd1498Szrj enum built_in_function tmpbase;
607738fd1498Szrj gimple_stmt_iterator gsi;
607838fd1498Szrj basic_block store_bb = single_succ (load_bb);
607938fd1498Szrj location_t loc;
608038fd1498Szrj gimple *stmt;
608138fd1498Szrj tree decl, call, type, itype;
608238fd1498Szrj machine_mode imode;
608338fd1498Szrj bool exchange;
608438fd1498Szrj
608538fd1498Szrj gsi = gsi_last_nondebug_bb (load_bb);
608638fd1498Szrj stmt = gsi_stmt (gsi);
608738fd1498Szrj gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_LOAD);
608838fd1498Szrj
608938fd1498Szrj /* If the load value is needed, then this isn't a store but an exchange. */
609038fd1498Szrj exchange = gimple_omp_atomic_need_value_p (stmt);
609138fd1498Szrj
609238fd1498Szrj gsi = gsi_last_nondebug_bb (store_bb);
609338fd1498Szrj stmt = gsi_stmt (gsi);
609438fd1498Szrj gcc_assert (gimple_code (stmt) == GIMPLE_OMP_ATOMIC_STORE);
609538fd1498Szrj loc = gimple_location (stmt);
609638fd1498Szrj
609738fd1498Szrj /* ??? If the target does not implement atomic_store_optab[mode], and mode
609838fd1498Szrj is smaller than word size, then expand_atomic_store assumes that the store
609938fd1498Szrj is atomic. We could avoid the builtin entirely in this case. */
610038fd1498Szrj
610138fd1498Szrj tmpbase = (exchange ? BUILT_IN_ATOMIC_EXCHANGE_N : BUILT_IN_ATOMIC_STORE_N);
610238fd1498Szrj tmpbase = (enum built_in_function) ((int) tmpbase + index + 1);
610338fd1498Szrj decl = builtin_decl_explicit (tmpbase);
610438fd1498Szrj if (decl == NULL_TREE)
610538fd1498Szrj return false;
610638fd1498Szrj
610738fd1498Szrj type = TREE_TYPE (stored_val);
610838fd1498Szrj
610938fd1498Szrj /* Dig out the type of the function's second argument. */
611038fd1498Szrj itype = TREE_TYPE (decl);
611138fd1498Szrj itype = TYPE_ARG_TYPES (itype);
611238fd1498Szrj itype = TREE_CHAIN (itype);
611338fd1498Szrj itype = TREE_VALUE (itype);
611438fd1498Szrj imode = TYPE_MODE (itype);
611538fd1498Szrj
611638fd1498Szrj if (exchange && !can_atomic_exchange_p (imode, true))
611738fd1498Szrj return false;
611838fd1498Szrj
611938fd1498Szrj if (!useless_type_conversion_p (itype, type))
612038fd1498Szrj stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val);
612138fd1498Szrj call = build_call_expr_loc (loc, decl, 3, addr, stored_val,
612238fd1498Szrj build_int_cst (NULL,
612338fd1498Szrj gimple_omp_atomic_seq_cst_p (stmt)
612438fd1498Szrj ? MEMMODEL_SEQ_CST
612538fd1498Szrj : MEMMODEL_RELAXED));
612638fd1498Szrj if (exchange)
612738fd1498Szrj {
612838fd1498Szrj if (!useless_type_conversion_p (type, itype))
612938fd1498Szrj call = build1_loc (loc, VIEW_CONVERT_EXPR, type, call);
613038fd1498Szrj call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call);
613138fd1498Szrj }
613238fd1498Szrj
613338fd1498Szrj force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
613438fd1498Szrj gsi_remove (&gsi, true);
613538fd1498Szrj
613638fd1498Szrj /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */
613738fd1498Szrj gsi = gsi_last_nondebug_bb (load_bb);
613838fd1498Szrj gsi_remove (&gsi, true);
613938fd1498Szrj
614038fd1498Szrj if (gimple_in_ssa_p (cfun))
614138fd1498Szrj update_ssa (TODO_update_ssa_no_phi);
614238fd1498Szrj
614338fd1498Szrj return true;
614438fd1498Szrj }
614538fd1498Szrj
614638fd1498Szrj /* A subroutine of expand_omp_atomic. Attempt to implement the atomic
614738fd1498Szrj operation as a __atomic_fetch_op builtin. INDEX is log2 of the
614838fd1498Szrj size of the data type, and thus usable to find the index of the builtin
614938fd1498Szrj decl. Returns false if the expression is not of the proper form. */
615038fd1498Szrj
615138fd1498Szrj static bool
expand_omp_atomic_fetch_op(basic_block load_bb,tree addr,tree loaded_val,tree stored_val,int index)615238fd1498Szrj expand_omp_atomic_fetch_op (basic_block load_bb,
615338fd1498Szrj tree addr, tree loaded_val,
615438fd1498Szrj tree stored_val, int index)
615538fd1498Szrj {
615638fd1498Szrj enum built_in_function oldbase, newbase, tmpbase;
615738fd1498Szrj tree decl, itype, call;
615838fd1498Szrj tree lhs, rhs;
615938fd1498Szrj basic_block store_bb = single_succ (load_bb);
616038fd1498Szrj gimple_stmt_iterator gsi;
616138fd1498Szrj gimple *stmt;
616238fd1498Szrj location_t loc;
616338fd1498Szrj enum tree_code code;
616438fd1498Szrj bool need_old, need_new;
616538fd1498Szrj machine_mode imode;
616638fd1498Szrj bool seq_cst;
616738fd1498Szrj
616838fd1498Szrj /* We expect to find the following sequences:
616938fd1498Szrj
617038fd1498Szrj load_bb:
617138fd1498Szrj GIMPLE_OMP_ATOMIC_LOAD (tmp, mem)
617238fd1498Szrj
617338fd1498Szrj store_bb:
617438fd1498Szrj val = tmp OP something; (or: something OP tmp)
617538fd1498Szrj GIMPLE_OMP_STORE (val)
617638fd1498Szrj
617738fd1498Szrj ???FIXME: Allow a more flexible sequence.
617838fd1498Szrj Perhaps use data flow to pick the statements.
617938fd1498Szrj
618038fd1498Szrj */
618138fd1498Szrj
618238fd1498Szrj gsi = gsi_after_labels (store_bb);
618338fd1498Szrj stmt = gsi_stmt (gsi);
618438fd1498Szrj if (is_gimple_debug (stmt))
618538fd1498Szrj {
618638fd1498Szrj gsi_next_nondebug (&gsi);
618738fd1498Szrj if (gsi_end_p (gsi))
618838fd1498Szrj return false;
618938fd1498Szrj stmt = gsi_stmt (gsi);
619038fd1498Szrj }
619138fd1498Szrj loc = gimple_location (stmt);
619238fd1498Szrj if (!is_gimple_assign (stmt))
619338fd1498Szrj return false;
619438fd1498Szrj gsi_next_nondebug (&gsi);
619538fd1498Szrj if (gimple_code (gsi_stmt (gsi)) != GIMPLE_OMP_ATOMIC_STORE)
619638fd1498Szrj return false;
619738fd1498Szrj need_new = gimple_omp_atomic_need_value_p (gsi_stmt (gsi));
619838fd1498Szrj need_old = gimple_omp_atomic_need_value_p (last_stmt (load_bb));
619938fd1498Szrj seq_cst = gimple_omp_atomic_seq_cst_p (last_stmt (load_bb));
620038fd1498Szrj gcc_checking_assert (!need_old || !need_new);
620138fd1498Szrj
620238fd1498Szrj if (!operand_equal_p (gimple_assign_lhs (stmt), stored_val, 0))
620338fd1498Szrj return false;
620438fd1498Szrj
620538fd1498Szrj /* Check for one of the supported fetch-op operations. */
620638fd1498Szrj code = gimple_assign_rhs_code (stmt);
620738fd1498Szrj switch (code)
620838fd1498Szrj {
620938fd1498Szrj case PLUS_EXPR:
621038fd1498Szrj case POINTER_PLUS_EXPR:
621138fd1498Szrj oldbase = BUILT_IN_ATOMIC_FETCH_ADD_N;
621238fd1498Szrj newbase = BUILT_IN_ATOMIC_ADD_FETCH_N;
621338fd1498Szrj break;
621438fd1498Szrj case MINUS_EXPR:
621538fd1498Szrj oldbase = BUILT_IN_ATOMIC_FETCH_SUB_N;
621638fd1498Szrj newbase = BUILT_IN_ATOMIC_SUB_FETCH_N;
621738fd1498Szrj break;
621838fd1498Szrj case BIT_AND_EXPR:
621938fd1498Szrj oldbase = BUILT_IN_ATOMIC_FETCH_AND_N;
622038fd1498Szrj newbase = BUILT_IN_ATOMIC_AND_FETCH_N;
622138fd1498Szrj break;
622238fd1498Szrj case BIT_IOR_EXPR:
622338fd1498Szrj oldbase = BUILT_IN_ATOMIC_FETCH_OR_N;
622438fd1498Szrj newbase = BUILT_IN_ATOMIC_OR_FETCH_N;
622538fd1498Szrj break;
622638fd1498Szrj case BIT_XOR_EXPR:
622738fd1498Szrj oldbase = BUILT_IN_ATOMIC_FETCH_XOR_N;
622838fd1498Szrj newbase = BUILT_IN_ATOMIC_XOR_FETCH_N;
622938fd1498Szrj break;
623038fd1498Szrj default:
623138fd1498Szrj return false;
623238fd1498Szrj }
623338fd1498Szrj
623438fd1498Szrj /* Make sure the expression is of the proper form. */
623538fd1498Szrj if (operand_equal_p (gimple_assign_rhs1 (stmt), loaded_val, 0))
623638fd1498Szrj rhs = gimple_assign_rhs2 (stmt);
623738fd1498Szrj else if (commutative_tree_code (gimple_assign_rhs_code (stmt))
623838fd1498Szrj && operand_equal_p (gimple_assign_rhs2 (stmt), loaded_val, 0))
623938fd1498Szrj rhs = gimple_assign_rhs1 (stmt);
624038fd1498Szrj else
624138fd1498Szrj return false;
624238fd1498Szrj
624338fd1498Szrj tmpbase = ((enum built_in_function)
624438fd1498Szrj ((need_new ? newbase : oldbase) + index + 1));
624538fd1498Szrj decl = builtin_decl_explicit (tmpbase);
624638fd1498Szrj if (decl == NULL_TREE)
624738fd1498Szrj return false;
624838fd1498Szrj itype = TREE_TYPE (TREE_TYPE (decl));
624938fd1498Szrj imode = TYPE_MODE (itype);
625038fd1498Szrj
625138fd1498Szrj /* We could test all of the various optabs involved, but the fact of the
625238fd1498Szrj matter is that (with the exception of i486 vs i586 and xadd) all targets
625338fd1498Szrj that support any atomic operaton optab also implements compare-and-swap.
625438fd1498Szrj Let optabs.c take care of expanding any compare-and-swap loop. */
625538fd1498Szrj if (!can_compare_and_swap_p (imode, true) || !can_atomic_load_p (imode))
625638fd1498Szrj return false;
625738fd1498Szrj
625838fd1498Szrj gsi = gsi_last_nondebug_bb (load_bb);
625938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD);
626038fd1498Szrj
626138fd1498Szrj /* OpenMP does not imply any barrier-like semantics on its atomic ops.
626238fd1498Szrj It only requires that the operation happen atomically. Thus we can
626338fd1498Szrj use the RELAXED memory model. */
626438fd1498Szrj call = build_call_expr_loc (loc, decl, 3, addr,
626538fd1498Szrj fold_convert_loc (loc, itype, rhs),
626638fd1498Szrj build_int_cst (NULL,
626738fd1498Szrj seq_cst ? MEMMODEL_SEQ_CST
626838fd1498Szrj : MEMMODEL_RELAXED));
626938fd1498Szrj
627038fd1498Szrj if (need_old || need_new)
627138fd1498Szrj {
627238fd1498Szrj lhs = need_old ? loaded_val : stored_val;
627338fd1498Szrj call = fold_convert_loc (loc, TREE_TYPE (lhs), call);
627438fd1498Szrj call = build2_loc (loc, MODIFY_EXPR, void_type_node, lhs, call);
627538fd1498Szrj }
627638fd1498Szrj else
627738fd1498Szrj call = fold_convert_loc (loc, void_type_node, call);
627838fd1498Szrj force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT);
627938fd1498Szrj gsi_remove (&gsi, true);
628038fd1498Szrj
628138fd1498Szrj gsi = gsi_last_nondebug_bb (store_bb);
628238fd1498Szrj gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE);
628338fd1498Szrj gsi_remove (&gsi, true);
628438fd1498Szrj gsi = gsi_last_nondebug_bb (store_bb);
628538fd1498Szrj stmt = gsi_stmt (gsi);
628638fd1498Szrj gsi_remove (&gsi, true);
628738fd1498Szrj
628838fd1498Szrj if (gimple_in_ssa_p (cfun))
628938fd1498Szrj {
629038fd1498Szrj release_defs (stmt);
629138fd1498Szrj update_ssa (TODO_update_ssa_no_phi);
629238fd1498Szrj }
629338fd1498Szrj
629438fd1498Szrj return true;
629538fd1498Szrj }
629638fd1498Szrj
629738fd1498Szrj /* A subroutine of expand_omp_atomic. Implement the atomic operation as:
629838fd1498Szrj
629938fd1498Szrj oldval = *addr;
630038fd1498Szrj repeat:
630138fd1498Szrj newval = rhs; // with oldval replacing *addr in rhs
630238fd1498Szrj oldval = __sync_val_compare_and_swap (addr, oldval, newval);
630338fd1498Szrj if (oldval != newval)
630438fd1498Szrj goto repeat;
630538fd1498Szrj
630638fd1498Szrj INDEX is log2 of the size of the data type, and thus usable to find the
630738fd1498Szrj index of the builtin decl. */
630838fd1498Szrj
630938fd1498Szrj static bool
expand_omp_atomic_pipeline(basic_block load_bb,basic_block store_bb,tree addr,tree loaded_val,tree stored_val,int index)631038fd1498Szrj expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
631138fd1498Szrj tree addr, tree loaded_val, tree stored_val,
631238fd1498Szrj int index)
631338fd1498Szrj {
631438fd1498Szrj tree loadedi, storedi, initial, new_storedi, old_vali;
631538fd1498Szrj tree type, itype, cmpxchg, iaddr, atype;
631638fd1498Szrj gimple_stmt_iterator si;
631738fd1498Szrj basic_block loop_header = single_succ (load_bb);
631838fd1498Szrj gimple *phi, *stmt;
631938fd1498Szrj edge e;
632038fd1498Szrj enum built_in_function fncode;
632138fd1498Szrj
632238fd1498Szrj /* ??? We need a non-pointer interface to __atomic_compare_exchange in
632338fd1498Szrj order to use the RELAXED memory model effectively. */
632438fd1498Szrj fncode = (enum built_in_function)((int)BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N
632538fd1498Szrj + index + 1);
632638fd1498Szrj cmpxchg = builtin_decl_explicit (fncode);
632738fd1498Szrj if (cmpxchg == NULL_TREE)
632838fd1498Szrj return false;
632938fd1498Szrj type = TYPE_MAIN_VARIANT (TREE_TYPE (loaded_val));
633038fd1498Szrj atype = type;
633138fd1498Szrj itype = TREE_TYPE (TREE_TYPE (cmpxchg));
633238fd1498Szrj
633338fd1498Szrj if (!can_compare_and_swap_p (TYPE_MODE (itype), true)
633438fd1498Szrj || !can_atomic_load_p (TYPE_MODE (itype)))
633538fd1498Szrj return false;
633638fd1498Szrj
633738fd1498Szrj /* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
633838fd1498Szrj si = gsi_last_nondebug_bb (load_bb);
633938fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
634038fd1498Szrj
634138fd1498Szrj /* For floating-point values, we'll need to view-convert them to integers
634238fd1498Szrj so that we can perform the atomic compare and swap. Simplify the
634338fd1498Szrj following code by always setting up the "i"ntegral variables. */
634438fd1498Szrj if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
634538fd1498Szrj {
634638fd1498Szrj tree iaddr_val;
634738fd1498Szrj
634838fd1498Szrj iaddr = create_tmp_reg (build_pointer_type_for_mode (itype, ptr_mode,
634938fd1498Szrj true));
635038fd1498Szrj atype = itype;
635138fd1498Szrj iaddr_val
635238fd1498Szrj = force_gimple_operand_gsi (&si,
635338fd1498Szrj fold_convert (TREE_TYPE (iaddr), addr),
635438fd1498Szrj false, NULL_TREE, true, GSI_SAME_STMT);
635538fd1498Szrj stmt = gimple_build_assign (iaddr, iaddr_val);
635638fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
635738fd1498Szrj loadedi = create_tmp_var (itype);
635838fd1498Szrj if (gimple_in_ssa_p (cfun))
635938fd1498Szrj loadedi = make_ssa_name (loadedi);
636038fd1498Szrj }
636138fd1498Szrj else
636238fd1498Szrj {
636338fd1498Szrj iaddr = addr;
636438fd1498Szrj loadedi = loaded_val;
636538fd1498Szrj }
636638fd1498Szrj
636738fd1498Szrj fncode = (enum built_in_function) (BUILT_IN_ATOMIC_LOAD_N + index + 1);
636838fd1498Szrj tree loaddecl = builtin_decl_explicit (fncode);
636938fd1498Szrj if (loaddecl)
637038fd1498Szrj initial
637138fd1498Szrj = fold_convert (atype,
637238fd1498Szrj build_call_expr (loaddecl, 2, iaddr,
637338fd1498Szrj build_int_cst (NULL_TREE,
637438fd1498Szrj MEMMODEL_RELAXED)));
637538fd1498Szrj else
637638fd1498Szrj {
637738fd1498Szrj tree off
637838fd1498Szrj = build_int_cst (build_pointer_type_for_mode (atype, ptr_mode,
637938fd1498Szrj true), 0);
638038fd1498Szrj initial = build2 (MEM_REF, atype, iaddr, off);
638138fd1498Szrj }
638238fd1498Szrj
638338fd1498Szrj initial
638438fd1498Szrj = force_gimple_operand_gsi (&si, initial, true, NULL_TREE, true,
638538fd1498Szrj GSI_SAME_STMT);
638638fd1498Szrj
638738fd1498Szrj /* Move the value to the LOADEDI temporary. */
638838fd1498Szrj if (gimple_in_ssa_p (cfun))
638938fd1498Szrj {
639038fd1498Szrj gcc_assert (gimple_seq_empty_p (phi_nodes (loop_header)));
639138fd1498Szrj phi = create_phi_node (loadedi, loop_header);
639238fd1498Szrj SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, single_succ_edge (load_bb)),
639338fd1498Szrj initial);
639438fd1498Szrj }
639538fd1498Szrj else
639638fd1498Szrj gsi_insert_before (&si,
639738fd1498Szrj gimple_build_assign (loadedi, initial),
639838fd1498Szrj GSI_SAME_STMT);
639938fd1498Szrj if (loadedi != loaded_val)
640038fd1498Szrj {
640138fd1498Szrj gimple_stmt_iterator gsi2;
640238fd1498Szrj tree x;
640338fd1498Szrj
640438fd1498Szrj x = build1 (VIEW_CONVERT_EXPR, type, loadedi);
640538fd1498Szrj gsi2 = gsi_start_bb (loop_header);
640638fd1498Szrj if (gimple_in_ssa_p (cfun))
640738fd1498Szrj {
640838fd1498Szrj gassign *stmt;
640938fd1498Szrj x = force_gimple_operand_gsi (&gsi2, x, true, NULL_TREE,
641038fd1498Szrj true, GSI_SAME_STMT);
641138fd1498Szrj stmt = gimple_build_assign (loaded_val, x);
641238fd1498Szrj gsi_insert_before (&gsi2, stmt, GSI_SAME_STMT);
641338fd1498Szrj }
641438fd1498Szrj else
641538fd1498Szrj {
641638fd1498Szrj x = build2 (MODIFY_EXPR, TREE_TYPE (loaded_val), loaded_val, x);
641738fd1498Szrj force_gimple_operand_gsi (&gsi2, x, true, NULL_TREE,
641838fd1498Szrj true, GSI_SAME_STMT);
641938fd1498Szrj }
642038fd1498Szrj }
642138fd1498Szrj gsi_remove (&si, true);
642238fd1498Szrj
642338fd1498Szrj si = gsi_last_nondebug_bb (store_bb);
642438fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
642538fd1498Szrj
642638fd1498Szrj if (iaddr == addr)
642738fd1498Szrj storedi = stored_val;
642838fd1498Szrj else
642938fd1498Szrj storedi
643038fd1498Szrj = force_gimple_operand_gsi (&si,
643138fd1498Szrj build1 (VIEW_CONVERT_EXPR, itype,
643238fd1498Szrj stored_val), true, NULL_TREE, true,
643338fd1498Szrj GSI_SAME_STMT);
643438fd1498Szrj
643538fd1498Szrj /* Build the compare&swap statement. */
643638fd1498Szrj new_storedi = build_call_expr (cmpxchg, 3, iaddr, loadedi, storedi);
643738fd1498Szrj new_storedi = force_gimple_operand_gsi (&si,
643838fd1498Szrj fold_convert (TREE_TYPE (loadedi),
643938fd1498Szrj new_storedi),
644038fd1498Szrj true, NULL_TREE,
644138fd1498Szrj true, GSI_SAME_STMT);
644238fd1498Szrj
644338fd1498Szrj if (gimple_in_ssa_p (cfun))
644438fd1498Szrj old_vali = loadedi;
644538fd1498Szrj else
644638fd1498Szrj {
644738fd1498Szrj old_vali = create_tmp_var (TREE_TYPE (loadedi));
644838fd1498Szrj stmt = gimple_build_assign (old_vali, loadedi);
644938fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
645038fd1498Szrj
645138fd1498Szrj stmt = gimple_build_assign (loadedi, new_storedi);
645238fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
645338fd1498Szrj }
645438fd1498Szrj
645538fd1498Szrj /* Note that we always perform the comparison as an integer, even for
645638fd1498Szrj floating point. This allows the atomic operation to properly
645738fd1498Szrj succeed even with NaNs and -0.0. */
645838fd1498Szrj tree ne = build2 (NE_EXPR, boolean_type_node, new_storedi, old_vali);
645938fd1498Szrj stmt = gimple_build_cond_empty (ne);
646038fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
646138fd1498Szrj
646238fd1498Szrj /* Update cfg. */
646338fd1498Szrj e = single_succ_edge (store_bb);
646438fd1498Szrj e->flags &= ~EDGE_FALLTHRU;
646538fd1498Szrj e->flags |= EDGE_FALSE_VALUE;
646638fd1498Szrj /* Expect no looping. */
646738fd1498Szrj e->probability = profile_probability::guessed_always ();
646838fd1498Szrj
646938fd1498Szrj e = make_edge (store_bb, loop_header, EDGE_TRUE_VALUE);
647038fd1498Szrj e->probability = profile_probability::guessed_never ();
647138fd1498Szrj
647238fd1498Szrj /* Copy the new value to loadedi (we already did that before the condition
647338fd1498Szrj if we are not in SSA). */
647438fd1498Szrj if (gimple_in_ssa_p (cfun))
647538fd1498Szrj {
647638fd1498Szrj phi = gimple_seq_first_stmt (phi_nodes (loop_header));
647738fd1498Szrj SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), new_storedi);
647838fd1498Szrj }
647938fd1498Szrj
648038fd1498Szrj /* Remove GIMPLE_OMP_ATOMIC_STORE. */
648138fd1498Szrj gsi_remove (&si, true);
648238fd1498Szrj
648338fd1498Szrj struct loop *loop = alloc_loop ();
648438fd1498Szrj loop->header = loop_header;
648538fd1498Szrj loop->latch = store_bb;
648638fd1498Szrj add_loop (loop, loop_header->loop_father);
648738fd1498Szrj
648838fd1498Szrj if (gimple_in_ssa_p (cfun))
648938fd1498Szrj update_ssa (TODO_update_ssa_no_phi);
649038fd1498Szrj
649138fd1498Szrj return true;
649238fd1498Szrj }
649338fd1498Szrj
649438fd1498Szrj /* A subroutine of expand_omp_atomic. Implement the atomic operation as:
649538fd1498Szrj
649638fd1498Szrj GOMP_atomic_start ();
649738fd1498Szrj *addr = rhs;
649838fd1498Szrj GOMP_atomic_end ();
649938fd1498Szrj
650038fd1498Szrj The result is not globally atomic, but works so long as all parallel
650138fd1498Szrj references are within #pragma omp atomic directives. According to
650238fd1498Szrj responses received from omp@openmp.org, appears to be within spec.
650338fd1498Szrj Which makes sense, since that's how several other compilers handle
650438fd1498Szrj this situation as well.
650538fd1498Szrj LOADED_VAL and ADDR are the operands of GIMPLE_OMP_ATOMIC_LOAD we're
650638fd1498Szrj expanding. STORED_VAL is the operand of the matching
650738fd1498Szrj GIMPLE_OMP_ATOMIC_STORE.
650838fd1498Szrj
650938fd1498Szrj We replace
651038fd1498Szrj GIMPLE_OMP_ATOMIC_LOAD (loaded_val, addr) with
651138fd1498Szrj loaded_val = *addr;
651238fd1498Szrj
651338fd1498Szrj and replace
651438fd1498Szrj GIMPLE_OMP_ATOMIC_STORE (stored_val) with
651538fd1498Szrj *addr = stored_val;
651638fd1498Szrj */
651738fd1498Szrj
651838fd1498Szrj static bool
expand_omp_atomic_mutex(basic_block load_bb,basic_block store_bb,tree addr,tree loaded_val,tree stored_val)651938fd1498Szrj expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
652038fd1498Szrj tree addr, tree loaded_val, tree stored_val)
652138fd1498Szrj {
652238fd1498Szrj gimple_stmt_iterator si;
652338fd1498Szrj gassign *stmt;
652438fd1498Szrj tree t;
652538fd1498Szrj
652638fd1498Szrj si = gsi_last_nondebug_bb (load_bb);
652738fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_LOAD);
652838fd1498Szrj
652938fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
653038fd1498Szrj t = build_call_expr (t, 0);
653138fd1498Szrj force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT);
653238fd1498Szrj
653338fd1498Szrj tree mem = build_simple_mem_ref (addr);
653438fd1498Szrj TREE_TYPE (mem) = TREE_TYPE (loaded_val);
653538fd1498Szrj TREE_OPERAND (mem, 1)
653638fd1498Szrj = fold_convert (build_pointer_type_for_mode (TREE_TYPE (mem), ptr_mode,
653738fd1498Szrj true),
653838fd1498Szrj TREE_OPERAND (mem, 1));
653938fd1498Szrj stmt = gimple_build_assign (loaded_val, mem);
654038fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
654138fd1498Szrj gsi_remove (&si, true);
654238fd1498Szrj
654338fd1498Szrj si = gsi_last_nondebug_bb (store_bb);
654438fd1498Szrj gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
654538fd1498Szrj
654638fd1498Szrj stmt = gimple_build_assign (unshare_expr (mem), stored_val);
654738fd1498Szrj gsi_insert_before (&si, stmt, GSI_SAME_STMT);
654838fd1498Szrj
654938fd1498Szrj t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
655038fd1498Szrj t = build_call_expr (t, 0);
655138fd1498Szrj force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT);
655238fd1498Szrj gsi_remove (&si, true);
655338fd1498Szrj
655438fd1498Szrj if (gimple_in_ssa_p (cfun))
655538fd1498Szrj update_ssa (TODO_update_ssa_no_phi);
655638fd1498Szrj return true;
655738fd1498Szrj }
655838fd1498Szrj
655938fd1498Szrj /* Expand an GIMPLE_OMP_ATOMIC statement. We try to expand
656038fd1498Szrj using expand_omp_atomic_fetch_op. If it failed, we try to
656138fd1498Szrj call expand_omp_atomic_pipeline, and if it fails too, the
656238fd1498Szrj ultimate fallback is wrapping the operation in a mutex
656338fd1498Szrj (expand_omp_atomic_mutex). REGION is the atomic region built
656438fd1498Szrj by build_omp_regions_1(). */
656538fd1498Szrj
656638fd1498Szrj static void
expand_omp_atomic(struct omp_region * region)656738fd1498Szrj expand_omp_atomic (struct omp_region *region)
656838fd1498Szrj {
656938fd1498Szrj basic_block load_bb = region->entry, store_bb = region->exit;
657038fd1498Szrj gomp_atomic_load *load = as_a <gomp_atomic_load *> (last_stmt (load_bb));
657138fd1498Szrj gomp_atomic_store *store = as_a <gomp_atomic_store *> (last_stmt (store_bb));
657238fd1498Szrj tree loaded_val = gimple_omp_atomic_load_lhs (load);
657338fd1498Szrj tree addr = gimple_omp_atomic_load_rhs (load);
657438fd1498Szrj tree stored_val = gimple_omp_atomic_store_val (store);
657538fd1498Szrj tree type = TYPE_MAIN_VARIANT (TREE_TYPE (loaded_val));
657638fd1498Szrj HOST_WIDE_INT index;
657738fd1498Szrj
657838fd1498Szrj /* Make sure the type is one of the supported sizes. */
657938fd1498Szrj index = tree_to_uhwi (TYPE_SIZE_UNIT (type));
658038fd1498Szrj index = exact_log2 (index);
658138fd1498Szrj if (index >= 0 && index <= 4)
658238fd1498Szrj {
658338fd1498Szrj unsigned int align = TYPE_ALIGN_UNIT (type);
658438fd1498Szrj
658538fd1498Szrj /* __sync builtins require strict data alignment. */
658638fd1498Szrj if (exact_log2 (align) >= index)
658738fd1498Szrj {
658838fd1498Szrj /* Atomic load. */
658938fd1498Szrj scalar_mode smode;
659038fd1498Szrj if (loaded_val == stored_val
659138fd1498Szrj && (is_int_mode (TYPE_MODE (type), &smode)
659238fd1498Szrj || is_float_mode (TYPE_MODE (type), &smode))
659338fd1498Szrj && GET_MODE_BITSIZE (smode) <= BITS_PER_WORD
659438fd1498Szrj && expand_omp_atomic_load (load_bb, addr, loaded_val, index))
659538fd1498Szrj return;
659638fd1498Szrj
659738fd1498Szrj /* Atomic store. */
659838fd1498Szrj if ((is_int_mode (TYPE_MODE (type), &smode)
659938fd1498Szrj || is_float_mode (TYPE_MODE (type), &smode))
660038fd1498Szrj && GET_MODE_BITSIZE (smode) <= BITS_PER_WORD
660138fd1498Szrj && store_bb == single_succ (load_bb)
660238fd1498Szrj && first_stmt (store_bb) == store
660338fd1498Szrj && expand_omp_atomic_store (load_bb, addr, loaded_val,
660438fd1498Szrj stored_val, index))
660538fd1498Szrj return;
660638fd1498Szrj
660738fd1498Szrj /* When possible, use specialized atomic update functions. */
660838fd1498Szrj if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
660938fd1498Szrj && store_bb == single_succ (load_bb)
661038fd1498Szrj && expand_omp_atomic_fetch_op (load_bb, addr,
661138fd1498Szrj loaded_val, stored_val, index))
661238fd1498Szrj return;
661338fd1498Szrj
661438fd1498Szrj /* If we don't have specialized __sync builtins, try and implement
661538fd1498Szrj as a compare and swap loop. */
661638fd1498Szrj if (expand_omp_atomic_pipeline (load_bb, store_bb, addr,
661738fd1498Szrj loaded_val, stored_val, index))
661838fd1498Szrj return;
661938fd1498Szrj }
662038fd1498Szrj }
662138fd1498Szrj
662238fd1498Szrj /* The ultimate fallback is wrapping the operation in a mutex. */
662338fd1498Szrj expand_omp_atomic_mutex (load_bb, store_bb, addr, loaded_val, stored_val);
662438fd1498Szrj }
662538fd1498Szrj
662638fd1498Szrj /* Mark the loops inside the kernels region starting at REGION_ENTRY and ending
662738fd1498Szrj at REGION_EXIT. */
662838fd1498Szrj
662938fd1498Szrj static void
mark_loops_in_oacc_kernels_region(basic_block region_entry,basic_block region_exit)663038fd1498Szrj mark_loops_in_oacc_kernels_region (basic_block region_entry,
663138fd1498Szrj basic_block region_exit)
663238fd1498Szrj {
663338fd1498Szrj struct loop *outer = region_entry->loop_father;
663438fd1498Szrj gcc_assert (region_exit == NULL || outer == region_exit->loop_father);
663538fd1498Szrj
663638fd1498Szrj /* Don't parallelize the kernels region if it contains more than one outer
663738fd1498Szrj loop. */
663838fd1498Szrj unsigned int nr_outer_loops = 0;
663938fd1498Szrj struct loop *single_outer = NULL;
664038fd1498Szrj for (struct loop *loop = outer->inner; loop != NULL; loop = loop->next)
664138fd1498Szrj {
664238fd1498Szrj gcc_assert (loop_outer (loop) == outer);
664338fd1498Szrj
664438fd1498Szrj if (!dominated_by_p (CDI_DOMINATORS, loop->header, region_entry))
664538fd1498Szrj continue;
664638fd1498Szrj
664738fd1498Szrj if (region_exit != NULL
664838fd1498Szrj && dominated_by_p (CDI_DOMINATORS, loop->header, region_exit))
664938fd1498Szrj continue;
665038fd1498Szrj
665138fd1498Szrj nr_outer_loops++;
665238fd1498Szrj single_outer = loop;
665338fd1498Szrj }
665438fd1498Szrj if (nr_outer_loops != 1)
665538fd1498Szrj return;
665638fd1498Szrj
665738fd1498Szrj for (struct loop *loop = single_outer->inner;
665838fd1498Szrj loop != NULL;
665938fd1498Szrj loop = loop->inner)
666038fd1498Szrj if (loop->next)
666138fd1498Szrj return;
666238fd1498Szrj
666338fd1498Szrj /* Mark the loops in the region. */
666438fd1498Szrj for (struct loop *loop = single_outer; loop != NULL; loop = loop->inner)
666538fd1498Szrj loop->in_oacc_kernels_region = true;
666638fd1498Szrj }
666738fd1498Szrj
666838fd1498Szrj /* Types used to pass grid and wortkgroup sizes to kernel invocation. */
666938fd1498Szrj
667038fd1498Szrj struct GTY(()) grid_launch_attributes_trees
667138fd1498Szrj {
667238fd1498Szrj tree kernel_dim_array_type;
667338fd1498Szrj tree kernel_lattrs_dimnum_decl;
667438fd1498Szrj tree kernel_lattrs_grid_decl;
667538fd1498Szrj tree kernel_lattrs_group_decl;
667638fd1498Szrj tree kernel_launch_attributes_type;
667738fd1498Szrj };
667838fd1498Szrj
667938fd1498Szrj static GTY(()) struct grid_launch_attributes_trees *grid_attr_trees;
668038fd1498Szrj
668138fd1498Szrj /* Create types used to pass kernel launch attributes to target. */
668238fd1498Szrj
668338fd1498Szrj static void
grid_create_kernel_launch_attr_types(void)668438fd1498Szrj grid_create_kernel_launch_attr_types (void)
668538fd1498Szrj {
668638fd1498Szrj if (grid_attr_trees)
668738fd1498Szrj return;
668838fd1498Szrj grid_attr_trees = ggc_alloc <grid_launch_attributes_trees> ();
668938fd1498Szrj
669038fd1498Szrj tree dim_arr_index_type
669138fd1498Szrj = build_index_type (build_int_cst (integer_type_node, 2));
669238fd1498Szrj grid_attr_trees->kernel_dim_array_type
669338fd1498Szrj = build_array_type (uint32_type_node, dim_arr_index_type);
669438fd1498Szrj
669538fd1498Szrj grid_attr_trees->kernel_launch_attributes_type = make_node (RECORD_TYPE);
669638fd1498Szrj grid_attr_trees->kernel_lattrs_dimnum_decl
669738fd1498Szrj = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("ndim"),
669838fd1498Szrj uint32_type_node);
669938fd1498Szrj DECL_CHAIN (grid_attr_trees->kernel_lattrs_dimnum_decl) = NULL_TREE;
670038fd1498Szrj
670138fd1498Szrj grid_attr_trees->kernel_lattrs_grid_decl
670238fd1498Szrj = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("grid_size"),
670338fd1498Szrj grid_attr_trees->kernel_dim_array_type);
670438fd1498Szrj DECL_CHAIN (grid_attr_trees->kernel_lattrs_grid_decl)
670538fd1498Szrj = grid_attr_trees->kernel_lattrs_dimnum_decl;
670638fd1498Szrj grid_attr_trees->kernel_lattrs_group_decl
670738fd1498Szrj = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("group_size"),
670838fd1498Szrj grid_attr_trees->kernel_dim_array_type);
670938fd1498Szrj DECL_CHAIN (grid_attr_trees->kernel_lattrs_group_decl)
671038fd1498Szrj = grid_attr_trees->kernel_lattrs_grid_decl;
671138fd1498Szrj finish_builtin_struct (grid_attr_trees->kernel_launch_attributes_type,
671238fd1498Szrj "__gomp_kernel_launch_attributes",
671338fd1498Szrj grid_attr_trees->kernel_lattrs_group_decl, NULL_TREE);
671438fd1498Szrj }
671538fd1498Szrj
671638fd1498Szrj /* Insert before the current statement in GSI a store of VALUE to INDEX of
671738fd1498Szrj array (of type kernel_dim_array_type) FLD_DECL of RANGE_VAR. VALUE must be
671838fd1498Szrj of type uint32_type_node. */
671938fd1498Szrj
672038fd1498Szrj static void
grid_insert_store_range_dim(gimple_stmt_iterator * gsi,tree range_var,tree fld_decl,int index,tree value)672138fd1498Szrj grid_insert_store_range_dim (gimple_stmt_iterator *gsi, tree range_var,
672238fd1498Szrj tree fld_decl, int index, tree value)
672338fd1498Szrj {
672438fd1498Szrj tree ref = build4 (ARRAY_REF, uint32_type_node,
672538fd1498Szrj build3 (COMPONENT_REF,
672638fd1498Szrj grid_attr_trees->kernel_dim_array_type,
672738fd1498Szrj range_var, fld_decl, NULL_TREE),
672838fd1498Szrj build_int_cst (integer_type_node, index),
672938fd1498Szrj NULL_TREE, NULL_TREE);
673038fd1498Szrj gsi_insert_before (gsi, gimple_build_assign (ref, value), GSI_SAME_STMT);
673138fd1498Szrj }
673238fd1498Szrj
673338fd1498Szrj /* Return a tree representation of a pointer to a structure with grid and
673438fd1498Szrj work-group size information. Statements filling that information will be
673538fd1498Szrj inserted before GSI, TGT_STMT is the target statement which has the
673638fd1498Szrj necessary information in it. */
673738fd1498Szrj
673838fd1498Szrj static tree
grid_get_kernel_launch_attributes(gimple_stmt_iterator * gsi,gomp_target * tgt_stmt)673938fd1498Szrj grid_get_kernel_launch_attributes (gimple_stmt_iterator *gsi,
674038fd1498Szrj gomp_target *tgt_stmt)
674138fd1498Szrj {
674238fd1498Szrj grid_create_kernel_launch_attr_types ();
674338fd1498Szrj tree lattrs = create_tmp_var (grid_attr_trees->kernel_launch_attributes_type,
674438fd1498Szrj "__kernel_launch_attrs");
674538fd1498Szrj
674638fd1498Szrj unsigned max_dim = 0;
674738fd1498Szrj for (tree clause = gimple_omp_target_clauses (tgt_stmt);
674838fd1498Szrj clause;
674938fd1498Szrj clause = OMP_CLAUSE_CHAIN (clause))
675038fd1498Szrj {
675138fd1498Szrj if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE__GRIDDIM_)
675238fd1498Szrj continue;
675338fd1498Szrj
675438fd1498Szrj unsigned dim = OMP_CLAUSE__GRIDDIM__DIMENSION (clause);
675538fd1498Szrj max_dim = MAX (dim, max_dim);
675638fd1498Szrj
675738fd1498Szrj grid_insert_store_range_dim (gsi, lattrs,
675838fd1498Szrj grid_attr_trees->kernel_lattrs_grid_decl,
675938fd1498Szrj dim, OMP_CLAUSE__GRIDDIM__SIZE (clause));
676038fd1498Szrj grid_insert_store_range_dim (gsi, lattrs,
676138fd1498Szrj grid_attr_trees->kernel_lattrs_group_decl,
676238fd1498Szrj dim, OMP_CLAUSE__GRIDDIM__GROUP (clause));
676338fd1498Szrj }
676438fd1498Szrj
676538fd1498Szrj tree dimref = build3 (COMPONENT_REF, uint32_type_node, lattrs,
676638fd1498Szrj grid_attr_trees->kernel_lattrs_dimnum_decl, NULL_TREE);
676738fd1498Szrj gcc_checking_assert (max_dim <= 2);
676838fd1498Szrj tree dimensions = build_int_cstu (uint32_type_node, max_dim + 1);
676938fd1498Szrj gsi_insert_before (gsi, gimple_build_assign (dimref, dimensions),
677038fd1498Szrj GSI_SAME_STMT);
677138fd1498Szrj TREE_ADDRESSABLE (lattrs) = 1;
677238fd1498Szrj return build_fold_addr_expr (lattrs);
677338fd1498Szrj }
677438fd1498Szrj
677538fd1498Szrj /* Build target argument identifier from the DEVICE identifier, value
677638fd1498Szrj identifier ID and whether the element also has a SUBSEQUENT_PARAM. */
677738fd1498Szrj
677838fd1498Szrj static tree
get_target_argument_identifier_1(int device,bool subseqent_param,int id)677938fd1498Szrj get_target_argument_identifier_1 (int device, bool subseqent_param, int id)
678038fd1498Szrj {
678138fd1498Szrj tree t = build_int_cst (integer_type_node, device);
678238fd1498Szrj if (subseqent_param)
678338fd1498Szrj t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
678438fd1498Szrj build_int_cst (integer_type_node,
678538fd1498Szrj GOMP_TARGET_ARG_SUBSEQUENT_PARAM));
678638fd1498Szrj t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
678738fd1498Szrj build_int_cst (integer_type_node, id));
678838fd1498Szrj return t;
678938fd1498Szrj }
679038fd1498Szrj
679138fd1498Szrj /* Like above but return it in type that can be directly stored as an element
679238fd1498Szrj of the argument array. */
679338fd1498Szrj
679438fd1498Szrj static tree
get_target_argument_identifier(int device,bool subseqent_param,int id)679538fd1498Szrj get_target_argument_identifier (int device, bool subseqent_param, int id)
679638fd1498Szrj {
679738fd1498Szrj tree t = get_target_argument_identifier_1 (device, subseqent_param, id);
679838fd1498Szrj return fold_convert (ptr_type_node, t);
679938fd1498Szrj }
680038fd1498Szrj
680138fd1498Szrj /* Return a target argument consisting of DEVICE identifier, value identifier
680238fd1498Szrj ID, and the actual VALUE. */
680338fd1498Szrj
680438fd1498Szrj static tree
get_target_argument_value(gimple_stmt_iterator * gsi,int device,int id,tree value)680538fd1498Szrj get_target_argument_value (gimple_stmt_iterator *gsi, int device, int id,
680638fd1498Szrj tree value)
680738fd1498Szrj {
680838fd1498Szrj tree t = fold_build2 (LSHIFT_EXPR, integer_type_node,
680938fd1498Szrj fold_convert (integer_type_node, value),
681038fd1498Szrj build_int_cst (unsigned_type_node,
681138fd1498Szrj GOMP_TARGET_ARG_VALUE_SHIFT));
681238fd1498Szrj t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
681338fd1498Szrj get_target_argument_identifier_1 (device, false, id));
681438fd1498Szrj t = fold_convert (ptr_type_node, t);
681538fd1498Szrj return force_gimple_operand_gsi (gsi, t, true, NULL, true, GSI_SAME_STMT);
681638fd1498Szrj }
681738fd1498Szrj
681838fd1498Szrj /* If VALUE is an integer constant greater than -2^15 and smaller than 2^15,
681938fd1498Szrj push one argument to ARGS with both the DEVICE, ID and VALUE embedded in it,
682038fd1498Szrj otherwise push an identifier (with DEVICE and ID) and the VALUE in two
682138fd1498Szrj arguments. */
682238fd1498Szrj
682338fd1498Szrj static void
push_target_argument_according_to_value(gimple_stmt_iterator * gsi,int device,int id,tree value,vec<tree> * args)682438fd1498Szrj push_target_argument_according_to_value (gimple_stmt_iterator *gsi, int device,
682538fd1498Szrj int id, tree value, vec <tree> *args)
682638fd1498Szrj {
682738fd1498Szrj if (tree_fits_shwi_p (value)
682838fd1498Szrj && tree_to_shwi (value) > -(1 << 15)
682938fd1498Szrj && tree_to_shwi (value) < (1 << 15))
683038fd1498Szrj args->quick_push (get_target_argument_value (gsi, device, id, value));
683138fd1498Szrj else
683238fd1498Szrj {
683338fd1498Szrj args->quick_push (get_target_argument_identifier (device, true, id));
683438fd1498Szrj value = fold_convert (ptr_type_node, value);
683538fd1498Szrj value = force_gimple_operand_gsi (gsi, value, true, NULL, true,
683638fd1498Szrj GSI_SAME_STMT);
683738fd1498Szrj args->quick_push (value);
683838fd1498Szrj }
683938fd1498Szrj }
684038fd1498Szrj
684138fd1498Szrj /* Create an array of arguments that is then passed to GOMP_target. */
684238fd1498Szrj
684338fd1498Szrj static tree
get_target_arguments(gimple_stmt_iterator * gsi,gomp_target * tgt_stmt)684438fd1498Szrj get_target_arguments (gimple_stmt_iterator *gsi, gomp_target *tgt_stmt)
684538fd1498Szrj {
684638fd1498Szrj auto_vec <tree, 6> args;
684738fd1498Szrj tree clauses = gimple_omp_target_clauses (tgt_stmt);
684838fd1498Szrj tree t, c = omp_find_clause (clauses, OMP_CLAUSE_NUM_TEAMS);
684938fd1498Szrj if (c)
685038fd1498Szrj t = OMP_CLAUSE_NUM_TEAMS_EXPR (c);
685138fd1498Szrj else
685238fd1498Szrj t = integer_minus_one_node;
685338fd1498Szrj push_target_argument_according_to_value (gsi, GOMP_TARGET_ARG_DEVICE_ALL,
685438fd1498Szrj GOMP_TARGET_ARG_NUM_TEAMS, t, &args);
685538fd1498Szrj
685638fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_THREAD_LIMIT);
685738fd1498Szrj if (c)
685838fd1498Szrj t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c);
685938fd1498Szrj else
686038fd1498Szrj t = integer_minus_one_node;
686138fd1498Szrj push_target_argument_according_to_value (gsi, GOMP_TARGET_ARG_DEVICE_ALL,
686238fd1498Szrj GOMP_TARGET_ARG_THREAD_LIMIT, t,
686338fd1498Szrj &args);
686438fd1498Szrj
686538fd1498Szrj /* Add HSA-specific grid sizes, if available. */
686638fd1498Szrj if (omp_find_clause (gimple_omp_target_clauses (tgt_stmt),
686738fd1498Szrj OMP_CLAUSE__GRIDDIM_))
686838fd1498Szrj {
686938fd1498Szrj int id = GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES;
687038fd1498Szrj t = get_target_argument_identifier (GOMP_DEVICE_HSA, true, id);
687138fd1498Szrj args.quick_push (t);
687238fd1498Szrj args.quick_push (grid_get_kernel_launch_attributes (gsi, tgt_stmt));
687338fd1498Szrj }
687438fd1498Szrj
687538fd1498Szrj /* Produce more, perhaps device specific, arguments here. */
687638fd1498Szrj
687738fd1498Szrj tree argarray = create_tmp_var (build_array_type_nelts (ptr_type_node,
687838fd1498Szrj args.length () + 1),
687938fd1498Szrj ".omp_target_args");
688038fd1498Szrj for (unsigned i = 0; i < args.length (); i++)
688138fd1498Szrj {
688238fd1498Szrj tree ref = build4 (ARRAY_REF, ptr_type_node, argarray,
688338fd1498Szrj build_int_cst (integer_type_node, i),
688438fd1498Szrj NULL_TREE, NULL_TREE);
688538fd1498Szrj gsi_insert_before (gsi, gimple_build_assign (ref, args[i]),
688638fd1498Szrj GSI_SAME_STMT);
688738fd1498Szrj }
688838fd1498Szrj tree ref = build4 (ARRAY_REF, ptr_type_node, argarray,
688938fd1498Szrj build_int_cst (integer_type_node, args.length ()),
689038fd1498Szrj NULL_TREE, NULL_TREE);
689138fd1498Szrj gsi_insert_before (gsi, gimple_build_assign (ref, null_pointer_node),
689238fd1498Szrj GSI_SAME_STMT);
689338fd1498Szrj TREE_ADDRESSABLE (argarray) = 1;
689438fd1498Szrj return build_fold_addr_expr (argarray);
689538fd1498Szrj }
689638fd1498Szrj
689738fd1498Szrj /* Expand the GIMPLE_OMP_TARGET starting at REGION. */
689838fd1498Szrj
689938fd1498Szrj static void
expand_omp_target(struct omp_region * region)690038fd1498Szrj expand_omp_target (struct omp_region *region)
690138fd1498Szrj {
690238fd1498Szrj basic_block entry_bb, exit_bb, new_bb;
690338fd1498Szrj struct function *child_cfun;
690438fd1498Szrj tree child_fn, block, t;
690538fd1498Szrj gimple_stmt_iterator gsi;
690638fd1498Szrj gomp_target *entry_stmt;
690738fd1498Szrj gimple *stmt;
690838fd1498Szrj edge e;
690938fd1498Szrj bool offloaded, data_region;
691038fd1498Szrj
691138fd1498Szrj entry_stmt = as_a <gomp_target *> (last_stmt (region->entry));
691238fd1498Szrj new_bb = region->entry;
691338fd1498Szrj
691438fd1498Szrj offloaded = is_gimple_omp_offloaded (entry_stmt);
691538fd1498Szrj switch (gimple_omp_target_kind (entry_stmt))
691638fd1498Szrj {
691738fd1498Szrj case GF_OMP_TARGET_KIND_REGION:
691838fd1498Szrj case GF_OMP_TARGET_KIND_UPDATE:
691938fd1498Szrj case GF_OMP_TARGET_KIND_ENTER_DATA:
692038fd1498Szrj case GF_OMP_TARGET_KIND_EXIT_DATA:
692138fd1498Szrj case GF_OMP_TARGET_KIND_OACC_PARALLEL:
692238fd1498Szrj case GF_OMP_TARGET_KIND_OACC_KERNELS:
692338fd1498Szrj case GF_OMP_TARGET_KIND_OACC_UPDATE:
692438fd1498Szrj case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
692538fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DECLARE:
692638fd1498Szrj data_region = false;
692738fd1498Szrj break;
692838fd1498Szrj case GF_OMP_TARGET_KIND_DATA:
692938fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DATA:
693038fd1498Szrj case GF_OMP_TARGET_KIND_OACC_HOST_DATA:
693138fd1498Szrj data_region = true;
693238fd1498Szrj break;
693338fd1498Szrj default:
693438fd1498Szrj gcc_unreachable ();
693538fd1498Szrj }
693638fd1498Szrj
693738fd1498Szrj child_fn = NULL_TREE;
693838fd1498Szrj child_cfun = NULL;
693938fd1498Szrj if (offloaded)
694038fd1498Szrj {
694138fd1498Szrj child_fn = gimple_omp_target_child_fn (entry_stmt);
694238fd1498Szrj child_cfun = DECL_STRUCT_FUNCTION (child_fn);
694338fd1498Szrj }
694438fd1498Szrj
694538fd1498Szrj /* Supported by expand_omp_taskreg, but not here. */
694638fd1498Szrj if (child_cfun != NULL)
694738fd1498Szrj gcc_checking_assert (!child_cfun->cfg);
694838fd1498Szrj gcc_checking_assert (!gimple_in_ssa_p (cfun));
694938fd1498Szrj
695038fd1498Szrj entry_bb = region->entry;
695138fd1498Szrj exit_bb = region->exit;
695238fd1498Szrj
695338fd1498Szrj if (gimple_omp_target_kind (entry_stmt) == GF_OMP_TARGET_KIND_OACC_KERNELS)
695438fd1498Szrj {
695538fd1498Szrj mark_loops_in_oacc_kernels_region (region->entry, region->exit);
695638fd1498Szrj
695738fd1498Szrj /* Further down, both OpenACC kernels and OpenACC parallel constructs
695838fd1498Szrj will be mappted to BUILT_IN_GOACC_PARALLEL, and to distinguish the
695938fd1498Szrj two, there is an "oacc kernels" attribute set for OpenACC kernels. */
696038fd1498Szrj DECL_ATTRIBUTES (child_fn)
696138fd1498Szrj = tree_cons (get_identifier ("oacc kernels"),
696238fd1498Szrj NULL_TREE, DECL_ATTRIBUTES (child_fn));
696338fd1498Szrj }
696438fd1498Szrj
696538fd1498Szrj if (offloaded)
696638fd1498Szrj {
696738fd1498Szrj unsigned srcidx, dstidx, num;
696838fd1498Szrj
696938fd1498Szrj /* If the offloading region needs data sent from the parent
697038fd1498Szrj function, then the very first statement (except possible
697138fd1498Szrj tree profile counter updates) of the offloading body
697238fd1498Szrj is a copy assignment .OMP_DATA_I = &.OMP_DATA_O. Since
697338fd1498Szrj &.OMP_DATA_O is passed as an argument to the child function,
697438fd1498Szrj we need to replace it with the argument as seen by the child
697538fd1498Szrj function.
697638fd1498Szrj
697738fd1498Szrj In most cases, this will end up being the identity assignment
697838fd1498Szrj .OMP_DATA_I = .OMP_DATA_I. However, if the offloading body had
697938fd1498Szrj a function call that has been inlined, the original PARM_DECL
698038fd1498Szrj .OMP_DATA_I may have been converted into a different local
698138fd1498Szrj variable. In which case, we need to keep the assignment. */
698238fd1498Szrj tree data_arg = gimple_omp_target_data_arg (entry_stmt);
698338fd1498Szrj if (data_arg)
698438fd1498Szrj {
698538fd1498Szrj basic_block entry_succ_bb = single_succ (entry_bb);
698638fd1498Szrj gimple_stmt_iterator gsi;
698738fd1498Szrj tree arg;
698838fd1498Szrj gimple *tgtcopy_stmt = NULL;
698938fd1498Szrj tree sender = TREE_VEC_ELT (data_arg, 0);
699038fd1498Szrj
699138fd1498Szrj for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi))
699238fd1498Szrj {
699338fd1498Szrj gcc_assert (!gsi_end_p (gsi));
699438fd1498Szrj stmt = gsi_stmt (gsi);
699538fd1498Szrj if (gimple_code (stmt) != GIMPLE_ASSIGN)
699638fd1498Szrj continue;
699738fd1498Szrj
699838fd1498Szrj if (gimple_num_ops (stmt) == 2)
699938fd1498Szrj {
700038fd1498Szrj tree arg = gimple_assign_rhs1 (stmt);
700138fd1498Szrj
700238fd1498Szrj /* We're ignoring the subcode because we're
700338fd1498Szrj effectively doing a STRIP_NOPS. */
700438fd1498Szrj
700538fd1498Szrj if (TREE_CODE (arg) == ADDR_EXPR
700638fd1498Szrj && TREE_OPERAND (arg, 0) == sender)
700738fd1498Szrj {
700838fd1498Szrj tgtcopy_stmt = stmt;
700938fd1498Szrj break;
701038fd1498Szrj }
701138fd1498Szrj }
701238fd1498Szrj }
701338fd1498Szrj
701438fd1498Szrj gcc_assert (tgtcopy_stmt != NULL);
701538fd1498Szrj arg = DECL_ARGUMENTS (child_fn);
701638fd1498Szrj
701738fd1498Szrj gcc_assert (gimple_assign_lhs (tgtcopy_stmt) == arg);
701838fd1498Szrj gsi_remove (&gsi, true);
701938fd1498Szrj }
702038fd1498Szrj
702138fd1498Szrj /* Declare local variables needed in CHILD_CFUN. */
702238fd1498Szrj block = DECL_INITIAL (child_fn);
702338fd1498Szrj BLOCK_VARS (block) = vec2chain (child_cfun->local_decls);
702438fd1498Szrj /* The gimplifier could record temporaries in the offloading block
702538fd1498Szrj rather than in containing function's local_decls chain,
702638fd1498Szrj which would mean cgraph missed finalizing them. Do it now. */
702738fd1498Szrj for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t))
702838fd1498Szrj if (VAR_P (t) && TREE_STATIC (t) && !DECL_EXTERNAL (t))
702938fd1498Szrj varpool_node::finalize_decl (t);
703038fd1498Szrj DECL_SAVED_TREE (child_fn) = NULL;
703138fd1498Szrj /* We'll create a CFG for child_fn, so no gimple body is needed. */
703238fd1498Szrj gimple_set_body (child_fn, NULL);
703338fd1498Szrj TREE_USED (block) = 1;
703438fd1498Szrj
703538fd1498Szrj /* Reset DECL_CONTEXT on function arguments. */
703638fd1498Szrj for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t))
703738fd1498Szrj DECL_CONTEXT (t) = child_fn;
703838fd1498Szrj
703938fd1498Szrj /* Split ENTRY_BB at GIMPLE_*,
704038fd1498Szrj so that it can be moved to the child function. */
704138fd1498Szrj gsi = gsi_last_nondebug_bb (entry_bb);
704238fd1498Szrj stmt = gsi_stmt (gsi);
704338fd1498Szrj gcc_assert (stmt
704438fd1498Szrj && gimple_code (stmt) == gimple_code (entry_stmt));
704538fd1498Szrj e = split_block (entry_bb, stmt);
704638fd1498Szrj gsi_remove (&gsi, true);
704738fd1498Szrj entry_bb = e->dest;
704838fd1498Szrj single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
704938fd1498Szrj
705038fd1498Szrj /* Convert GIMPLE_OMP_RETURN into a RETURN_EXPR. */
705138fd1498Szrj if (exit_bb)
705238fd1498Szrj {
705338fd1498Szrj gsi = gsi_last_nondebug_bb (exit_bb);
705438fd1498Szrj gcc_assert (!gsi_end_p (gsi)
705538fd1498Szrj && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
705638fd1498Szrj stmt = gimple_build_return (NULL);
705738fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
705838fd1498Szrj gsi_remove (&gsi, true);
705938fd1498Szrj }
706038fd1498Szrj
706138fd1498Szrj /* Move the offloading region into CHILD_CFUN. */
706238fd1498Szrj
706338fd1498Szrj block = gimple_block (entry_stmt);
706438fd1498Szrj
706538fd1498Szrj new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
706638fd1498Szrj if (exit_bb)
706738fd1498Szrj single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
706838fd1498Szrj /* When the OMP expansion process cannot guarantee an up-to-date
706938fd1498Szrj loop tree arrange for the child function to fixup loops. */
707038fd1498Szrj if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
707138fd1498Szrj child_cfun->x_current_loops->state |= LOOPS_NEED_FIXUP;
707238fd1498Szrj
707338fd1498Szrj /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */
707438fd1498Szrj num = vec_safe_length (child_cfun->local_decls);
707538fd1498Szrj for (srcidx = 0, dstidx = 0; srcidx < num; srcidx++)
707638fd1498Szrj {
707738fd1498Szrj t = (*child_cfun->local_decls)[srcidx];
707838fd1498Szrj if (DECL_CONTEXT (t) == cfun->decl)
707938fd1498Szrj continue;
708038fd1498Szrj if (srcidx != dstidx)
708138fd1498Szrj (*child_cfun->local_decls)[dstidx] = t;
708238fd1498Szrj dstidx++;
708338fd1498Szrj }
708438fd1498Szrj if (dstidx != num)
708538fd1498Szrj vec_safe_truncate (child_cfun->local_decls, dstidx);
708638fd1498Szrj
708738fd1498Szrj /* Inform the callgraph about the new function. */
708838fd1498Szrj child_cfun->curr_properties = cfun->curr_properties;
708938fd1498Szrj child_cfun->has_simduid_loops |= cfun->has_simduid_loops;
709038fd1498Szrj child_cfun->has_force_vectorize_loops |= cfun->has_force_vectorize_loops;
709138fd1498Szrj cgraph_node *node = cgraph_node::get_create (child_fn);
709238fd1498Szrj node->parallelized_function = 1;
709338fd1498Szrj cgraph_node::add_new_function (child_fn, true);
709438fd1498Szrj
709538fd1498Szrj /* Add the new function to the offload table. */
709638fd1498Szrj if (ENABLE_OFFLOADING)
709738fd1498Szrj {
709838fd1498Szrj if (in_lto_p)
709938fd1498Szrj DECL_PRESERVE_P (child_fn) = 1;
710038fd1498Szrj vec_safe_push (offload_funcs, child_fn);
710138fd1498Szrj }
710238fd1498Szrj
710338fd1498Szrj bool need_asm = DECL_ASSEMBLER_NAME_SET_P (current_function_decl)
710438fd1498Szrj && !DECL_ASSEMBLER_NAME_SET_P (child_fn);
710538fd1498Szrj
710638fd1498Szrj /* Fix the callgraph edges for child_cfun. Those for cfun will be
710738fd1498Szrj fixed in a following pass. */
710838fd1498Szrj push_cfun (child_cfun);
710938fd1498Szrj if (need_asm)
711038fd1498Szrj assign_assembler_name_if_needed (child_fn);
711138fd1498Szrj cgraph_edge::rebuild_edges ();
711238fd1498Szrj
711338fd1498Szrj /* Some EH regions might become dead, see PR34608. If
711438fd1498Szrj pass_cleanup_cfg isn't the first pass to happen with the
711538fd1498Szrj new child, these dead EH edges might cause problems.
711638fd1498Szrj Clean them up now. */
711738fd1498Szrj if (flag_exceptions)
711838fd1498Szrj {
711938fd1498Szrj basic_block bb;
712038fd1498Szrj bool changed = false;
712138fd1498Szrj
712238fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
712338fd1498Szrj changed |= gimple_purge_dead_eh_edges (bb);
712438fd1498Szrj if (changed)
712538fd1498Szrj cleanup_tree_cfg ();
712638fd1498Szrj }
712738fd1498Szrj if (flag_checking && !loops_state_satisfies_p (LOOPS_NEED_FIXUP))
712838fd1498Szrj verify_loop_structure ();
712938fd1498Szrj pop_cfun ();
713038fd1498Szrj
713138fd1498Szrj if (dump_file && !gimple_in_ssa_p (cfun))
713238fd1498Szrj {
713338fd1498Szrj omp_any_child_fn_dumped = true;
713438fd1498Szrj dump_function_header (dump_file, child_fn, dump_flags);
713538fd1498Szrj dump_function_to_file (child_fn, dump_file, dump_flags);
713638fd1498Szrj }
7137*58e805e6Szrj
7138*58e805e6Szrj adjust_context_and_scope (region, gimple_block (entry_stmt), child_fn);
713938fd1498Szrj }
714038fd1498Szrj
714138fd1498Szrj /* Emit a library call to launch the offloading region, or do data
714238fd1498Szrj transfers. */
714338fd1498Szrj tree t1, t2, t3, t4, device, cond, depend, c, clauses;
714438fd1498Szrj enum built_in_function start_ix;
714538fd1498Szrj location_t clause_loc;
714638fd1498Szrj unsigned int flags_i = 0;
714738fd1498Szrj
714838fd1498Szrj switch (gimple_omp_target_kind (entry_stmt))
714938fd1498Szrj {
715038fd1498Szrj case GF_OMP_TARGET_KIND_REGION:
715138fd1498Szrj start_ix = BUILT_IN_GOMP_TARGET;
715238fd1498Szrj break;
715338fd1498Szrj case GF_OMP_TARGET_KIND_DATA:
715438fd1498Szrj start_ix = BUILT_IN_GOMP_TARGET_DATA;
715538fd1498Szrj break;
715638fd1498Szrj case GF_OMP_TARGET_KIND_UPDATE:
715738fd1498Szrj start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
715838fd1498Szrj break;
715938fd1498Szrj case GF_OMP_TARGET_KIND_ENTER_DATA:
716038fd1498Szrj start_ix = BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA;
716138fd1498Szrj break;
716238fd1498Szrj case GF_OMP_TARGET_KIND_EXIT_DATA:
716338fd1498Szrj start_ix = BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA;
716438fd1498Szrj flags_i |= GOMP_TARGET_FLAG_EXIT_DATA;
716538fd1498Szrj break;
716638fd1498Szrj case GF_OMP_TARGET_KIND_OACC_KERNELS:
716738fd1498Szrj case GF_OMP_TARGET_KIND_OACC_PARALLEL:
716838fd1498Szrj start_ix = BUILT_IN_GOACC_PARALLEL;
716938fd1498Szrj break;
717038fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DATA:
717138fd1498Szrj case GF_OMP_TARGET_KIND_OACC_HOST_DATA:
717238fd1498Szrj start_ix = BUILT_IN_GOACC_DATA_START;
717338fd1498Szrj break;
717438fd1498Szrj case GF_OMP_TARGET_KIND_OACC_UPDATE:
717538fd1498Szrj start_ix = BUILT_IN_GOACC_UPDATE;
717638fd1498Szrj break;
717738fd1498Szrj case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
717838fd1498Szrj start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA;
717938fd1498Szrj break;
718038fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DECLARE:
718138fd1498Szrj start_ix = BUILT_IN_GOACC_DECLARE;
718238fd1498Szrj break;
718338fd1498Szrj default:
718438fd1498Szrj gcc_unreachable ();
718538fd1498Szrj }
718638fd1498Szrj
718738fd1498Szrj clauses = gimple_omp_target_clauses (entry_stmt);
718838fd1498Szrj
718938fd1498Szrj /* By default, the value of DEVICE is GOMP_DEVICE_ICV (let runtime
719038fd1498Szrj library choose) and there is no conditional. */
719138fd1498Szrj cond = NULL_TREE;
719238fd1498Szrj device = build_int_cst (integer_type_node, GOMP_DEVICE_ICV);
719338fd1498Szrj
719438fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_IF);
719538fd1498Szrj if (c)
719638fd1498Szrj cond = OMP_CLAUSE_IF_EXPR (c);
719738fd1498Szrj
719838fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE);
719938fd1498Szrj if (c)
720038fd1498Szrj {
720138fd1498Szrj /* Even if we pass it to all library function calls, it is currently only
720238fd1498Szrj defined/used for the OpenMP target ones. */
720338fd1498Szrj gcc_checking_assert (start_ix == BUILT_IN_GOMP_TARGET
720438fd1498Szrj || start_ix == BUILT_IN_GOMP_TARGET_DATA
720538fd1498Szrj || start_ix == BUILT_IN_GOMP_TARGET_UPDATE
720638fd1498Szrj || start_ix == BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA);
720738fd1498Szrj
720838fd1498Szrj device = OMP_CLAUSE_DEVICE_ID (c);
720938fd1498Szrj clause_loc = OMP_CLAUSE_LOCATION (c);
721038fd1498Szrj }
721138fd1498Szrj else
721238fd1498Szrj clause_loc = gimple_location (entry_stmt);
721338fd1498Szrj
721438fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_NOWAIT);
721538fd1498Szrj if (c)
721638fd1498Szrj flags_i |= GOMP_TARGET_FLAG_NOWAIT;
721738fd1498Szrj
721838fd1498Szrj /* Ensure 'device' is of the correct type. */
721938fd1498Szrj device = fold_convert_loc (clause_loc, integer_type_node, device);
722038fd1498Szrj
722138fd1498Szrj /* If we found the clause 'if (cond)', build
722238fd1498Szrj (cond ? device : GOMP_DEVICE_HOST_FALLBACK). */
722338fd1498Szrj if (cond)
722438fd1498Szrj {
722538fd1498Szrj cond = gimple_boolify (cond);
722638fd1498Szrj
722738fd1498Szrj basic_block cond_bb, then_bb, else_bb;
722838fd1498Szrj edge e;
722938fd1498Szrj tree tmp_var;
723038fd1498Szrj
723138fd1498Szrj tmp_var = create_tmp_var (TREE_TYPE (device));
723238fd1498Szrj if (offloaded)
723338fd1498Szrj e = split_block_after_labels (new_bb);
723438fd1498Szrj else
723538fd1498Szrj {
723638fd1498Szrj gsi = gsi_last_nondebug_bb (new_bb);
723738fd1498Szrj gsi_prev (&gsi);
723838fd1498Szrj e = split_block (new_bb, gsi_stmt (gsi));
723938fd1498Szrj }
724038fd1498Szrj cond_bb = e->src;
724138fd1498Szrj new_bb = e->dest;
724238fd1498Szrj remove_edge (e);
724338fd1498Szrj
724438fd1498Szrj then_bb = create_empty_bb (cond_bb);
724538fd1498Szrj else_bb = create_empty_bb (then_bb);
724638fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
724738fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
724838fd1498Szrj
724938fd1498Szrj stmt = gimple_build_cond_empty (cond);
725038fd1498Szrj gsi = gsi_last_bb (cond_bb);
725138fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
725238fd1498Szrj
725338fd1498Szrj gsi = gsi_start_bb (then_bb);
725438fd1498Szrj stmt = gimple_build_assign (tmp_var, device);
725538fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
725638fd1498Szrj
725738fd1498Szrj gsi = gsi_start_bb (else_bb);
725838fd1498Szrj stmt = gimple_build_assign (tmp_var,
725938fd1498Szrj build_int_cst (integer_type_node,
726038fd1498Szrj GOMP_DEVICE_HOST_FALLBACK));
726138fd1498Szrj gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING);
726238fd1498Szrj
726338fd1498Szrj make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
726438fd1498Szrj make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
726538fd1498Szrj add_bb_to_loop (then_bb, cond_bb->loop_father);
726638fd1498Szrj add_bb_to_loop (else_bb, cond_bb->loop_father);
726738fd1498Szrj make_edge (then_bb, new_bb, EDGE_FALLTHRU);
726838fd1498Szrj make_edge (else_bb, new_bb, EDGE_FALLTHRU);
726938fd1498Szrj
727038fd1498Szrj device = tmp_var;
727138fd1498Szrj gsi = gsi_last_nondebug_bb (new_bb);
727238fd1498Szrj }
727338fd1498Szrj else
727438fd1498Szrj {
727538fd1498Szrj gsi = gsi_last_nondebug_bb (new_bb);
727638fd1498Szrj device = force_gimple_operand_gsi (&gsi, device, true, NULL_TREE,
727738fd1498Szrj true, GSI_SAME_STMT);
727838fd1498Szrj }
727938fd1498Szrj
728038fd1498Szrj t = gimple_omp_target_data_arg (entry_stmt);
728138fd1498Szrj if (t == NULL)
728238fd1498Szrj {
728338fd1498Szrj t1 = size_zero_node;
728438fd1498Szrj t2 = build_zero_cst (ptr_type_node);
728538fd1498Szrj t3 = t2;
728638fd1498Szrj t4 = t2;
728738fd1498Szrj }
728838fd1498Szrj else
728938fd1498Szrj {
729038fd1498Szrj t1 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (TREE_VEC_ELT (t, 1))));
729138fd1498Szrj t1 = size_binop (PLUS_EXPR, t1, size_int (1));
729238fd1498Szrj t2 = build_fold_addr_expr (TREE_VEC_ELT (t, 0));
729338fd1498Szrj t3 = build_fold_addr_expr (TREE_VEC_ELT (t, 1));
729438fd1498Szrj t4 = build_fold_addr_expr (TREE_VEC_ELT (t, 2));
729538fd1498Szrj }
729638fd1498Szrj
729738fd1498Szrj gimple *g;
729838fd1498Szrj bool tagging = false;
729938fd1498Szrj /* The maximum number used by any start_ix, without varargs. */
730038fd1498Szrj auto_vec<tree, 11> args;
730138fd1498Szrj args.quick_push (device);
730238fd1498Szrj if (offloaded)
730338fd1498Szrj args.quick_push (build_fold_addr_expr (child_fn));
730438fd1498Szrj args.quick_push (t1);
730538fd1498Szrj args.quick_push (t2);
730638fd1498Szrj args.quick_push (t3);
730738fd1498Szrj args.quick_push (t4);
730838fd1498Szrj switch (start_ix)
730938fd1498Szrj {
731038fd1498Szrj case BUILT_IN_GOACC_DATA_START:
731138fd1498Szrj case BUILT_IN_GOACC_DECLARE:
731238fd1498Szrj case BUILT_IN_GOMP_TARGET_DATA:
731338fd1498Szrj break;
731438fd1498Szrj case BUILT_IN_GOMP_TARGET:
731538fd1498Szrj case BUILT_IN_GOMP_TARGET_UPDATE:
731638fd1498Szrj case BUILT_IN_GOMP_TARGET_ENTER_EXIT_DATA:
731738fd1498Szrj args.quick_push (build_int_cst (unsigned_type_node, flags_i));
731838fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_DEPEND);
731938fd1498Szrj if (c)
732038fd1498Szrj depend = OMP_CLAUSE_DECL (c);
732138fd1498Szrj else
732238fd1498Szrj depend = build_int_cst (ptr_type_node, 0);
732338fd1498Szrj args.quick_push (depend);
732438fd1498Szrj if (start_ix == BUILT_IN_GOMP_TARGET)
732538fd1498Szrj args.quick_push (get_target_arguments (&gsi, entry_stmt));
732638fd1498Szrj break;
732738fd1498Szrj case BUILT_IN_GOACC_PARALLEL:
732838fd1498Szrj oacc_set_fn_attrib (child_fn, clauses, &args);
732938fd1498Szrj tagging = true;
733038fd1498Szrj /* FALLTHRU */
733138fd1498Szrj case BUILT_IN_GOACC_ENTER_EXIT_DATA:
733238fd1498Szrj case BUILT_IN_GOACC_UPDATE:
733338fd1498Szrj {
733438fd1498Szrj tree t_async = NULL_TREE;
733538fd1498Szrj
733638fd1498Szrj /* If present, use the value specified by the respective
733738fd1498Szrj clause, making sure that is of the correct type. */
733838fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_ASYNC);
733938fd1498Szrj if (c)
734038fd1498Szrj t_async = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
734138fd1498Szrj integer_type_node,
734238fd1498Szrj OMP_CLAUSE_ASYNC_EXPR (c));
734338fd1498Szrj else if (!tagging)
734438fd1498Szrj /* Default values for t_async. */
734538fd1498Szrj t_async = fold_convert_loc (gimple_location (entry_stmt),
734638fd1498Szrj integer_type_node,
734738fd1498Szrj build_int_cst (integer_type_node,
734838fd1498Szrj GOMP_ASYNC_SYNC));
734938fd1498Szrj if (tagging && t_async)
735038fd1498Szrj {
735138fd1498Szrj unsigned HOST_WIDE_INT i_async = GOMP_LAUNCH_OP_MAX;
735238fd1498Szrj
735338fd1498Szrj if (TREE_CODE (t_async) == INTEGER_CST)
735438fd1498Szrj {
735538fd1498Szrj /* See if we can pack the async arg in to the tag's
735638fd1498Szrj operand. */
735738fd1498Szrj i_async = TREE_INT_CST_LOW (t_async);
735838fd1498Szrj if (i_async < GOMP_LAUNCH_OP_MAX)
735938fd1498Szrj t_async = NULL_TREE;
736038fd1498Szrj else
736138fd1498Szrj i_async = GOMP_LAUNCH_OP_MAX;
736238fd1498Szrj }
736338fd1498Szrj args.safe_push (oacc_launch_pack (GOMP_LAUNCH_ASYNC, NULL_TREE,
736438fd1498Szrj i_async));
736538fd1498Szrj }
736638fd1498Szrj if (t_async)
736738fd1498Szrj args.safe_push (t_async);
736838fd1498Szrj
736938fd1498Szrj /* Save the argument index, and ... */
737038fd1498Szrj unsigned t_wait_idx = args.length ();
737138fd1498Szrj unsigned num_waits = 0;
737238fd1498Szrj c = omp_find_clause (clauses, OMP_CLAUSE_WAIT);
737338fd1498Szrj if (!tagging || c)
737438fd1498Szrj /* ... push a placeholder. */
737538fd1498Szrj args.safe_push (integer_zero_node);
737638fd1498Szrj
737738fd1498Szrj for (; c; c = OMP_CLAUSE_CHAIN (c))
737838fd1498Szrj if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_WAIT)
737938fd1498Szrj {
738038fd1498Szrj args.safe_push (fold_convert_loc (OMP_CLAUSE_LOCATION (c),
738138fd1498Szrj integer_type_node,
738238fd1498Szrj OMP_CLAUSE_WAIT_EXPR (c)));
738338fd1498Szrj num_waits++;
738438fd1498Szrj }
738538fd1498Szrj
738638fd1498Szrj if (!tagging || num_waits)
738738fd1498Szrj {
738838fd1498Szrj tree len;
738938fd1498Szrj
739038fd1498Szrj /* Now that we know the number, update the placeholder. */
739138fd1498Szrj if (tagging)
739238fd1498Szrj len = oacc_launch_pack (GOMP_LAUNCH_WAIT, NULL_TREE, num_waits);
739338fd1498Szrj else
739438fd1498Szrj len = build_int_cst (integer_type_node, num_waits);
739538fd1498Szrj len = fold_convert_loc (gimple_location (entry_stmt),
739638fd1498Szrj unsigned_type_node, len);
739738fd1498Szrj args[t_wait_idx] = len;
739838fd1498Szrj }
739938fd1498Szrj }
740038fd1498Szrj break;
740138fd1498Szrj default:
740238fd1498Szrj gcc_unreachable ();
740338fd1498Szrj }
740438fd1498Szrj if (tagging)
740538fd1498Szrj /* Push terminal marker - zero. */
740638fd1498Szrj args.safe_push (oacc_launch_pack (0, NULL_TREE, 0));
740738fd1498Szrj
740838fd1498Szrj g = gimple_build_call_vec (builtin_decl_explicit (start_ix), args);
740938fd1498Szrj gimple_set_location (g, gimple_location (entry_stmt));
741038fd1498Szrj gsi_insert_before (&gsi, g, GSI_SAME_STMT);
741138fd1498Szrj if (!offloaded)
741238fd1498Szrj {
741338fd1498Szrj g = gsi_stmt (gsi);
741438fd1498Szrj gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET);
741538fd1498Szrj gsi_remove (&gsi, true);
741638fd1498Szrj }
741738fd1498Szrj if (data_region && region->exit)
741838fd1498Szrj {
741938fd1498Szrj gsi = gsi_last_nondebug_bb (region->exit);
742038fd1498Szrj g = gsi_stmt (gsi);
742138fd1498Szrj gcc_assert (g && gimple_code (g) == GIMPLE_OMP_RETURN);
742238fd1498Szrj gsi_remove (&gsi, true);
742338fd1498Szrj }
742438fd1498Szrj }
742538fd1498Szrj
742638fd1498Szrj /* Expand KFOR loop as a HSA grifidied kernel, i.e. as a body only with
742738fd1498Szrj iteration variable derived from the thread number. INTRA_GROUP means this
742838fd1498Szrj is an expansion of a loop iterating over work-items within a separate
742938fd1498Szrj iteration over groups. */
743038fd1498Szrj
743138fd1498Szrj static void
grid_expand_omp_for_loop(struct omp_region * kfor,bool intra_group)743238fd1498Szrj grid_expand_omp_for_loop (struct omp_region *kfor, bool intra_group)
743338fd1498Szrj {
743438fd1498Szrj gimple_stmt_iterator gsi;
743538fd1498Szrj gomp_for *for_stmt = as_a <gomp_for *> (last_stmt (kfor->entry));
743638fd1498Szrj gcc_checking_assert (gimple_omp_for_kind (for_stmt)
743738fd1498Szrj == GF_OMP_FOR_KIND_GRID_LOOP);
743838fd1498Szrj size_t collapse = gimple_omp_for_collapse (for_stmt);
743938fd1498Szrj struct omp_for_data_loop *loops
744038fd1498Szrj = XALLOCAVEC (struct omp_for_data_loop,
744138fd1498Szrj gimple_omp_for_collapse (for_stmt));
744238fd1498Szrj struct omp_for_data fd;
744338fd1498Szrj
744438fd1498Szrj remove_edge (BRANCH_EDGE (kfor->entry));
744538fd1498Szrj basic_block body_bb = FALLTHRU_EDGE (kfor->entry)->dest;
744638fd1498Szrj
744738fd1498Szrj gcc_assert (kfor->cont);
744838fd1498Szrj omp_extract_for_data (for_stmt, &fd, loops);
744938fd1498Szrj
745038fd1498Szrj gsi = gsi_start_bb (body_bb);
745138fd1498Szrj
745238fd1498Szrj for (size_t dim = 0; dim < collapse; dim++)
745338fd1498Szrj {
745438fd1498Szrj tree type, itype;
745538fd1498Szrj itype = type = TREE_TYPE (fd.loops[dim].v);
745638fd1498Szrj if (POINTER_TYPE_P (type))
745738fd1498Szrj itype = signed_type_for (type);
745838fd1498Szrj
745938fd1498Szrj tree n1 = fd.loops[dim].n1;
746038fd1498Szrj tree step = fd.loops[dim].step;
746138fd1498Szrj n1 = force_gimple_operand_gsi (&gsi, fold_convert (type, n1),
746238fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
746338fd1498Szrj step = force_gimple_operand_gsi (&gsi, fold_convert (itype, step),
746438fd1498Szrj true, NULL_TREE, true, GSI_SAME_STMT);
746538fd1498Szrj tree threadid;
746638fd1498Szrj if (gimple_omp_for_grid_group_iter (for_stmt))
746738fd1498Szrj {
746838fd1498Szrj gcc_checking_assert (!intra_group);
746938fd1498Szrj threadid = build_call_expr (builtin_decl_explicit
747038fd1498Szrj (BUILT_IN_HSA_WORKGROUPID), 1,
747138fd1498Szrj build_int_cstu (unsigned_type_node, dim));
747238fd1498Szrj }
747338fd1498Szrj else if (intra_group)
747438fd1498Szrj threadid = build_call_expr (builtin_decl_explicit
747538fd1498Szrj (BUILT_IN_HSA_WORKITEMID), 1,
747638fd1498Szrj build_int_cstu (unsigned_type_node, dim));
747738fd1498Szrj else
747838fd1498Szrj threadid = build_call_expr (builtin_decl_explicit
747938fd1498Szrj (BUILT_IN_HSA_WORKITEMABSID), 1,
748038fd1498Szrj build_int_cstu (unsigned_type_node, dim));
748138fd1498Szrj threadid = fold_convert (itype, threadid);
748238fd1498Szrj threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE,
748338fd1498Szrj true, GSI_SAME_STMT);
748438fd1498Szrj
748538fd1498Szrj tree startvar = fd.loops[dim].v;
748638fd1498Szrj tree t = fold_build2 (MULT_EXPR, itype, threadid, step);
748738fd1498Szrj if (POINTER_TYPE_P (type))
748838fd1498Szrj t = fold_build_pointer_plus (n1, t);
748938fd1498Szrj else
749038fd1498Szrj t = fold_build2 (PLUS_EXPR, type, t, n1);
749138fd1498Szrj t = fold_convert (type, t);
749238fd1498Szrj t = force_gimple_operand_gsi (&gsi, t,
749338fd1498Szrj DECL_P (startvar)
749438fd1498Szrj && TREE_ADDRESSABLE (startvar),
749538fd1498Szrj NULL_TREE, true, GSI_SAME_STMT);
749638fd1498Szrj gassign *assign_stmt = gimple_build_assign (startvar, t);
749738fd1498Szrj gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
749838fd1498Szrj }
749938fd1498Szrj /* Remove the omp for statement. */
750038fd1498Szrj gsi = gsi_last_nondebug_bb (kfor->entry);
750138fd1498Szrj gsi_remove (&gsi, true);
750238fd1498Szrj
750338fd1498Szrj /* Remove the GIMPLE_OMP_CONTINUE statement. */
750438fd1498Szrj gsi = gsi_last_nondebug_bb (kfor->cont);
750538fd1498Szrj gcc_assert (!gsi_end_p (gsi)
750638fd1498Szrj && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_CONTINUE);
750738fd1498Szrj gsi_remove (&gsi, true);
750838fd1498Szrj
750938fd1498Szrj /* Replace the GIMPLE_OMP_RETURN with a barrier, if necessary. */
751038fd1498Szrj gsi = gsi_last_nondebug_bb (kfor->exit);
751138fd1498Szrj gcc_assert (!gsi_end_p (gsi)
751238fd1498Szrj && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
751338fd1498Szrj if (intra_group)
751438fd1498Szrj gsi_insert_before (&gsi, omp_build_barrier (NULL_TREE), GSI_SAME_STMT);
751538fd1498Szrj gsi_remove (&gsi, true);
751638fd1498Szrj
751738fd1498Szrj /* Fixup the much simpler CFG. */
751838fd1498Szrj remove_edge (find_edge (kfor->cont, body_bb));
751938fd1498Szrj
752038fd1498Szrj if (kfor->cont != body_bb)
752138fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, kfor->cont, body_bb);
752238fd1498Szrj set_immediate_dominator (CDI_DOMINATORS, kfor->exit, kfor->cont);
752338fd1498Szrj }
752438fd1498Szrj
752538fd1498Szrj /* Structure passed to grid_remap_kernel_arg_accesses so that it can remap
752638fd1498Szrj argument_decls. */
752738fd1498Szrj
752838fd1498Szrj struct grid_arg_decl_map
752938fd1498Szrj {
753038fd1498Szrj tree old_arg;
753138fd1498Szrj tree new_arg;
753238fd1498Szrj };
753338fd1498Szrj
753438fd1498Szrj /* Invoked through walk_gimple_op, will remap all PARM_DECLs to the ones
753538fd1498Szrj pertaining to kernel function. */
753638fd1498Szrj
753738fd1498Szrj static tree
grid_remap_kernel_arg_accesses(tree * tp,int * walk_subtrees,void * data)753838fd1498Szrj grid_remap_kernel_arg_accesses (tree *tp, int *walk_subtrees, void *data)
753938fd1498Szrj {
754038fd1498Szrj struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
754138fd1498Szrj struct grid_arg_decl_map *adm = (struct grid_arg_decl_map *) wi->info;
754238fd1498Szrj tree t = *tp;
754338fd1498Szrj
754438fd1498Szrj if (t == adm->old_arg)
754538fd1498Szrj *tp = adm->new_arg;
754638fd1498Szrj *walk_subtrees = !TYPE_P (t) && !DECL_P (t);
754738fd1498Szrj return NULL_TREE;
754838fd1498Szrj }
754938fd1498Szrj
755038fd1498Szrj /* If TARGET region contains a kernel body for loop, remove its region from the
755138fd1498Szrj TARGET and expand it in HSA gridified kernel fashion. */
755238fd1498Szrj
755338fd1498Szrj static void
grid_expand_target_grid_body(struct omp_region * target)755438fd1498Szrj grid_expand_target_grid_body (struct omp_region *target)
755538fd1498Szrj {
755638fd1498Szrj if (!hsa_gen_requested_p ())
755738fd1498Szrj return;
755838fd1498Szrj
755938fd1498Szrj gomp_target *tgt_stmt = as_a <gomp_target *> (last_stmt (target->entry));
756038fd1498Szrj struct omp_region **pp;
756138fd1498Szrj
756238fd1498Szrj for (pp = &target->inner; *pp; pp = &(*pp)->next)
756338fd1498Szrj if ((*pp)->type == GIMPLE_OMP_GRID_BODY)
756438fd1498Szrj break;
756538fd1498Szrj
756638fd1498Szrj struct omp_region *gpukernel = *pp;
756738fd1498Szrj
756838fd1498Szrj tree orig_child_fndecl = gimple_omp_target_child_fn (tgt_stmt);
756938fd1498Szrj if (!gpukernel)
757038fd1498Szrj {
757138fd1498Szrj /* HSA cannot handle OACC stuff. */
757238fd1498Szrj if (gimple_omp_target_kind (tgt_stmt) != GF_OMP_TARGET_KIND_REGION)
757338fd1498Szrj return;
757438fd1498Szrj gcc_checking_assert (orig_child_fndecl);
757538fd1498Szrj gcc_assert (!omp_find_clause (gimple_omp_target_clauses (tgt_stmt),
757638fd1498Szrj OMP_CLAUSE__GRIDDIM_));
757738fd1498Szrj cgraph_node *n = cgraph_node::get (orig_child_fndecl);
757838fd1498Szrj
757938fd1498Szrj hsa_register_kernel (n);
758038fd1498Szrj return;
758138fd1498Szrj }
758238fd1498Szrj
758338fd1498Szrj gcc_assert (omp_find_clause (gimple_omp_target_clauses (tgt_stmt),
758438fd1498Szrj OMP_CLAUSE__GRIDDIM_));
758538fd1498Szrj tree inside_block
758638fd1498Szrj = gimple_block (first_stmt (single_succ (gpukernel->entry)));
758738fd1498Szrj *pp = gpukernel->next;
758838fd1498Szrj for (pp = &gpukernel->inner; *pp; pp = &(*pp)->next)
758938fd1498Szrj if ((*pp)->type == GIMPLE_OMP_FOR)
759038fd1498Szrj break;
759138fd1498Szrj
759238fd1498Szrj struct omp_region *kfor = *pp;
759338fd1498Szrj gcc_assert (kfor);
759438fd1498Szrj gomp_for *for_stmt = as_a <gomp_for *> (last_stmt (kfor->entry));
759538fd1498Szrj gcc_assert (gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_GRID_LOOP);
759638fd1498Szrj *pp = kfor->next;
759738fd1498Szrj if (kfor->inner)
759838fd1498Szrj {
759938fd1498Szrj if (gimple_omp_for_grid_group_iter (for_stmt))
760038fd1498Szrj {
760138fd1498Szrj struct omp_region **next_pp;
760238fd1498Szrj for (pp = &kfor->inner; *pp; pp = next_pp)
760338fd1498Szrj {
760438fd1498Szrj next_pp = &(*pp)->next;
760538fd1498Szrj if ((*pp)->type != GIMPLE_OMP_FOR)
760638fd1498Szrj continue;
760738fd1498Szrj gomp_for *inner = as_a <gomp_for *> (last_stmt ((*pp)->entry));
760838fd1498Szrj gcc_assert (gimple_omp_for_kind (inner)
760938fd1498Szrj == GF_OMP_FOR_KIND_GRID_LOOP);
761038fd1498Szrj grid_expand_omp_for_loop (*pp, true);
761138fd1498Szrj *pp = (*pp)->next;
761238fd1498Szrj next_pp = pp;
761338fd1498Szrj }
761438fd1498Szrj }
761538fd1498Szrj expand_omp (kfor->inner);
761638fd1498Szrj }
761738fd1498Szrj if (gpukernel->inner)
761838fd1498Szrj expand_omp (gpukernel->inner);
761938fd1498Szrj
762038fd1498Szrj tree kern_fndecl = copy_node (orig_child_fndecl);
762138fd1498Szrj DECL_NAME (kern_fndecl) = clone_function_name (kern_fndecl, "kernel");
762238fd1498Szrj SET_DECL_ASSEMBLER_NAME (kern_fndecl, DECL_NAME (kern_fndecl));
762338fd1498Szrj tree tgtblock = gimple_block (tgt_stmt);
762438fd1498Szrj tree fniniblock = make_node (BLOCK);
762538fd1498Szrj BLOCK_ABSTRACT_ORIGIN (fniniblock) = tgtblock;
762638fd1498Szrj BLOCK_SOURCE_LOCATION (fniniblock) = BLOCK_SOURCE_LOCATION (tgtblock);
762738fd1498Szrj BLOCK_SOURCE_END_LOCATION (fniniblock) = BLOCK_SOURCE_END_LOCATION (tgtblock);
762838fd1498Szrj BLOCK_SUPERCONTEXT (fniniblock) = kern_fndecl;
762938fd1498Szrj DECL_INITIAL (kern_fndecl) = fniniblock;
763038fd1498Szrj push_struct_function (kern_fndecl);
763138fd1498Szrj cfun->function_end_locus = gimple_location (tgt_stmt);
763238fd1498Szrj init_tree_ssa (cfun);
763338fd1498Szrj pop_cfun ();
763438fd1498Szrj
763538fd1498Szrj tree old_parm_decl = DECL_ARGUMENTS (kern_fndecl);
763638fd1498Szrj gcc_assert (!DECL_CHAIN (old_parm_decl));
763738fd1498Szrj tree new_parm_decl = copy_node (DECL_ARGUMENTS (kern_fndecl));
763838fd1498Szrj DECL_CONTEXT (new_parm_decl) = kern_fndecl;
763938fd1498Szrj DECL_ARGUMENTS (kern_fndecl) = new_parm_decl;
764038fd1498Szrj gcc_assert (VOID_TYPE_P (TREE_TYPE (DECL_RESULT (kern_fndecl))));
764138fd1498Szrj DECL_RESULT (kern_fndecl) = copy_node (DECL_RESULT (kern_fndecl));
764238fd1498Szrj DECL_CONTEXT (DECL_RESULT (kern_fndecl)) = kern_fndecl;
764338fd1498Szrj struct function *kern_cfun = DECL_STRUCT_FUNCTION (kern_fndecl);
764438fd1498Szrj kern_cfun->curr_properties = cfun->curr_properties;
764538fd1498Szrj
764638fd1498Szrj grid_expand_omp_for_loop (kfor, false);
764738fd1498Szrj
764838fd1498Szrj /* Remove the omp for statement. */
764938fd1498Szrj gimple_stmt_iterator gsi = gsi_last_nondebug_bb (gpukernel->entry);
765038fd1498Szrj gsi_remove (&gsi, true);
765138fd1498Szrj /* Replace the GIMPLE_OMP_RETURN at the end of the kernel region with a real
765238fd1498Szrj return. */
765338fd1498Szrj gsi = gsi_last_nondebug_bb (gpukernel->exit);
765438fd1498Szrj gcc_assert (!gsi_end_p (gsi)
765538fd1498Szrj && gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_RETURN);
765638fd1498Szrj gimple *ret_stmt = gimple_build_return (NULL);
765738fd1498Szrj gsi_insert_after (&gsi, ret_stmt, GSI_SAME_STMT);
765838fd1498Szrj gsi_remove (&gsi, true);
765938fd1498Szrj
766038fd1498Szrj /* Statements in the first BB in the target construct have been produced by
766138fd1498Szrj target lowering and must be copied inside the GPUKERNEL, with the two
766238fd1498Szrj exceptions of the first OMP statement and the OMP_DATA assignment
766338fd1498Szrj statement. */
766438fd1498Szrj gsi = gsi_start_bb (single_succ (gpukernel->entry));
766538fd1498Szrj tree data_arg = gimple_omp_target_data_arg (tgt_stmt);
766638fd1498Szrj tree sender = data_arg ? TREE_VEC_ELT (data_arg, 0) : NULL;
766738fd1498Szrj for (gimple_stmt_iterator tsi = gsi_start_bb (single_succ (target->entry));
766838fd1498Szrj !gsi_end_p (tsi); gsi_next (&tsi))
766938fd1498Szrj {
767038fd1498Szrj gimple *stmt = gsi_stmt (tsi);
767138fd1498Szrj if (is_gimple_omp (stmt))
767238fd1498Szrj break;
767338fd1498Szrj if (sender
767438fd1498Szrj && is_gimple_assign (stmt)
767538fd1498Szrj && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR
767638fd1498Szrj && TREE_OPERAND (gimple_assign_rhs1 (stmt), 0) == sender)
767738fd1498Szrj continue;
767838fd1498Szrj gimple *copy = gimple_copy (stmt);
767938fd1498Szrj gsi_insert_before (&gsi, copy, GSI_SAME_STMT);
768038fd1498Szrj gimple_set_block (copy, fniniblock);
768138fd1498Szrj }
768238fd1498Szrj
768338fd1498Szrj move_sese_region_to_fn (kern_cfun, single_succ (gpukernel->entry),
768438fd1498Szrj gpukernel->exit, inside_block);
768538fd1498Szrj
768638fd1498Szrj cgraph_node *kcn = cgraph_node::get_create (kern_fndecl);
768738fd1498Szrj kcn->mark_force_output ();
768838fd1498Szrj cgraph_node *orig_child = cgraph_node::get (orig_child_fndecl);
768938fd1498Szrj
769038fd1498Szrj hsa_register_kernel (kcn, orig_child);
769138fd1498Szrj
769238fd1498Szrj cgraph_node::add_new_function (kern_fndecl, true);
769338fd1498Szrj push_cfun (kern_cfun);
769438fd1498Szrj cgraph_edge::rebuild_edges ();
769538fd1498Szrj
769638fd1498Szrj /* Re-map any mention of the PARM_DECL of the original function to the
769738fd1498Szrj PARM_DECL of the new one.
769838fd1498Szrj
769938fd1498Szrj TODO: It would be great if lowering produced references into the GPU
770038fd1498Szrj kernel decl straight away and we did not have to do this. */
770138fd1498Szrj struct grid_arg_decl_map adm;
770238fd1498Szrj adm.old_arg = old_parm_decl;
770338fd1498Szrj adm.new_arg = new_parm_decl;
770438fd1498Szrj basic_block bb;
770538fd1498Szrj FOR_EACH_BB_FN (bb, kern_cfun)
770638fd1498Szrj {
770738fd1498Szrj for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
770838fd1498Szrj {
770938fd1498Szrj gimple *stmt = gsi_stmt (gsi);
771038fd1498Szrj struct walk_stmt_info wi;
771138fd1498Szrj memset (&wi, 0, sizeof (wi));
771238fd1498Szrj wi.info = &adm;
771338fd1498Szrj walk_gimple_op (stmt, grid_remap_kernel_arg_accesses, &wi);
771438fd1498Szrj }
771538fd1498Szrj }
771638fd1498Szrj pop_cfun ();
771738fd1498Szrj
771838fd1498Szrj return;
771938fd1498Szrj }
772038fd1498Szrj
772138fd1498Szrj /* Expand the parallel region tree rooted at REGION. Expansion
772238fd1498Szrj proceeds in depth-first order. Innermost regions are expanded
772338fd1498Szrj first. This way, parallel regions that require a new function to
772438fd1498Szrj be created (e.g., GIMPLE_OMP_PARALLEL) can be expanded without having any
772538fd1498Szrj internal dependencies in their body. */
772638fd1498Szrj
772738fd1498Szrj static void
expand_omp(struct omp_region * region)772838fd1498Szrj expand_omp (struct omp_region *region)
772938fd1498Szrj {
773038fd1498Szrj omp_any_child_fn_dumped = false;
773138fd1498Szrj while (region)
773238fd1498Szrj {
773338fd1498Szrj location_t saved_location;
773438fd1498Szrj gimple *inner_stmt = NULL;
773538fd1498Szrj
773638fd1498Szrj /* First, determine whether this is a combined parallel+workshare
773738fd1498Szrj region. */
773838fd1498Szrj if (region->type == GIMPLE_OMP_PARALLEL)
773938fd1498Szrj determine_parallel_type (region);
774038fd1498Szrj else if (region->type == GIMPLE_OMP_TARGET)
774138fd1498Szrj grid_expand_target_grid_body (region);
774238fd1498Szrj
774338fd1498Szrj if (region->type == GIMPLE_OMP_FOR
774438fd1498Szrj && gimple_omp_for_combined_p (last_stmt (region->entry)))
774538fd1498Szrj inner_stmt = last_stmt (region->inner->entry);
774638fd1498Szrj
774738fd1498Szrj if (region->inner)
774838fd1498Szrj expand_omp (region->inner);
774938fd1498Szrj
775038fd1498Szrj saved_location = input_location;
775138fd1498Szrj if (gimple_has_location (last_stmt (region->entry)))
775238fd1498Szrj input_location = gimple_location (last_stmt (region->entry));
775338fd1498Szrj
775438fd1498Szrj switch (region->type)
775538fd1498Szrj {
775638fd1498Szrj case GIMPLE_OMP_PARALLEL:
775738fd1498Szrj case GIMPLE_OMP_TASK:
775838fd1498Szrj expand_omp_taskreg (region);
775938fd1498Szrj break;
776038fd1498Szrj
776138fd1498Szrj case GIMPLE_OMP_FOR:
776238fd1498Szrj expand_omp_for (region, inner_stmt);
776338fd1498Szrj break;
776438fd1498Szrj
776538fd1498Szrj case GIMPLE_OMP_SECTIONS:
776638fd1498Szrj expand_omp_sections (region);
776738fd1498Szrj break;
776838fd1498Szrj
776938fd1498Szrj case GIMPLE_OMP_SECTION:
777038fd1498Szrj /* Individual omp sections are handled together with their
777138fd1498Szrj parent GIMPLE_OMP_SECTIONS region. */
777238fd1498Szrj break;
777338fd1498Szrj
777438fd1498Szrj case GIMPLE_OMP_SINGLE:
777538fd1498Szrj expand_omp_single (region);
777638fd1498Szrj break;
777738fd1498Szrj
777838fd1498Szrj case GIMPLE_OMP_ORDERED:
777938fd1498Szrj {
778038fd1498Szrj gomp_ordered *ord_stmt
778138fd1498Szrj = as_a <gomp_ordered *> (last_stmt (region->entry));
778238fd1498Szrj if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
778338fd1498Szrj OMP_CLAUSE_DEPEND))
778438fd1498Szrj {
778538fd1498Szrj /* We'll expand these when expanding corresponding
778638fd1498Szrj worksharing region with ordered(n) clause. */
778738fd1498Szrj gcc_assert (region->outer
778838fd1498Szrj && region->outer->type == GIMPLE_OMP_FOR);
778938fd1498Szrj region->ord_stmt = ord_stmt;
779038fd1498Szrj break;
779138fd1498Szrj }
779238fd1498Szrj }
779338fd1498Szrj /* FALLTHRU */
779438fd1498Szrj case GIMPLE_OMP_MASTER:
779538fd1498Szrj case GIMPLE_OMP_TASKGROUP:
779638fd1498Szrj case GIMPLE_OMP_CRITICAL:
779738fd1498Szrj case GIMPLE_OMP_TEAMS:
779838fd1498Szrj expand_omp_synch (region);
779938fd1498Szrj break;
780038fd1498Szrj
780138fd1498Szrj case GIMPLE_OMP_ATOMIC_LOAD:
780238fd1498Szrj expand_omp_atomic (region);
780338fd1498Szrj break;
780438fd1498Szrj
780538fd1498Szrj case GIMPLE_OMP_TARGET:
780638fd1498Szrj expand_omp_target (region);
780738fd1498Szrj break;
780838fd1498Szrj
780938fd1498Szrj default:
781038fd1498Szrj gcc_unreachable ();
781138fd1498Szrj }
781238fd1498Szrj
781338fd1498Szrj input_location = saved_location;
781438fd1498Szrj region = region->next;
781538fd1498Szrj }
781638fd1498Szrj if (omp_any_child_fn_dumped)
781738fd1498Szrj {
781838fd1498Szrj if (dump_file)
781938fd1498Szrj dump_function_header (dump_file, current_function_decl, dump_flags);
782038fd1498Szrj omp_any_child_fn_dumped = false;
782138fd1498Szrj }
782238fd1498Szrj }
782338fd1498Szrj
782438fd1498Szrj /* Helper for build_omp_regions. Scan the dominator tree starting at
782538fd1498Szrj block BB. PARENT is the region that contains BB. If SINGLE_TREE is
782638fd1498Szrj true, the function ends once a single tree is built (otherwise, whole
782738fd1498Szrj forest of OMP constructs may be built). */
782838fd1498Szrj
782938fd1498Szrj static void
build_omp_regions_1(basic_block bb,struct omp_region * parent,bool single_tree)783038fd1498Szrj build_omp_regions_1 (basic_block bb, struct omp_region *parent,
783138fd1498Szrj bool single_tree)
783238fd1498Szrj {
783338fd1498Szrj gimple_stmt_iterator gsi;
783438fd1498Szrj gimple *stmt;
783538fd1498Szrj basic_block son;
783638fd1498Szrj
783738fd1498Szrj gsi = gsi_last_nondebug_bb (bb);
783838fd1498Szrj if (!gsi_end_p (gsi) && is_gimple_omp (gsi_stmt (gsi)))
783938fd1498Szrj {
784038fd1498Szrj struct omp_region *region;
784138fd1498Szrj enum gimple_code code;
784238fd1498Szrj
784338fd1498Szrj stmt = gsi_stmt (gsi);
784438fd1498Szrj code = gimple_code (stmt);
784538fd1498Szrj if (code == GIMPLE_OMP_RETURN)
784638fd1498Szrj {
784738fd1498Szrj /* STMT is the return point out of region PARENT. Mark it
784838fd1498Szrj as the exit point and make PARENT the immediately
784938fd1498Szrj enclosing region. */
785038fd1498Szrj gcc_assert (parent);
785138fd1498Szrj region = parent;
785238fd1498Szrj region->exit = bb;
785338fd1498Szrj parent = parent->outer;
785438fd1498Szrj }
785538fd1498Szrj else if (code == GIMPLE_OMP_ATOMIC_STORE)
785638fd1498Szrj {
785738fd1498Szrj /* GIMPLE_OMP_ATOMIC_STORE is analogous to
785838fd1498Szrj GIMPLE_OMP_RETURN, but matches with
785938fd1498Szrj GIMPLE_OMP_ATOMIC_LOAD. */
786038fd1498Szrj gcc_assert (parent);
786138fd1498Szrj gcc_assert (parent->type == GIMPLE_OMP_ATOMIC_LOAD);
786238fd1498Szrj region = parent;
786338fd1498Szrj region->exit = bb;
786438fd1498Szrj parent = parent->outer;
786538fd1498Szrj }
786638fd1498Szrj else if (code == GIMPLE_OMP_CONTINUE)
786738fd1498Szrj {
786838fd1498Szrj gcc_assert (parent);
786938fd1498Szrj parent->cont = bb;
787038fd1498Szrj }
787138fd1498Szrj else if (code == GIMPLE_OMP_SECTIONS_SWITCH)
787238fd1498Szrj {
787338fd1498Szrj /* GIMPLE_OMP_SECTIONS_SWITCH is part of
787438fd1498Szrj GIMPLE_OMP_SECTIONS, and we do nothing for it. */
787538fd1498Szrj }
787638fd1498Szrj else
787738fd1498Szrj {
787838fd1498Szrj region = new_omp_region (bb, code, parent);
787938fd1498Szrj /* Otherwise... */
788038fd1498Szrj if (code == GIMPLE_OMP_TARGET)
788138fd1498Szrj {
788238fd1498Szrj switch (gimple_omp_target_kind (stmt))
788338fd1498Szrj {
788438fd1498Szrj case GF_OMP_TARGET_KIND_REGION:
788538fd1498Szrj case GF_OMP_TARGET_KIND_DATA:
788638fd1498Szrj case GF_OMP_TARGET_KIND_OACC_PARALLEL:
788738fd1498Szrj case GF_OMP_TARGET_KIND_OACC_KERNELS:
788838fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DATA:
788938fd1498Szrj case GF_OMP_TARGET_KIND_OACC_HOST_DATA:
789038fd1498Szrj break;
789138fd1498Szrj case GF_OMP_TARGET_KIND_UPDATE:
789238fd1498Szrj case GF_OMP_TARGET_KIND_ENTER_DATA:
789338fd1498Szrj case GF_OMP_TARGET_KIND_EXIT_DATA:
789438fd1498Szrj case GF_OMP_TARGET_KIND_OACC_UPDATE:
789538fd1498Szrj case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
789638fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DECLARE:
789738fd1498Szrj /* ..., other than for those stand-alone directives... */
789838fd1498Szrj region = NULL;
789938fd1498Szrj break;
790038fd1498Szrj default:
790138fd1498Szrj gcc_unreachable ();
790238fd1498Szrj }
790338fd1498Szrj }
790438fd1498Szrj else if (code == GIMPLE_OMP_ORDERED
790538fd1498Szrj && omp_find_clause (gimple_omp_ordered_clauses
790638fd1498Szrj (as_a <gomp_ordered *> (stmt)),
790738fd1498Szrj OMP_CLAUSE_DEPEND))
790838fd1498Szrj /* #pragma omp ordered depend is also just a stand-alone
790938fd1498Szrj directive. */
791038fd1498Szrj region = NULL;
791138fd1498Szrj /* ..., this directive becomes the parent for a new region. */
791238fd1498Szrj if (region)
791338fd1498Szrj parent = region;
791438fd1498Szrj }
791538fd1498Szrj }
791638fd1498Szrj
791738fd1498Szrj if (single_tree && !parent)
791838fd1498Szrj return;
791938fd1498Szrj
792038fd1498Szrj for (son = first_dom_son (CDI_DOMINATORS, bb);
792138fd1498Szrj son;
792238fd1498Szrj son = next_dom_son (CDI_DOMINATORS, son))
792338fd1498Szrj build_omp_regions_1 (son, parent, single_tree);
792438fd1498Szrj }
792538fd1498Szrj
792638fd1498Szrj /* Builds the tree of OMP regions rooted at ROOT, storing it to
792738fd1498Szrj root_omp_region. */
792838fd1498Szrj
792938fd1498Szrj static void
build_omp_regions_root(basic_block root)793038fd1498Szrj build_omp_regions_root (basic_block root)
793138fd1498Szrj {
793238fd1498Szrj gcc_assert (root_omp_region == NULL);
793338fd1498Szrj build_omp_regions_1 (root, NULL, true);
793438fd1498Szrj gcc_assert (root_omp_region != NULL);
793538fd1498Szrj }
793638fd1498Szrj
793738fd1498Szrj /* Expands omp construct (and its subconstructs) starting in HEAD. */
793838fd1498Szrj
793938fd1498Szrj void
omp_expand_local(basic_block head)794038fd1498Szrj omp_expand_local (basic_block head)
794138fd1498Szrj {
794238fd1498Szrj build_omp_regions_root (head);
794338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
794438fd1498Szrj {
794538fd1498Szrj fprintf (dump_file, "\nOMP region tree\n\n");
794638fd1498Szrj dump_omp_region (dump_file, root_omp_region, 0);
794738fd1498Szrj fprintf (dump_file, "\n");
794838fd1498Szrj }
794938fd1498Szrj
795038fd1498Szrj remove_exit_barriers (root_omp_region);
795138fd1498Szrj expand_omp (root_omp_region);
795238fd1498Szrj
795338fd1498Szrj omp_free_regions ();
795438fd1498Szrj }
795538fd1498Szrj
795638fd1498Szrj /* Scan the CFG and build a tree of OMP regions. Return the root of
795738fd1498Szrj the OMP region tree. */
795838fd1498Szrj
795938fd1498Szrj static void
build_omp_regions(void)796038fd1498Szrj build_omp_regions (void)
796138fd1498Szrj {
796238fd1498Szrj gcc_assert (root_omp_region == NULL);
796338fd1498Szrj calculate_dominance_info (CDI_DOMINATORS);
796438fd1498Szrj build_omp_regions_1 (ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, false);
796538fd1498Szrj }
796638fd1498Szrj
796738fd1498Szrj /* Main entry point for expanding OMP-GIMPLE into runtime calls. */
796838fd1498Szrj
796938fd1498Szrj static unsigned int
execute_expand_omp(void)797038fd1498Szrj execute_expand_omp (void)
797138fd1498Szrj {
797238fd1498Szrj build_omp_regions ();
797338fd1498Szrj
797438fd1498Szrj if (!root_omp_region)
797538fd1498Szrj return 0;
797638fd1498Szrj
797738fd1498Szrj if (dump_file)
797838fd1498Szrj {
797938fd1498Szrj fprintf (dump_file, "\nOMP region tree\n\n");
798038fd1498Szrj dump_omp_region (dump_file, root_omp_region, 0);
798138fd1498Szrj fprintf (dump_file, "\n");
798238fd1498Szrj }
798338fd1498Szrj
798438fd1498Szrj remove_exit_barriers (root_omp_region);
798538fd1498Szrj
798638fd1498Szrj expand_omp (root_omp_region);
798738fd1498Szrj
798838fd1498Szrj if (flag_checking && !loops_state_satisfies_p (LOOPS_NEED_FIXUP))
798938fd1498Szrj verify_loop_structure ();
799038fd1498Szrj cleanup_tree_cfg ();
799138fd1498Szrj
799238fd1498Szrj omp_free_regions ();
799338fd1498Szrj
799438fd1498Szrj return 0;
799538fd1498Szrj }
799638fd1498Szrj
799738fd1498Szrj /* OMP expansion -- the default pass, run before creation of SSA form. */
799838fd1498Szrj
799938fd1498Szrj namespace {
800038fd1498Szrj
800138fd1498Szrj const pass_data pass_data_expand_omp =
800238fd1498Szrj {
800338fd1498Szrj GIMPLE_PASS, /* type */
800438fd1498Szrj "ompexp", /* name */
800538fd1498Szrj OPTGROUP_OMP, /* optinfo_flags */
800638fd1498Szrj TV_NONE, /* tv_id */
800738fd1498Szrj PROP_gimple_any, /* properties_required */
800838fd1498Szrj PROP_gimple_eomp, /* properties_provided */
800938fd1498Szrj 0, /* properties_destroyed */
801038fd1498Szrj 0, /* todo_flags_start */
801138fd1498Szrj 0, /* todo_flags_finish */
801238fd1498Szrj };
801338fd1498Szrj
801438fd1498Szrj class pass_expand_omp : public gimple_opt_pass
801538fd1498Szrj {
801638fd1498Szrj public:
pass_expand_omp(gcc::context * ctxt)801738fd1498Szrj pass_expand_omp (gcc::context *ctxt)
801838fd1498Szrj : gimple_opt_pass (pass_data_expand_omp, ctxt)
801938fd1498Szrj {}
802038fd1498Szrj
802138fd1498Szrj /* opt_pass methods: */
execute(function *)802238fd1498Szrj virtual unsigned int execute (function *)
802338fd1498Szrj {
802438fd1498Szrj bool gate = ((flag_openacc != 0 || flag_openmp != 0
802538fd1498Szrj || flag_openmp_simd != 0)
802638fd1498Szrj && !seen_error ());
802738fd1498Szrj
802838fd1498Szrj /* This pass always runs, to provide PROP_gimple_eomp.
802938fd1498Szrj But often, there is nothing to do. */
803038fd1498Szrj if (!gate)
803138fd1498Szrj return 0;
803238fd1498Szrj
803338fd1498Szrj return execute_expand_omp ();
803438fd1498Szrj }
803538fd1498Szrj
803638fd1498Szrj }; // class pass_expand_omp
803738fd1498Szrj
803838fd1498Szrj } // anon namespace
803938fd1498Szrj
804038fd1498Szrj gimple_opt_pass *
make_pass_expand_omp(gcc::context * ctxt)804138fd1498Szrj make_pass_expand_omp (gcc::context *ctxt)
804238fd1498Szrj {
804338fd1498Szrj return new pass_expand_omp (ctxt);
804438fd1498Szrj }
804538fd1498Szrj
804638fd1498Szrj namespace {
804738fd1498Szrj
804838fd1498Szrj const pass_data pass_data_expand_omp_ssa =
804938fd1498Szrj {
805038fd1498Szrj GIMPLE_PASS, /* type */
805138fd1498Szrj "ompexpssa", /* name */
805238fd1498Szrj OPTGROUP_OMP, /* optinfo_flags */
805338fd1498Szrj TV_NONE, /* tv_id */
805438fd1498Szrj PROP_cfg | PROP_ssa, /* properties_required */
805538fd1498Szrj PROP_gimple_eomp, /* properties_provided */
805638fd1498Szrj 0, /* properties_destroyed */
805738fd1498Szrj 0, /* todo_flags_start */
805838fd1498Szrj TODO_cleanup_cfg | TODO_rebuild_alias, /* todo_flags_finish */
805938fd1498Szrj };
806038fd1498Szrj
806138fd1498Szrj class pass_expand_omp_ssa : public gimple_opt_pass
806238fd1498Szrj {
806338fd1498Szrj public:
pass_expand_omp_ssa(gcc::context * ctxt)806438fd1498Szrj pass_expand_omp_ssa (gcc::context *ctxt)
806538fd1498Szrj : gimple_opt_pass (pass_data_expand_omp_ssa, ctxt)
806638fd1498Szrj {}
806738fd1498Szrj
806838fd1498Szrj /* opt_pass methods: */
gate(function * fun)806938fd1498Szrj virtual bool gate (function *fun)
807038fd1498Szrj {
807138fd1498Szrj return !(fun->curr_properties & PROP_gimple_eomp);
807238fd1498Szrj }
execute(function *)807338fd1498Szrj virtual unsigned int execute (function *) { return execute_expand_omp (); }
clone()807438fd1498Szrj opt_pass * clone () { return new pass_expand_omp_ssa (m_ctxt); }
807538fd1498Szrj
807638fd1498Szrj }; // class pass_expand_omp_ssa
807738fd1498Szrj
807838fd1498Szrj } // anon namespace
807938fd1498Szrj
808038fd1498Szrj gimple_opt_pass *
make_pass_expand_omp_ssa(gcc::context * ctxt)808138fd1498Szrj make_pass_expand_omp_ssa (gcc::context *ctxt)
808238fd1498Szrj {
808338fd1498Szrj return new pass_expand_omp_ssa (ctxt);
808438fd1498Szrj }
808538fd1498Szrj
808638fd1498Szrj /* Called from tree-cfg.c::make_edges to create cfg edges for all relevant
808738fd1498Szrj GIMPLE_* codes. */
808838fd1498Szrj
808938fd1498Szrj bool
omp_make_gimple_edges(basic_block bb,struct omp_region ** region,int * region_idx)809038fd1498Szrj omp_make_gimple_edges (basic_block bb, struct omp_region **region,
809138fd1498Szrj int *region_idx)
809238fd1498Szrj {
809338fd1498Szrj gimple *last = last_stmt (bb);
809438fd1498Szrj enum gimple_code code = gimple_code (last);
809538fd1498Szrj struct omp_region *cur_region = *region;
809638fd1498Szrj bool fallthru = false;
809738fd1498Szrj
809838fd1498Szrj switch (code)
809938fd1498Szrj {
810038fd1498Szrj case GIMPLE_OMP_PARALLEL:
810138fd1498Szrj case GIMPLE_OMP_TASK:
810238fd1498Szrj case GIMPLE_OMP_FOR:
810338fd1498Szrj case GIMPLE_OMP_SINGLE:
810438fd1498Szrj case GIMPLE_OMP_TEAMS:
810538fd1498Szrj case GIMPLE_OMP_MASTER:
810638fd1498Szrj case GIMPLE_OMP_TASKGROUP:
810738fd1498Szrj case GIMPLE_OMP_CRITICAL:
810838fd1498Szrj case GIMPLE_OMP_SECTION:
810938fd1498Szrj case GIMPLE_OMP_GRID_BODY:
811038fd1498Szrj cur_region = new_omp_region (bb, code, cur_region);
811138fd1498Szrj fallthru = true;
811238fd1498Szrj break;
811338fd1498Szrj
811438fd1498Szrj case GIMPLE_OMP_ORDERED:
811538fd1498Szrj cur_region = new_omp_region (bb, code, cur_region);
811638fd1498Szrj fallthru = true;
811738fd1498Szrj if (omp_find_clause (gimple_omp_ordered_clauses
811838fd1498Szrj (as_a <gomp_ordered *> (last)),
811938fd1498Szrj OMP_CLAUSE_DEPEND))
812038fd1498Szrj cur_region = cur_region->outer;
812138fd1498Szrj break;
812238fd1498Szrj
812338fd1498Szrj case GIMPLE_OMP_TARGET:
812438fd1498Szrj cur_region = new_omp_region (bb, code, cur_region);
812538fd1498Szrj fallthru = true;
812638fd1498Szrj switch (gimple_omp_target_kind (last))
812738fd1498Szrj {
812838fd1498Szrj case GF_OMP_TARGET_KIND_REGION:
812938fd1498Szrj case GF_OMP_TARGET_KIND_DATA:
813038fd1498Szrj case GF_OMP_TARGET_KIND_OACC_PARALLEL:
813138fd1498Szrj case GF_OMP_TARGET_KIND_OACC_KERNELS:
813238fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DATA:
813338fd1498Szrj case GF_OMP_TARGET_KIND_OACC_HOST_DATA:
813438fd1498Szrj break;
813538fd1498Szrj case GF_OMP_TARGET_KIND_UPDATE:
813638fd1498Szrj case GF_OMP_TARGET_KIND_ENTER_DATA:
813738fd1498Szrj case GF_OMP_TARGET_KIND_EXIT_DATA:
813838fd1498Szrj case GF_OMP_TARGET_KIND_OACC_UPDATE:
813938fd1498Szrj case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
814038fd1498Szrj case GF_OMP_TARGET_KIND_OACC_DECLARE:
814138fd1498Szrj cur_region = cur_region->outer;
814238fd1498Szrj break;
814338fd1498Szrj default:
814438fd1498Szrj gcc_unreachable ();
814538fd1498Szrj }
814638fd1498Szrj break;
814738fd1498Szrj
814838fd1498Szrj case GIMPLE_OMP_SECTIONS:
814938fd1498Szrj cur_region = new_omp_region (bb, code, cur_region);
815038fd1498Szrj fallthru = true;
815138fd1498Szrj break;
815238fd1498Szrj
815338fd1498Szrj case GIMPLE_OMP_SECTIONS_SWITCH:
815438fd1498Szrj fallthru = false;
815538fd1498Szrj break;
815638fd1498Szrj
815738fd1498Szrj case GIMPLE_OMP_ATOMIC_LOAD:
815838fd1498Szrj case GIMPLE_OMP_ATOMIC_STORE:
815938fd1498Szrj fallthru = true;
816038fd1498Szrj break;
816138fd1498Szrj
816238fd1498Szrj case GIMPLE_OMP_RETURN:
816338fd1498Szrj /* In the case of a GIMPLE_OMP_SECTION, the edge will go
816438fd1498Szrj somewhere other than the next block. This will be
816538fd1498Szrj created later. */
816638fd1498Szrj cur_region->exit = bb;
816738fd1498Szrj if (cur_region->type == GIMPLE_OMP_TASK)
816838fd1498Szrj /* Add an edge corresponding to not scheduling the task
816938fd1498Szrj immediately. */
817038fd1498Szrj make_edge (cur_region->entry, bb, EDGE_ABNORMAL);
817138fd1498Szrj fallthru = cur_region->type != GIMPLE_OMP_SECTION;
817238fd1498Szrj cur_region = cur_region->outer;
817338fd1498Szrj break;
817438fd1498Szrj
817538fd1498Szrj case GIMPLE_OMP_CONTINUE:
817638fd1498Szrj cur_region->cont = bb;
817738fd1498Szrj switch (cur_region->type)
817838fd1498Szrj {
817938fd1498Szrj case GIMPLE_OMP_FOR:
818038fd1498Szrj /* Mark all GIMPLE_OMP_FOR and GIMPLE_OMP_CONTINUE
818138fd1498Szrj succs edges as abnormal to prevent splitting
818238fd1498Szrj them. */
818338fd1498Szrj single_succ_edge (cur_region->entry)->flags |= EDGE_ABNORMAL;
818438fd1498Szrj /* Make the loopback edge. */
818538fd1498Szrj make_edge (bb, single_succ (cur_region->entry),
818638fd1498Szrj EDGE_ABNORMAL);
818738fd1498Szrj
818838fd1498Szrj /* Create an edge from GIMPLE_OMP_FOR to exit, which
818938fd1498Szrj corresponds to the case that the body of the loop
819038fd1498Szrj is not executed at all. */
819138fd1498Szrj make_edge (cur_region->entry, bb->next_bb, EDGE_ABNORMAL);
819238fd1498Szrj make_edge (bb, bb->next_bb, EDGE_FALLTHRU | EDGE_ABNORMAL);
819338fd1498Szrj fallthru = false;
819438fd1498Szrj break;
819538fd1498Szrj
819638fd1498Szrj case GIMPLE_OMP_SECTIONS:
819738fd1498Szrj /* Wire up the edges into and out of the nested sections. */
819838fd1498Szrj {
819938fd1498Szrj basic_block switch_bb = single_succ (cur_region->entry);
820038fd1498Szrj
820138fd1498Szrj struct omp_region *i;
820238fd1498Szrj for (i = cur_region->inner; i ; i = i->next)
820338fd1498Szrj {
820438fd1498Szrj gcc_assert (i->type == GIMPLE_OMP_SECTION);
820538fd1498Szrj make_edge (switch_bb, i->entry, 0);
820638fd1498Szrj make_edge (i->exit, bb, EDGE_FALLTHRU);
820738fd1498Szrj }
820838fd1498Szrj
820938fd1498Szrj /* Make the loopback edge to the block with
821038fd1498Szrj GIMPLE_OMP_SECTIONS_SWITCH. */
821138fd1498Szrj make_edge (bb, switch_bb, 0);
821238fd1498Szrj
821338fd1498Szrj /* Make the edge from the switch to exit. */
821438fd1498Szrj make_edge (switch_bb, bb->next_bb, 0);
821538fd1498Szrj fallthru = false;
821638fd1498Szrj }
821738fd1498Szrj break;
821838fd1498Szrj
821938fd1498Szrj case GIMPLE_OMP_TASK:
822038fd1498Szrj fallthru = true;
822138fd1498Szrj break;
822238fd1498Szrj
822338fd1498Szrj default:
822438fd1498Szrj gcc_unreachable ();
822538fd1498Szrj }
822638fd1498Szrj break;
822738fd1498Szrj
822838fd1498Szrj default:
822938fd1498Szrj gcc_unreachable ();
823038fd1498Szrj }
823138fd1498Szrj
823238fd1498Szrj if (*region != cur_region)
823338fd1498Szrj {
823438fd1498Szrj *region = cur_region;
823538fd1498Szrj if (cur_region)
823638fd1498Szrj *region_idx = cur_region->entry->index;
823738fd1498Szrj else
823838fd1498Szrj *region_idx = 0;
823938fd1498Szrj }
824038fd1498Szrj
824138fd1498Szrj return fallthru;
824238fd1498Szrj }
824338fd1498Szrj
824438fd1498Szrj #include "gt-omp-expand.h"
8245