LCOV - code coverage report
Current view: top level - gcc - omp-offload.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 76.5 % 1259 963
Test Date: 2024-03-23 14:05:01 Functions: 81.4 % 59 48
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Bits of OpenMP and OpenACC handling that is specific to device offloading
       2                 :             :    and a lowering pass for OpenACC device directives.
       3                 :             : 
       4                 :             :    Copyright (C) 2005-2024 Free Software Foundation, Inc.
       5                 :             : 
       6                 :             : This file is part of GCC.
       7                 :             : 
       8                 :             : GCC is free software; you can redistribute it and/or modify it under
       9                 :             : the terms of the GNU General Public License as published by the Free
      10                 :             : Software Foundation; either version 3, or (at your option) any later
      11                 :             : version.
      12                 :             : 
      13                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16                 :             : for more details.
      17                 :             : 
      18                 :             : You should have received a copy of the GNU General Public License
      19                 :             : along with GCC; see the file COPYING3.  If not see
      20                 :             : <http://www.gnu.org/licenses/>.  */
      21                 :             : 
      22                 :             : #include "config.h"
      23                 :             : #include "system.h"
      24                 :             : #include "coretypes.h"
      25                 :             : #include "backend.h"
      26                 :             : #include "target.h"
      27                 :             : #include "tree.h"
      28                 :             : #include "gimple.h"
      29                 :             : #include "tree-pass.h"
      30                 :             : #include "ssa.h"
      31                 :             : #include "cgraph.h"
      32                 :             : #include "pretty-print.h"
      33                 :             : #include "diagnostic-core.h"
      34                 :             : #include "fold-const.h"
      35                 :             : #include "internal-fn.h"
      36                 :             : #include "langhooks.h"
      37                 :             : #include "gimplify.h"
      38                 :             : #include "gimple-iterator.h"
      39                 :             : #include "gimplify-me.h"
      40                 :             : #include "gimple-walk.h"
      41                 :             : #include "tree-cfg.h"
      42                 :             : #include "tree-into-ssa.h"
      43                 :             : #include "tree-nested.h"
      44                 :             : #include "stor-layout.h"
      45                 :             : #include "common/common-target.h"
      46                 :             : #include "omp-general.h"
      47                 :             : #include "omp-offload.h"
      48                 :             : #include "lto-section-names.h"
      49                 :             : #include "gomp-constants.h"
      50                 :             : #include "gimple-pretty-print.h"
      51                 :             : #include "intl.h"
      52                 :             : #include "stringpool.h"
      53                 :             : #include "attribs.h"
      54                 :             : #include "cfgloop.h"
      55                 :             : #include "context.h"
      56                 :             : #include "convert.h"
      57                 :             : #include "opts.h"
      58                 :             : 
      59                 :             : /* Describe the OpenACC looping structure of a function.  The entire
      60                 :             :    function is held in a 'NULL' loop.  */
      61                 :             : 
      62                 :             : struct oacc_loop
      63                 :             : {
      64                 :             :   oacc_loop *parent; /* Containing loop.  */
      65                 :             : 
      66                 :             :   oacc_loop *child; /* First inner loop.  */
      67                 :             : 
      68                 :             :   oacc_loop *sibling; /* Next loop within same parent.  */
      69                 :             : 
      70                 :             :   location_t loc; /* Location of the loop start.  */
      71                 :             : 
      72                 :             :   gcall *marker; /* Initial head marker.  */
      73                 :             : 
      74                 :             :   gcall *heads[GOMP_DIM_MAX];  /* Head marker functions.  */
      75                 :             :   gcall *tails[GOMP_DIM_MAX];  /* Tail marker functions.  */
      76                 :             : 
      77                 :             :   tree routine;  /* Pseudo-loop enclosing a routine.  */
      78                 :             : 
      79                 :             :   unsigned mask;   /* Partitioning mask.  */
      80                 :             :   unsigned e_mask; /* Partitioning of element loops (when tiling).  */
      81                 :             :   unsigned inner;  /* Partitioning of inner loops.  */
      82                 :             :   unsigned flags;  /* Partitioning flags.  */
      83                 :             :   vec<gcall *> ifns;  /* Contained loop abstraction functions.  */
      84                 :             :   tree chunk_size; /* Chunk size.  */
      85                 :             :   gcall *head_end; /* Final marker of head sequence.  */
      86                 :             : };
      87                 :             : 
      88                 :             : /* Holds offload tables with decls.  */
      89                 :             : vec<tree, va_gc> *offload_funcs, *offload_vars, *offload_ind_funcs;
      90                 :             : 
      91                 :             : /* Return level at which oacc routine may spawn a partitioned loop, or
      92                 :             :    -1 if it is not a routine (i.e. is an offload fn).  */
      93                 :             : 
      94                 :             : int
      95                 :       10584 : oacc_fn_attrib_level (tree attr)
      96                 :             : {
      97                 :       10584 :   tree pos = TREE_VALUE (attr);
      98                 :             : 
      99                 :       10584 :   if (!TREE_PURPOSE (pos))
     100                 :             :     return -1;
     101                 :             : 
     102                 :             :   int ix = 0;
     103                 :        4937 :   for (ix = 0; ix != GOMP_DIM_MAX;
     104                 :        3299 :        ix++, pos = TREE_CHAIN (pos))
     105                 :        4062 :     if (!integer_zerop (TREE_PURPOSE (pos)))
     106                 :             :       break;
     107                 :             : 
     108                 :             :   return ix;
     109                 :             : }
     110                 :             : 
     111                 :             : /* Helper function for omp_finish_file routine.  Takes decls from V_DECLS and
     112                 :             :    adds their addresses and sizes to constructor-vector V_CTOR.  */
     113                 :             : 
     114                 :             : static void
     115                 :          90 : add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls,
     116                 :             :                                          vec<constructor_elt, va_gc> *v_ctor)
     117                 :             : {
     118                 :          90 :   unsigned len = vec_safe_length (v_decls);
     119                 :         169 :   for (unsigned i = 0; i < len; i++)
     120                 :             :     {
     121                 :          79 :       tree it = (*v_decls)[i];
     122                 :          79 :       bool is_var = VAR_P (it);
     123                 :          79 :       bool is_link_var
     124                 :             :         = is_var
     125                 :             : #ifdef ACCEL_COMPILER
     126                 :             :           && DECL_HAS_VALUE_EXPR_P (it)
     127                 :             : #endif
     128                 :          79 :           && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (it));
     129                 :             : 
     130                 :             :       /* See also omp_finish_file and output_offload_tables in lto-cgraph.cc.  */
     131                 :          79 :       if (!in_lto_p && !symtab_node::get (it))
     132                 :           0 :         continue;
     133                 :             : 
     134                 :          79 :       tree size = NULL_TREE;
     135                 :          79 :       if (is_var)
     136                 :           0 :         size = fold_convert (const_ptr_type_node, DECL_SIZE_UNIT (it));
     137                 :             : 
     138                 :          79 :       tree addr;
     139                 :          79 :       if (!is_link_var)
     140                 :          79 :         addr = build_fold_addr_expr (it);
     141                 :             :       else
     142                 :             :         {
     143                 :             : #ifdef ACCEL_COMPILER
     144                 :             :           /* For "omp declare target link" vars add address of the pointer to
     145                 :             :              the target table, instead of address of the var.  */
     146                 :             :           tree value_expr = DECL_VALUE_EXPR (it);
     147                 :             :           tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
     148                 :             :           varpool_node::finalize_decl (link_ptr_decl);
     149                 :             :           addr = build_fold_addr_expr (link_ptr_decl);
     150                 :             : #else
     151                 :           0 :           addr = build_fold_addr_expr (it);
     152                 :             : #endif
     153                 :             : 
     154                 :             :           /* Most significant bit of the size marks "omp declare target link"
     155                 :             :              vars in host and target tables.  */
     156                 :           0 :           unsigned HOST_WIDE_INT isize = tree_to_uhwi (size);
     157                 :           0 :           isize |= 1ULL << (int_size_in_bytes (const_ptr_type_node)
     158                 :           0 :                             * BITS_PER_UNIT - 1);
     159                 :           0 :           size = wide_int_to_tree (const_ptr_type_node, isize);
     160                 :             :         }
     161                 :             : 
     162                 :          79 :       CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, addr);
     163                 :          79 :       if (is_var)
     164                 :           0 :         CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, size);
     165                 :             :     }
     166                 :          90 : }
     167                 :             : 
     168                 :             : /* Return true if DECL is a function for which its references should be
     169                 :             :    analyzed.  */
     170                 :             : 
     171                 :             : static bool
     172                 :       72618 : omp_declare_target_fn_p (tree decl)
     173                 :             : {
     174                 :       72618 :   return (TREE_CODE (decl) == FUNCTION_DECL
     175                 :       72618 :           && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
     176                 :       10841 :           && !lookup_attribute ("omp declare target host",
     177                 :       10841 :                                 DECL_ATTRIBUTES (decl))
     178                 :       83404 :           && (!flag_openacc
     179                 :          57 :               || oacc_get_fn_attrib (decl) == NULL_TREE));
     180                 :             : }
     181                 :             : 
     182                 :             : /* Return true if DECL Is a variable for which its initializer references
     183                 :             :    should be analyzed.  */
     184                 :             : 
     185                 :             : static bool
     186                 :       10320 : omp_declare_target_var_p (tree decl)
     187                 :             : {
     188                 :       10320 :   return (VAR_P (decl)
     189                 :       10320 :           && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
     190                 :       10764 :           && !lookup_attribute ("omp declare target link",
     191                 :         444 :                                 DECL_ATTRIBUTES (decl)));
     192                 :             : }
     193                 :             : 
     194                 :             : /* Helper function for omp_discover_implicit_declare_target, called through
     195                 :             :    walk_tree.  Mark referenced FUNCTION_DECLs implicitly as
     196                 :             :    declare target to.  */
     197                 :             : 
     198                 :             : static tree
     199                 :      683876 : omp_discover_declare_target_tgt_fn_r (tree *tp, int *walk_subtrees, void *data)
     200                 :             : {
     201                 :      683876 :   if (TREE_CODE (*tp) == CALL_EXPR
     202                 :       10538 :       && CALL_EXPR_FN (*tp)
     203                 :       10538 :       && TREE_CODE (CALL_EXPR_FN (*tp)) == ADDR_EXPR
     204                 :       10492 :       && TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (*tp), 0)) == FUNCTION_DECL
     205                 :      694368 :       && lookup_attribute ("omp declare variant base",
     206                 :       10492 :                            DECL_ATTRIBUTES (TREE_OPERAND (CALL_EXPR_FN (*tp),
     207                 :             :                                                           0))))
     208                 :             :     {
     209                 :          38 :       tree fn = TREE_OPERAND (CALL_EXPR_FN (*tp), 0);
     210                 :          88 :       for (tree attr = DECL_ATTRIBUTES (fn); attr; attr = TREE_CHAIN (attr))
     211                 :             :         {
     212                 :          51 :           attr = lookup_attribute ("omp declare variant base", attr);
     213                 :          51 :           if (attr == NULL_TREE)
     214                 :             :             break;
     215                 :          50 :           tree purpose = TREE_PURPOSE (TREE_VALUE (attr));
     216                 :          50 :           if (TREE_CODE (purpose) == FUNCTION_DECL)
     217                 :          50 :             omp_discover_declare_target_tgt_fn_r (&purpose, walk_subtrees, data);
     218                 :             :         }
     219                 :             :     }
     220                 :      683838 :   else if (TREE_CODE (*tp) == FUNCTION_DECL)
     221                 :             :     {
     222                 :        7099 :       tree decl = *tp;
     223                 :        7099 :       tree id = get_identifier ("omp declare target");
     224                 :        7099 :       symtab_node *node = symtab_node::get (*tp);
     225                 :        7099 :       if (node != NULL)
     226                 :             :         {
     227                 :        3678 :           while (node->alias_target
     228                 :        3678 :                  && TREE_CODE (node->alias_target) == FUNCTION_DECL)
     229                 :             :             {
     230                 :           4 :               if (!omp_declare_target_fn_p (node->decl)
     231                 :           8 :                   && !lookup_attribute ("omp declare target host",
     232                 :           4 :                                         DECL_ATTRIBUTES (node->decl)))
     233                 :             :                 {
     234                 :           4 :                   node->offloadable = 1;
     235                 :           4 :                   DECL_ATTRIBUTES (node->decl)
     236                 :           8 :                     = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (node->decl));
     237                 :             :                 }
     238                 :           4 :               node = symtab_node::get (node->alias_target);
     239                 :             :             }
     240                 :        3674 :           symtab_node *new_node = node->ultimate_alias_target ();
     241                 :        3674 :           decl = new_node->decl;
     242                 :        3797 :           while (node != new_node)
     243                 :             :             {
     244                 :         123 :               if (!omp_declare_target_fn_p (node->decl)
     245                 :         131 :                   && !lookup_attribute ("omp declare target host",
     246                 :           8 :                                         DECL_ATTRIBUTES (node->decl)))
     247                 :             :                 {
     248                 :           8 :                   node->offloadable = 1;
     249                 :           8 :                   DECL_ATTRIBUTES (node->decl)
     250                 :          16 :                     = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (node->decl));
     251                 :             :                 }
     252                 :         123 :               gcc_assert (node->alias && node->analyzed);
     253                 :         123 :               node = node->get_alias_target ();
     254                 :             :             }
     255                 :        3674 :           node->offloadable = 1;
     256                 :        3674 :           if (ENABLE_OFFLOADING)
     257                 :             :             g->have_offload = true;
     258                 :             :         }
     259                 :        7099 :       if (omp_declare_target_fn_p (decl)
     260                 :        8491 :           || lookup_attribute ("omp declare target host",
     261                 :        1392 :                                DECL_ATTRIBUTES (decl)))
     262                 :        5707 :         return NULL_TREE;
     263                 :             : 
     264                 :        1392 :       if (!DECL_EXTERNAL (decl) && DECL_SAVED_TREE (decl))
     265                 :         283 :         ((vec<tree> *) data)->safe_push (decl);
     266                 :        1392 :       DECL_ATTRIBUTES (decl) = tree_cons (id, NULL_TREE,
     267                 :        1392 :                                           DECL_ATTRIBUTES (decl));
     268                 :             :     }
     269                 :      676739 :   else if (TYPE_P (*tp))
     270                 :          31 :     *walk_subtrees = 0;
     271                 :      676708 :   else if (TREE_CODE (*tp) == OMP_TARGET)
     272                 :             :     {
     273                 :        1684 :       tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
     274                 :        1684 :       if (c && OMP_CLAUSE_DEVICE_ANCESTOR (c))
     275                 :          48 :         *walk_subtrees = 0;
     276                 :             :     }
     277                 :             :   return NULL_TREE;
     278                 :             : }
     279                 :             : 
     280                 :             : /* Similarly, but ignore references outside of OMP_TARGET regions.  */
     281                 :             : 
     282                 :             : static tree
     283                 :      529605 : omp_discover_declare_target_fn_r (tree *tp, int *walk_subtrees, void *data)
     284                 :             : {
     285                 :      529605 :   if (TREE_CODE (*tp) == OMP_TARGET)
     286                 :             :     {
     287                 :       11004 :       tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
     288                 :       11004 :       if (!c || !OMP_CLAUSE_DEVICE_ANCESTOR (c))
     289                 :       10936 :         walk_tree_without_duplicates (&OMP_TARGET_BODY (*tp),
     290                 :             :                                       omp_discover_declare_target_tgt_fn_r,
     291                 :             :                                       data);
     292                 :       11004 :       *walk_subtrees = 0;
     293                 :             :     }
     294                 :      518601 :   else if (TYPE_P (*tp))
     295                 :         237 :     *walk_subtrees = 0;
     296                 :      529605 :   return NULL_TREE;
     297                 :             : }
     298                 :             : 
     299                 :             : /* Helper function for omp_discover_implicit_declare_target, called through
     300                 :             :    walk_tree.  Mark referenced FUNCTION_DECLs implicitly as
     301                 :             :    declare target to.  */
     302                 :             : 
     303                 :             : static tree
     304                 :         290 : omp_discover_declare_target_var_r (tree *tp, int *walk_subtrees, void *data)
     305                 :             : {
     306                 :         290 :   if (TREE_CODE (*tp) == FUNCTION_DECL)
     307                 :          12 :     return omp_discover_declare_target_tgt_fn_r (tp, walk_subtrees, data);
     308                 :         278 :   else if (VAR_P (*tp)
     309                 :          34 :            && is_global_var (*tp)
     310                 :         312 :            && !omp_declare_target_var_p (*tp))
     311                 :             :     {
     312                 :          18 :       tree id = get_identifier ("omp declare target");
     313                 :          18 :       if (lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp)))
     314                 :             :         {
     315                 :           0 :           error_at (DECL_SOURCE_LOCATION (*tp),
     316                 :             :                     "%qD specified both in declare target %<link%> and "
     317                 :             :                     "implicitly in %<to%> clauses", *tp);
     318                 :           0 :           DECL_ATTRIBUTES (*tp)
     319                 :           0 :             = remove_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp));
     320                 :             :         }
     321                 :          18 :       if (TREE_STATIC (*tp) && lang_hooks.decls.omp_get_decl_init (*tp))
     322                 :          18 :         ((vec<tree> *) data)->safe_push (*tp);
     323                 :          18 :       DECL_ATTRIBUTES (*tp) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (*tp));
     324                 :          18 :       symtab_node *node = symtab_node::get (*tp);
     325                 :          18 :       if (node != NULL && !node->offloadable)
     326                 :             :         {
     327                 :          18 :           node->offloadable = 1;
     328                 :          18 :           if (ENABLE_OFFLOADING)
     329                 :             :             {
     330                 :             :               g->have_offload = true;
     331                 :             :               if (is_a <varpool_node *> (node))
     332                 :             :                 vec_safe_push (offload_vars, node->decl);
     333                 :             :             }
     334                 :             :         }
     335                 :             :     }
     336                 :         260 :   else if (TYPE_P (*tp))
     337                 :           0 :     *walk_subtrees = 0;
     338                 :             :   return NULL_TREE;
     339                 :             : }
     340                 :             : 
     341                 :             : /* Perform the OpenMP implicit declare target to discovery.  */
     342                 :             : 
     343                 :             : void
     344                 :        8352 : omp_discover_implicit_declare_target (void)
     345                 :             : {
     346                 :        8352 :   cgraph_node *node;
     347                 :        8352 :   varpool_node *vnode;
     348                 :        8352 :   auto_vec<tree> worklist;
     349                 :             : 
     350                 :       66133 :   FOR_EACH_DEFINED_FUNCTION (node)
     351                 :       57781 :     if (DECL_SAVED_TREE (node->decl))
     352                 :             :       {
     353                 :       54670 :         struct cgraph_node *cgn;
     354                 :       54670 :         if (lookup_attribute ("omp declare target indirect",
     355                 :       54670 :                               DECL_ATTRIBUTES (node->decl)))
     356                 :         141 :           vec_safe_push (offload_ind_funcs, node->decl);
     357                 :       54670 :         if (omp_declare_target_fn_p (node->decl))
     358                 :        2307 :           worklist.safe_push (node->decl);
     359                 :       52363 :         else if (DECL_STRUCT_FUNCTION (node->decl)
     360                 :       52363 :                  && DECL_STRUCT_FUNCTION (node->decl)->has_omp_target)
     361                 :        5934 :           worklist.safe_push (node->decl);
     362                 :       56527 :         for (cgn = first_nested_function (node);
     363                 :       56527 :              cgn; cgn = next_nested_function (cgn))
     364                 :        1857 :           if (omp_declare_target_fn_p (cgn->decl))
     365                 :          21 :             worklist.safe_push (cgn->decl);
     366                 :        1836 :           else if (DECL_STRUCT_FUNCTION (cgn->decl)
     367                 :        1836 :                    && DECL_STRUCT_FUNCTION (cgn->decl)->has_omp_target)
     368                 :         320 :             worklist.safe_push (cgn->decl);
     369                 :             :       }
     370                 :       47798 :   FOR_EACH_VARIABLE (vnode)
     371                 :       15547 :     if (lang_hooks.decls.omp_get_decl_init (vnode->decl)
     372                 :       15547 :         && omp_declare_target_var_p (vnode->decl))
     373                 :         428 :       worklist.safe_push (vnode->decl);
     374                 :       17663 :   while (!worklist.is_empty ())
     375                 :             :     {
     376                 :        9311 :       tree decl = worklist.pop ();
     377                 :        9311 :       if (VAR_P (decl))
     378                 :         446 :         walk_tree_without_duplicates (lang_hooks.decls.omp_get_decl_init (decl),
     379                 :             :                                       omp_discover_declare_target_var_r,
     380                 :             :                                       &worklist);
     381                 :        8865 :       else if (omp_declare_target_fn_p (decl))
     382                 :        2611 :         walk_tree_without_duplicates (&DECL_SAVED_TREE (decl),
     383                 :             :                                       omp_discover_declare_target_tgt_fn_r,
     384                 :             :                                       &worklist);
     385                 :             :       else
     386                 :        6254 :         walk_tree_without_duplicates (&DECL_SAVED_TREE (decl),
     387                 :             :                                       omp_discover_declare_target_fn_r,
     388                 :             :                                       &worklist);
     389                 :             :     }
     390                 :             : 
     391                 :        8352 :   lang_hooks.decls.omp_finish_decl_inits ();
     392                 :        8352 : }
     393                 :             : 
     394                 :             : 
     395                 :             : /* Create new symbols containing (address, size) pairs for global variables,
     396                 :             :    marked with "omp declare target" attribute, as well as addresses for the
     397                 :             :    functions, which are outlined offloading regions.  */
     398                 :             : void
     399                 :      229350 : omp_finish_file (void)
     400                 :             : {
     401                 :      229350 :   unsigned num_funcs = vec_safe_length (offload_funcs);
     402                 :      229350 :   unsigned num_vars = vec_safe_length (offload_vars);
     403                 :      229350 :   unsigned num_ind_funcs = vec_safe_length (offload_ind_funcs);
     404                 :             : 
     405                 :      229350 :   if (num_funcs == 0 && num_vars == 0 && num_ind_funcs == 0)
     406                 :      229350 :     return;
     407                 :             : 
     408                 :          30 :   if (targetm_common.have_named_sections)
     409                 :             :     {
     410                 :          30 :       vec<constructor_elt, va_gc> *v_f, *v_v, *v_if;
     411                 :          30 :       vec_alloc (v_f, num_funcs);
     412                 :          30 :       vec_alloc (v_v, num_vars * 2);
     413                 :          30 :       vec_alloc (v_if, num_ind_funcs);
     414                 :             : 
     415                 :          30 :       add_decls_addresses_to_decl_constructor (offload_funcs, v_f);
     416                 :          30 :       add_decls_addresses_to_decl_constructor (offload_vars, v_v);
     417                 :          30 :       add_decls_addresses_to_decl_constructor (offload_ind_funcs, v_if);
     418                 :             : 
     419                 :          30 :       tree vars_decl_type = build_array_type_nelts (pointer_sized_int_node,
     420                 :          30 :                                                     vec_safe_length (v_v));
     421                 :          30 :       tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
     422                 :             :                                                      num_funcs);
     423                 :          30 :       tree ind_funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
     424                 :             :                                                          num_ind_funcs);
     425                 :             : 
     426                 :          30 :       SET_TYPE_ALIGN (vars_decl_type, TYPE_ALIGN (pointer_sized_int_node));
     427                 :          30 :       SET_TYPE_ALIGN (funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node));
     428                 :          30 :       SET_TYPE_ALIGN (ind_funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node));
     429                 :          30 :       tree ctor_v = build_constructor (vars_decl_type, v_v);
     430                 :          30 :       tree ctor_f = build_constructor (funcs_decl_type, v_f);
     431                 :          30 :       tree ctor_if = build_constructor (ind_funcs_decl_type, v_if);
     432                 :          30 :       TREE_CONSTANT (ctor_v) = TREE_CONSTANT (ctor_f) = TREE_CONSTANT (ctor_if) = 1;
     433                 :          30 :       TREE_STATIC (ctor_v) = TREE_STATIC (ctor_f) = TREE_STATIC (ctor_if) = 1;
     434                 :          30 :       tree funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     435                 :             :                                     get_identifier (".offload_func_table"),
     436                 :             :                                     funcs_decl_type);
     437                 :          30 :       tree vars_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     438                 :             :                                    get_identifier (".offload_var_table"),
     439                 :             :                                    vars_decl_type);
     440                 :          30 :       tree ind_funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     441                 :             :                                         get_identifier (".offload_ind_func_table"),
     442                 :             :                                         ind_funcs_decl_type);
     443                 :          30 :       TREE_STATIC (funcs_decl) = TREE_STATIC (ind_funcs_decl) = 1;
     444                 :          30 :       TREE_STATIC (vars_decl) = 1;
     445                 :             :       /* Do not align tables more than TYPE_ALIGN (pointer_sized_int_node),
     446                 :             :          otherwise a joint table in a binary will contain padding between
     447                 :             :          tables from multiple object files.  */
     448                 :          30 :       DECL_USER_ALIGN (funcs_decl) = DECL_USER_ALIGN (ind_funcs_decl) = 1;
     449                 :          30 :       DECL_USER_ALIGN (vars_decl) = 1;
     450                 :          30 :       SET_DECL_ALIGN (funcs_decl, TYPE_ALIGN (funcs_decl_type));
     451                 :          30 :       SET_DECL_ALIGN (vars_decl, TYPE_ALIGN (vars_decl_type));
     452                 :          30 :       SET_DECL_ALIGN (ind_funcs_decl, TYPE_ALIGN (ind_funcs_decl_type));
     453                 :          30 :       DECL_INITIAL (funcs_decl) = ctor_f;
     454                 :          30 :       DECL_INITIAL (vars_decl) = ctor_v;
     455                 :          30 :       DECL_INITIAL (ind_funcs_decl) = ctor_if;
     456                 :          30 :       set_decl_section_name (funcs_decl, OFFLOAD_FUNC_TABLE_SECTION_NAME);
     457                 :          30 :       set_decl_section_name (vars_decl, OFFLOAD_VAR_TABLE_SECTION_NAME);
     458                 :          30 :       set_decl_section_name (ind_funcs_decl,
     459                 :             :                              OFFLOAD_IND_FUNC_TABLE_SECTION_NAME);
     460                 :          30 :       varpool_node::finalize_decl (vars_decl);
     461                 :          30 :       varpool_node::finalize_decl (funcs_decl);
     462                 :          30 :       varpool_node::finalize_decl (ind_funcs_decl);
     463                 :             :     }
     464                 :             :   else
     465                 :             :     {
     466                 :           0 :       for (unsigned i = 0; i < num_funcs; i++)
     467                 :             :         {
     468                 :           0 :           tree it = (*offload_funcs)[i];
     469                 :             :           /* See also add_decls_addresses_to_decl_constructor
     470                 :             :              and output_offload_tables in lto-cgraph.cc.  */
     471                 :           0 :           if (!in_lto_p && !symtab_node::get (it))
     472                 :           0 :             continue;
     473                 :           0 :           targetm.record_offload_symbol (it);
     474                 :             :         }
     475                 :           0 :       for (unsigned i = 0; i < num_vars; i++)
     476                 :             :         {
     477                 :           0 :           tree it = (*offload_vars)[i];
     478                 :           0 :           if (!in_lto_p && !symtab_node::get (it))
     479                 :           0 :             continue;
     480                 :             : #ifdef ACCEL_COMPILER
     481                 :             :           if (DECL_HAS_VALUE_EXPR_P (it)
     482                 :             :               && lookup_attribute ("omp declare target link",
     483                 :             :                                    DECL_ATTRIBUTES (it)))
     484                 :             :             {
     485                 :             :               tree value_expr = DECL_VALUE_EXPR (it);
     486                 :             :               tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
     487                 :             :               targetm.record_offload_symbol (link_ptr_decl);
     488                 :             :               varpool_node::finalize_decl (link_ptr_decl);
     489                 :             :             }
     490                 :             :           else
     491                 :             : #endif
     492                 :           0 :             targetm.record_offload_symbol (it);
     493                 :             :         }
     494                 :           0 :       for (unsigned i = 0; i < num_ind_funcs; i++)
     495                 :             :         {
     496                 :           0 :           tree it = (*offload_ind_funcs)[i];
     497                 :             :           /* See also add_decls_addresses_to_decl_constructor
     498                 :             :              and output_offload_tables in lto-cgraph.cc.  */
     499                 :           0 :           if (!in_lto_p && !symtab_node::get (it))
     500                 :           0 :             continue;
     501                 :           0 :           targetm.record_offload_symbol (it);
     502                 :             :         }
     503                 :             :     }
     504                 :             : }
     505                 :             : 
     506                 :             : /* Call dim_pos (POS == true) or dim_size (POS == false) builtins for
     507                 :             :    axis DIM.  Return a tmp var holding the result.  */
     508                 :             : 
     509                 :             : static tree
     510                 :       28271 : oacc_dim_call (bool pos, int dim, gimple_seq *seq)
     511                 :             : {
     512                 :       28271 :   tree arg = build_int_cst (unsigned_type_node, dim);
     513                 :       28271 :   tree size = create_tmp_var (integer_type_node);
     514                 :       28271 :   enum internal_fn fn = pos ? IFN_GOACC_DIM_POS : IFN_GOACC_DIM_SIZE;
     515                 :       28271 :   gimple *call = gimple_build_call_internal (fn, 1, arg);
     516                 :             : 
     517                 :       28271 :   gimple_call_set_lhs (call, size);
     518                 :       28271 :   gimple_seq_add_stmt (seq, call);
     519                 :             : 
     520                 :       28271 :   return size;
     521                 :             : }
     522                 :             : 
     523                 :             : /* Find the number of threads (POS = false), or thread number (POS =
     524                 :             :    true) for an OpenACC region partitioned as MASK.  Setup code
     525                 :             :    required for the calculation is added to SEQ.  */
     526                 :             : 
     527                 :             : static tree
     528                 :       21881 : oacc_thread_numbers (bool pos, int mask, gimple_seq *seq)
     529                 :             : {
     530                 :       21881 :   tree res = pos ? NULL_TREE : build_int_cst (unsigned_type_node, 1);
     531                 :       21881 :   unsigned ix;
     532                 :             : 
     533                 :             :   /* Start at gang level, and examine relevant dimension indices.  */
     534                 :       87524 :   for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
     535                 :       65643 :     if (GOMP_DIM_MASK (ix) & mask)
     536                 :             :       {
     537                 :       24375 :         if (res)
     538                 :             :           {
     539                 :             :             /* We had an outer index, so scale that by the size of
     540                 :             :                this dimension.  */
     541                 :       16027 :             tree n = oacc_dim_call (false, ix, seq);
     542                 :       16027 :             res = fold_build2 (MULT_EXPR, integer_type_node, res, n);
     543                 :             :           }
     544                 :       24375 :         if (pos)
     545                 :             :           {
     546                 :             :             /* Determine index in this dimension.  */
     547                 :       12244 :             tree id = oacc_dim_call (true, ix, seq);
     548                 :       12244 :             if (res)
     549                 :        3896 :               res = fold_build2 (PLUS_EXPR, integer_type_node, res, id);
     550                 :             :             else
     551                 :             :               res = id;
     552                 :             :           }
     553                 :             :       }
     554                 :             : 
     555                 :       21881 :   if (res == NULL_TREE)
     556                 :        2645 :     res = integer_zero_node;
     557                 :             : 
     558                 :       21881 :   return res;
     559                 :             : }
     560                 :             : 
     561                 :             : /* Transform IFN_GOACC_LOOP calls to actual code.  See
     562                 :             :    expand_oacc_for for where these are generated.  At the vector
     563                 :             :    level, we stride loops, such that each member of a warp will
     564                 :             :    operate on adjacent iterations.  At the worker and gang level,
     565                 :             :    each gang/warp executes a set of contiguous iterations.  Chunking
     566                 :             :    can override this such that each iteration engine executes a
     567                 :             :    contiguous chunk, and then moves on to stride to the next chunk.  */
     568                 :             : 
     569                 :             : static void
     570                 :       43199 : oacc_xform_loop (gcall *call)
     571                 :             : {
     572                 :       43199 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
     573                 :       43199 :   enum ifn_goacc_loop_kind code
     574                 :       43199 :     = (enum ifn_goacc_loop_kind) TREE_INT_CST_LOW (gimple_call_arg (call, 0));
     575                 :       43199 :   tree dir = gimple_call_arg (call, 1);
     576                 :       43199 :   tree range = gimple_call_arg (call, 2);
     577                 :       43199 :   tree step = gimple_call_arg (call, 3);
     578                 :       43199 :   tree chunk_size = NULL_TREE;
     579                 :       43199 :   unsigned mask = (unsigned) TREE_INT_CST_LOW (gimple_call_arg (call, 5));
     580                 :       43199 :   tree lhs = gimple_call_lhs (call);
     581                 :       43199 :   tree type = NULL_TREE;
     582                 :       43199 :   tree diff_type = TREE_TYPE (range);
     583                 :       43199 :   tree r = NULL_TREE;
     584                 :       43199 :   gimple_seq seq = NULL;
     585                 :       43199 :   bool chunking = false, striding = true;
     586                 :       43199 :   unsigned outer_mask = mask & (~mask + 1); // Outermost partitioning
     587                 :       43199 :   unsigned inner_mask = mask & ~outer_mask; // Inner partitioning (if any)
     588                 :             : 
     589                 :             :   /* Skip lowering if return value of IFN_GOACC_LOOP call is not used.  */
     590                 :       43199 :   if (!lhs)
     591                 :             :     {
     592                 :          10 :       gsi_replace_with_seq (&gsi, seq, true);
     593                 :          10 :       return;
     594                 :             :     }
     595                 :             : 
     596                 :       43189 :   type = TREE_TYPE (lhs);
     597                 :             : 
     598                 :             : #ifdef ACCEL_COMPILER
     599                 :             :   chunk_size = gimple_call_arg (call, 4);
     600                 :             :   if (integer_minus_onep (chunk_size)  /* Force static allocation.  */
     601                 :             :       || integer_zerop (chunk_size))   /* Default (also static).  */
     602                 :             :     {
     603                 :             :       /* If we're at the gang level, we want each to execute a
     604                 :             :          contiguous run of iterations.  Otherwise we want each element
     605                 :             :          to stride.  */
     606                 :             :       striding = !(outer_mask & GOMP_DIM_MASK (GOMP_DIM_GANG));
     607                 :             :       chunking = false;
     608                 :             :     }
     609                 :             :   else
     610                 :             :     {
     611                 :             :       /* Chunk of size 1 is striding.  */
     612                 :             :       striding = integer_onep (chunk_size);
     613                 :             :       chunking = !striding;
     614                 :             :     }
     615                 :             : #endif
     616                 :             : 
     617                 :             :   /* striding=true, chunking=true
     618                 :             :        -> invalid.
     619                 :             :      striding=true, chunking=false
     620                 :             :        -> chunks=1
     621                 :             :      striding=false,chunking=true
     622                 :             :        -> chunks=ceil (range/(chunksize*threads*step))
     623                 :             :      striding=false,chunking=false
     624                 :             :        -> chunk_size=ceil(range/(threads*step)),chunks=1  */
     625                 :       43189 :   push_gimplify_context (true);
     626                 :             : 
     627                 :       43189 :   switch (code)
     628                 :             :     {
     629                 :           0 :     default: gcc_unreachable ();
     630                 :             : 
     631                 :       10320 :     case IFN_GOACC_LOOP_CHUNKS:
     632                 :       10320 :       if (!chunking)
     633                 :       10320 :         r = build_int_cst (type, 1);
     634                 :             :       else
     635                 :             :         {
     636                 :             :           /* chunk_max
     637                 :             :              = (range - dir) / (chunks * step * num_threads) + dir  */
     638                 :             :           tree per = oacc_thread_numbers (false, mask, &seq);
     639                 :             :           per = fold_convert (type, per);
     640                 :             :           chunk_size = fold_convert (type, chunk_size);
     641                 :             :           per = fold_build2 (MULT_EXPR, type, per, chunk_size);
     642                 :             :           per = fold_build2 (MULT_EXPR, type, per, step);
     643                 :             :           r = build2 (MINUS_EXPR, type, range, dir);
     644                 :             :           r = build2 (PLUS_EXPR, type, r, per);
     645                 :             :           r = build2 (TRUNC_DIV_EXPR, type, r, per);
     646                 :             :         }
     647                 :             :       break;
     648                 :             : 
     649                 :       10888 :     case IFN_GOACC_LOOP_STEP:
     650                 :       10888 :       {
     651                 :             :         /* If striding, step by the entire compute volume, otherwise
     652                 :             :            step by the inner volume.  */
     653                 :       10888 :         unsigned volume = striding ? mask : inner_mask;
     654                 :             : 
     655                 :       10888 :         r = oacc_thread_numbers (false, volume, &seq);
     656                 :       10888 :         r = build2 (MULT_EXPR, type, fold_convert (type, r), step);
     657                 :             :       }
     658                 :       10888 :       break;
     659                 :             : 
     660                 :       10993 :     case IFN_GOACC_LOOP_OFFSET:
     661                 :             :       /* Enable vectorization on non-SIMT targets.  */
     662                 :       10993 :       if (!targetm.simt.vf
     663                 :       10993 :           && outer_mask == GOMP_DIM_MASK (GOMP_DIM_VECTOR)
     664                 :             :           /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
     665                 :             :              the loop.  */
     666                 :        1693 :           && (flag_tree_loop_vectorize
     667                 :        1205 :               || !OPTION_SET_P (flag_tree_loop_vectorize)))
     668                 :             :         {
     669                 :        1693 :           basic_block bb = gsi_bb (gsi);
     670                 :        1693 :           class loop *parent = bb->loop_father;
     671                 :        1693 :           class loop *body = parent->inner;
     672                 :             : 
     673                 :        1693 :           parent->force_vectorize = true;
     674                 :        1693 :           parent->safelen = INT_MAX;
     675                 :             : 
     676                 :             :           /* "Chunking loops" may have inner loops.  */
     677                 :        1693 :           if (parent->inner)
     678                 :             :             {
     679                 :        1681 :               body->force_vectorize = true;
     680                 :        1681 :               body->safelen = INT_MAX;
     681                 :             :             }
     682                 :             : 
     683                 :        1693 :           cfun->has_force_vectorize_loops = true;
     684                 :             :         }
     685                 :       10993 :       if (striding)
     686                 :             :         {
     687                 :       10993 :           r = oacc_thread_numbers (true, mask, &seq);
     688                 :       10993 :           r = fold_convert (diff_type, r);
     689                 :             :         }
     690                 :             :       else
     691                 :             :         {
     692                 :             :           tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
     693                 :             :           tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
     694                 :             :           tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
     695                 :             :                                      inner_size, outer_size);
     696                 :             : 
     697                 :             :           volume = fold_convert (diff_type, volume);
     698                 :             :           if (chunking)
     699                 :             :             chunk_size = fold_convert (diff_type, chunk_size);
     700                 :             :           else
     701                 :             :             {
     702                 :             :               tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
     703                 :             : 
     704                 :             :               chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
     705                 :             :               chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
     706                 :             :               chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
     707                 :             :             }
     708                 :             : 
     709                 :             :           tree span = build2 (MULT_EXPR, diff_type, chunk_size,
     710                 :             :                               fold_convert (diff_type, inner_size));
     711                 :             :           r = oacc_thread_numbers (true, outer_mask, &seq);
     712                 :             :           r = fold_convert (diff_type, r);
     713                 :             :           r = build2 (MULT_EXPR, diff_type, r, span);
     714                 :             : 
     715                 :             :           tree inner = oacc_thread_numbers (true, inner_mask, &seq);
     716                 :             :           inner = fold_convert (diff_type, inner);
     717                 :             :           r = fold_build2 (PLUS_EXPR, diff_type, r, inner);
     718                 :             : 
     719                 :             :           if (chunking)
     720                 :             :             {
     721                 :             :               tree chunk = fold_convert (diff_type, gimple_call_arg (call, 6));
     722                 :             :               tree per
     723                 :             :                 = fold_build2 (MULT_EXPR, diff_type, volume, chunk_size);
     724                 :             :               per = build2 (MULT_EXPR, diff_type, per, chunk);
     725                 :             : 
     726                 :             :               r = build2 (PLUS_EXPR, diff_type, r, per);
     727                 :             :             }
     728                 :             :         }
     729                 :       10993 :       r = fold_build2 (MULT_EXPR, diff_type, r, step);
     730                 :       10993 :       if (type != diff_type)
     731                 :         209 :         r = fold_convert (type, r);
     732                 :             :       break;
     733                 :             : 
     734                 :       10988 :     case IFN_GOACC_LOOP_BOUND:
     735                 :       10988 :       if (striding)
     736                 :       10988 :         r = range;
     737                 :             :       else
     738                 :             :         {
     739                 :             :           tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
     740                 :             :           tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
     741                 :             :           tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
     742                 :             :                                      inner_size, outer_size);
     743                 :             : 
     744                 :             :           volume = fold_convert (diff_type, volume);
     745                 :             :           if (chunking)
     746                 :             :             chunk_size = fold_convert (diff_type, chunk_size);
     747                 :             :           else
     748                 :             :             {
     749                 :             :               tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
     750                 :             : 
     751                 :             :               chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
     752                 :             :               chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
     753                 :             :               chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
     754                 :             :             }
     755                 :             : 
     756                 :             :           tree span = build2 (MULT_EXPR, diff_type, chunk_size,
     757                 :             :                               fold_convert (diff_type, inner_size));
     758                 :             : 
     759                 :             :           r = fold_build2 (MULT_EXPR, diff_type, span, step);
     760                 :             : 
     761                 :             :           tree offset = gimple_call_arg (call, 6);
     762                 :             :           r = build2 (PLUS_EXPR, diff_type, r,
     763                 :             :                       fold_convert (diff_type, offset));
     764                 :             :           r = build2 (integer_onep (dir) ? MIN_EXPR : MAX_EXPR,
     765                 :             :                       diff_type, r, range);
     766                 :             :         }
     767                 :       10988 :       if (diff_type != type)
     768                 :         209 :         r = fold_convert (type, r);
     769                 :             :       break;
     770                 :             :     }
     771                 :             : 
     772                 :       43189 :   gimplify_assign (lhs, r, &seq);
     773                 :             : 
     774                 :       43189 :   pop_gimplify_context (NULL);
     775                 :             : 
     776                 :       43189 :   gsi_replace_with_seq (&gsi, seq, true);
     777                 :             : }
     778                 :             : 
     779                 :             : /* Transform a GOACC_TILE call.  Determines the element loop span for
     780                 :             :    the specified loop of the nest.  This is 1 if we're not tiling.
     781                 :             :    
     782                 :             :    GOACC_TILE (collapse_count, loop_no, tile_arg, gwv_tile, gwv_element);  */
     783                 :             : 
     784                 :             : static void
     785                 :         293 : oacc_xform_tile (gcall *call)
     786                 :             : {
     787                 :         293 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
     788                 :         293 :   unsigned collapse = tree_to_uhwi (gimple_call_arg (call, 0));
     789                 :             :   /* Inner loops have higher loop_nos.  */
     790                 :         293 :   unsigned loop_no = tree_to_uhwi (gimple_call_arg (call, 1));
     791                 :         293 :   tree tile_size = gimple_call_arg (call, 2);
     792                 :         293 :   unsigned e_mask = tree_to_uhwi (gimple_call_arg (call, 4));
     793                 :         293 :   tree lhs = gimple_call_lhs (call);
     794                 :         293 :   tree type = TREE_TYPE (lhs);
     795                 :         293 :   gimple_seq seq = NULL;
     796                 :         293 :   tree span = build_int_cst (type, 1);
     797                 :             : 
     798                 :         293 :   gcc_assert (!(e_mask
     799                 :             :                 & ~(GOMP_DIM_MASK (GOMP_DIM_VECTOR)
     800                 :             :                     | GOMP_DIM_MASK (GOMP_DIM_WORKER))));
     801                 :         293 :   push_gimplify_context (!seen_error ());
     802                 :             : 
     803                 :             : #ifndef ACCEL_COMPILER
     804                 :             :   /* Partitioning disabled on host compilers.  */
     805                 :         293 :   e_mask = 0;
     806                 :             : #endif
     807                 :         293 :   if (!e_mask)
     808                 :             :     /* Not paritioning.  */
     809                 :         293 :     span = integer_one_node;
     810                 :             :   else if (!integer_zerop (tile_size))
     811                 :             :     /* User explicitly specified size.  */
     812                 :             :     span = tile_size;
     813                 :             :   else
     814                 :             :     {
     815                 :             :       /* Pick a size based on the paritioning of the element loop and
     816                 :             :          the number of loop nests.  */
     817                 :             :       tree first_size = NULL_TREE;
     818                 :             :       tree second_size = NULL_TREE;
     819                 :             : 
     820                 :             :       if (e_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR))
     821                 :             :         first_size = oacc_dim_call (false, GOMP_DIM_VECTOR, &seq);
     822                 :             :       if (e_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER))
     823                 :             :         second_size = oacc_dim_call (false, GOMP_DIM_WORKER, &seq);
     824                 :             : 
     825                 :             :       if (!first_size)
     826                 :             :         {
     827                 :             :           first_size = second_size;
     828                 :             :           second_size = NULL_TREE;
     829                 :             :         }
     830                 :             : 
     831                 :             :       if (loop_no + 1 == collapse)
     832                 :             :         {
     833                 :             :           span = first_size;
     834                 :             :           if (!loop_no && second_size)
     835                 :             :             span = fold_build2 (MULT_EXPR, TREE_TYPE (span),
     836                 :             :                                 span, second_size);
     837                 :             :         }
     838                 :             :       else if (loop_no + 2 == collapse)
     839                 :             :         span = second_size;
     840                 :             :       else
     841                 :             :         span = NULL_TREE;
     842                 :             : 
     843                 :             :       if (!span)
     844                 :             :         /* There's no obvious element size for this loop.  Options
     845                 :             :            are 1, first_size or some non-unity constant (32 is my
     846                 :             :            favourite).   We should gather some statistics.  */
     847                 :             :         span = first_size;
     848                 :             :     }
     849                 :             : 
     850                 :         293 :   span = fold_convert (type, span);
     851                 :         293 :   gimplify_assign (lhs, span, &seq);
     852                 :             : 
     853                 :         293 :   pop_gimplify_context (NULL);
     854                 :             : 
     855                 :         293 :   gsi_replace_with_seq (&gsi, seq, true);
     856                 :         293 : }
     857                 :             : 
     858                 :             : /* Default partitioned and minimum partitioned dimensions.  */
     859                 :             : 
     860                 :             : static int oacc_default_dims[GOMP_DIM_MAX];
     861                 :             : static int oacc_min_dims[GOMP_DIM_MAX];
     862                 :             : 
     863                 :             : int
     864                 :           0 : oacc_get_default_dim (int dim)
     865                 :             : {
     866                 :           0 :   gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
     867                 :           0 :   return oacc_default_dims[dim];
     868                 :             : }
     869                 :             : 
     870                 :             : int
     871                 :           0 : oacc_get_min_dim (int dim)
     872                 :             : {
     873                 :           0 :   gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
     874                 :           0 :   return oacc_min_dims[dim];
     875                 :             : }
     876                 :             : 
     877                 :             : /* Parse the default dimension parameter.  This is a set of
     878                 :             :    :-separated optional compute dimensions.  Each specified dimension
     879                 :             :    is a positive integer.  When device type support is added, it is
     880                 :             :    planned to be a comma separated list of such compute dimensions,
     881                 :             :    with all but the first prefixed by the colon-terminated device
     882                 :             :    type.  */
     883                 :             : 
     884                 :             : static void
     885                 :        2365 : oacc_parse_default_dims (const char *dims)
     886                 :             : {
     887                 :        2365 :   int ix;
     888                 :             : 
     889                 :        9460 :   for (ix = GOMP_DIM_MAX; ix--;)
     890                 :             :     {
     891                 :        7095 :       oacc_default_dims[ix] = -1;
     892                 :        7095 :       oacc_min_dims[ix] = 1;
     893                 :             :     }
     894                 :             : 
     895                 :             : #ifndef ACCEL_COMPILER
     896                 :             :   /* Cannot be overridden on the host.  */
     897                 :        2365 :   dims = NULL;
     898                 :             : #endif
     899                 :        2365 :   if (dims)
     900                 :             :     {
     901                 :             :       const char *pos = dims;
     902                 :             : 
     903                 :             :       for (ix = 0; *pos && ix != GOMP_DIM_MAX; ix++)
     904                 :             :         {
     905                 :             :           if (ix)
     906                 :             :             {
     907                 :             :               if (*pos != ':')
     908                 :             :                 goto malformed;
     909                 :             :               pos++;
     910                 :             :             }
     911                 :             : 
     912                 :             :           if (*pos != ':')
     913                 :             :             {
     914                 :             :               long val;
     915                 :             :               const char *eptr;
     916                 :             : 
     917                 :             :               errno = 0;
     918                 :             :               val = strtol (pos, CONST_CAST (char **, &eptr), 10);
     919                 :             :               if (errno || val <= 0 || (int) val != val)
     920                 :             :                 goto malformed;
     921                 :             :               pos = eptr;
     922                 :             :               oacc_default_dims[ix] = (int) val;
     923                 :             :             }
     924                 :             :         }
     925                 :             :       if (*pos)
     926                 :             :         {
     927                 :             :         malformed:
     928                 :             :           error_at (UNKNOWN_LOCATION,
     929                 :             :                     "%<-fopenacc-dim%> operand is malformed at %qs", pos);
     930                 :             :         }
     931                 :             :     }
     932                 :             : 
     933                 :             :   /* Allow the backend to validate the dimensions.  */
     934                 :        2365 :   targetm.goacc.validate_dims (NULL_TREE, oacc_default_dims, -1, 0);
     935                 :        2365 :   targetm.goacc.validate_dims (NULL_TREE, oacc_min_dims, -2, 0);
     936                 :        2365 : }
     937                 :             : 
     938                 :             : /* Validate and update the dimensions for offloaded FN.  ATTRS is the
     939                 :             :    raw attribute.  DIMS is an array of dimensions, which is filled in.
     940                 :             :    LEVEL is the partitioning level of a routine, or -1 for an offload
     941                 :             :    region itself.  USED is the mask of partitioned execution in the
     942                 :             :    function.  */
     943                 :             : 
     944                 :             : static void
     945                 :        9453 : oacc_validate_dims (tree fn, tree attrs, int *dims, int level, unsigned used)
     946                 :             : {
     947                 :        9453 :   tree purpose[GOMP_DIM_MAX];
     948                 :        9453 :   unsigned ix;
     949                 :        9453 :   tree pos = TREE_VALUE (attrs);
     950                 :             : 
     951                 :             :   /* Make sure the attribute creator attached the dimension
     952                 :             :      information.  */
     953                 :        9453 :   gcc_assert (pos);
     954                 :             : 
     955                 :       37812 :   for (ix = 0; ix != GOMP_DIM_MAX; ix++)
     956                 :             :     {
     957                 :       28359 :       purpose[ix] = TREE_PURPOSE (pos);
     958                 :       28359 :       tree val = TREE_VALUE (pos);
     959                 :       28359 :       dims[ix] = val ? TREE_INT_CST_LOW (val) : -1;
     960                 :       28359 :       pos = TREE_CHAIN (pos);
     961                 :             :     }
     962                 :             : 
     963                 :        9453 :   bool check = true;
     964                 :             : #ifdef ACCEL_COMPILER
     965                 :             :   check = false;
     966                 :             : #endif
     967                 :        9453 :   if (check
     968                 :        9453 :       && warn_openacc_parallelism
     969                 :        1463 :       && !lookup_attribute ("oacc kernels", DECL_ATTRIBUTES (fn)))
     970                 :             :     {
     971                 :        1331 :       static char const *const axes[] =
     972                 :             :       /* Must be kept in sync with GOMP_DIM enumeration.  */
     973                 :             :         { "gang", "worker", "vector" };
     974                 :        5014 :       for (ix = level >= 0 ? level : 0; ix != GOMP_DIM_MAX; ix++)
     975                 :        3683 :         if (dims[ix] < 0)
     976                 :             :           ; /* Defaulting axis.  */
     977                 :        2021 :         else if ((used & GOMP_DIM_MASK (ix)) && dims[ix] == 1)
     978                 :             :           /* There is partitioned execution, but the user requested a
     979                 :             :              dimension size of 1.  They're probably confused.  */
     980                 :          80 :           warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wopenacc_parallelism,
     981                 :             :                       "region contains %s partitioned code but"
     982                 :          80 :                       " is not %s partitioned", axes[ix], axes[ix]);
     983                 :        1941 :         else if (!(used & GOMP_DIM_MASK (ix)) && dims[ix] != 1)
     984                 :             :           /* The dimension is explicitly partitioned to non-unity, but
     985                 :             :              no use is made within the region.  */
     986                 :         531 :           warning_at (DECL_SOURCE_LOCATION (fn), OPT_Wopenacc_parallelism,
     987                 :             :                       "region is %s partitioned but"
     988                 :             :                       " does not contain %s partitioned code",
     989                 :         531 :                       axes[ix], axes[ix]);
     990                 :             :     }
     991                 :             : 
     992                 :        9453 :   bool changed = targetm.goacc.validate_dims (fn, dims, level, used);
     993                 :             : 
     994                 :             :   /* Default anything left to 1 or a partitioned default.  */
     995                 :       47265 :   for (ix = 0; ix != GOMP_DIM_MAX; ix++)
     996                 :       28359 :     if (dims[ix] < 0)
     997                 :             :       {
     998                 :             :         /* The OpenACC spec says 'If the [num_gangs] clause is not
     999                 :             :            specified, an implementation-defined default will be used;
    1000                 :             :            the default may depend on the code within the construct.'
    1001                 :             :            (2.5.6).  Thus an implementation is free to choose
    1002                 :             :            non-unity default for a parallel region that doesn't have
    1003                 :             :            any gang-partitioned loops.  However, it appears that there
    1004                 :             :            is a sufficient body of user code that expects non-gang
    1005                 :             :            partitioned regions to not execute in gang-redundant mode.
    1006                 :             :            So we (a) don't warn about the non-portability and (b) pick
    1007                 :             :            the minimum permissible dimension size when there is no
    1008                 :             :            partitioned execution.  Otherwise we pick the global
    1009                 :             :            default for the dimension, which the user can control.  The
    1010                 :             :            same wording and logic applies to num_workers and
    1011                 :             :            vector_length, however the worker- or vector- single
    1012                 :             :            execution doesn't have the same impact as gang-redundant
    1013                 :             :            execution.  (If the minimum gang-level partioning is not 1,
    1014                 :             :            the target is probably too confusing.)  */
    1015                 :           0 :         dims[ix] = (used & GOMP_DIM_MASK (ix)
    1016                 :           0 :                     ? oacc_default_dims[ix] : oacc_min_dims[ix]);
    1017                 :           0 :         changed = true;
    1018                 :             :       }
    1019                 :             : 
    1020                 :        9453 :   if (changed)
    1021                 :             :     {
    1022                 :             :       /* Replace the attribute with new values.  */
    1023                 :             :       pos = NULL_TREE;
    1024                 :       36368 :       for (ix = GOMP_DIM_MAX; ix--;)
    1025                 :       27276 :         pos = tree_cons (purpose[ix],
    1026                 :       27276 :                          build_int_cst (integer_type_node, dims[ix]), pos);
    1027                 :        9092 :       oacc_replace_fn_attrib (fn, pos);
    1028                 :             :     }
    1029                 :        9453 : }
    1030                 :             : 
    1031                 :             : /* Create an empty OpenACC loop structure at LOC.  */
    1032                 :             : 
    1033                 :             : static oacc_loop *
    1034                 :       19727 : new_oacc_loop_raw (oacc_loop *parent, location_t loc)
    1035                 :             : {
    1036                 :        9580 :   oacc_loop *loop = XCNEW (oacc_loop);
    1037                 :             : 
    1038                 :       19727 :   loop->parent = parent;
    1039                 :             : 
    1040                 :        9580 :   if (parent)
    1041                 :             :     {
    1042                 :        9580 :       loop->sibling = parent->child;
    1043                 :        9580 :       parent->child = loop;
    1044                 :             :     }
    1045                 :             : 
    1046                 :       19727 :   loop->loc = loc;
    1047                 :       19727 :   return loop;
    1048                 :             : }
    1049                 :             : 
    1050                 :             : /* Create an outermost, dummy OpenACC loop for offloaded function
    1051                 :             :    DECL.  */
    1052                 :             : 
    1053                 :             : static oacc_loop *
    1054                 :        9453 : new_oacc_loop_outer (tree decl)
    1055                 :             : {
    1056                 :        9453 :   return new_oacc_loop_raw (NULL, DECL_SOURCE_LOCATION (decl));
    1057                 :             : }
    1058                 :             : 
    1059                 :             : /* Start a new OpenACC loop  structure beginning at head marker HEAD.
    1060                 :             :    Link into PARENT loop.  Return the new loop.  */
    1061                 :             : 
    1062                 :             : static oacc_loop *
    1063                 :        8519 : new_oacc_loop (oacc_loop *parent, gcall *marker)
    1064                 :             : {
    1065                 :        8519 :   oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (marker));
    1066                 :             : 
    1067                 :        8519 :   loop->marker = marker;
    1068                 :             : 
    1069                 :             :   /* TODO: This is where device_type flattening would occur for the loop
    1070                 :             :      flags.  */
    1071                 :             : 
    1072                 :        8519 :   loop->flags = TREE_INT_CST_LOW (gimple_call_arg (marker, 3));
    1073                 :             : 
    1074                 :        8519 :   tree chunk_size = integer_zero_node;
    1075                 :        8519 :   if (loop->flags & OLF_GANG_STATIC)
    1076                 :         131 :     chunk_size = gimple_call_arg (marker, 4);
    1077                 :        8519 :   loop->chunk_size = chunk_size;
    1078                 :             : 
    1079                 :        8519 :   return loop;
    1080                 :             : }
    1081                 :             : 
    1082                 :             : /* Create a dummy loop encompassing a call to a openACC routine.
    1083                 :             :    Extract the routine's partitioning requirements.  */
    1084                 :             : 
    1085                 :             : static void
    1086                 :        1061 : new_oacc_loop_routine (oacc_loop *parent, gcall *call, tree decl, tree attrs)
    1087                 :             : {
    1088                 :        1061 :   oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (call));
    1089                 :        1061 :   int level = oacc_fn_attrib_level (attrs);
    1090                 :             : 
    1091                 :        1061 :   gcc_assert (level >= 0);
    1092                 :             : 
    1093                 :        1061 :   loop->marker = call;
    1094                 :        1061 :   loop->routine = decl;
    1095                 :        1061 :   loop->mask = ((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1)
    1096                 :        1061 :                 ^ (GOMP_DIM_MASK (level) - 1));
    1097                 :        1061 : }
    1098                 :             : 
    1099                 :             : /* Finish off the current OpenACC loop ending at tail marker TAIL.
    1100                 :             :    Return the parent loop.  */
    1101                 :             : 
    1102                 :             : static oacc_loop *
    1103                 :        8519 : finish_oacc_loop (oacc_loop *loop)
    1104                 :             : {
    1105                 :             :   /* If the loop has been collapsed, don't partition it.  */
    1106                 :           0 :   if (loop->ifns.is_empty ())
    1107                 :           0 :     loop->mask = loop->flags = 0;
    1108                 :        8519 :   return loop->parent;
    1109                 :             : }
    1110                 :             : 
    1111                 :             : /* Free all OpenACC loop structures within LOOP (inclusive).  */
    1112                 :             : 
    1113                 :             : static void
    1114                 :       19727 : free_oacc_loop (oacc_loop *loop)
    1115                 :             : {
    1116                 :       19727 :   if (loop->sibling)
    1117                 :        1839 :     free_oacc_loop (loop->sibling);
    1118                 :       19727 :   if (loop->child)
    1119                 :        7741 :     free_oacc_loop (loop->child);
    1120                 :             : 
    1121                 :       19727 :   loop->ifns.release ();
    1122                 :       19727 :   free (loop);
    1123                 :       19727 : }
    1124                 :             : 
    1125                 :             : /* Dump out the OpenACC loop head or tail beginning at FROM.  */
    1126                 :             : 
    1127                 :             : static void
    1128                 :         202 : dump_oacc_loop_part (FILE *file, gcall *from, int depth,
    1129                 :             :                      const char *title, int level)
    1130                 :             : {
    1131                 :         202 :   enum ifn_unique_kind kind
    1132                 :         202 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
    1133                 :             : 
    1134                 :         202 :   fprintf (file, "%*s%s-%d:\n", depth * 2, "", title, level);
    1135                 :         202 :   for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
    1136                 :             :     {
    1137                 :         611 :       gimple *stmt = gsi_stmt (gsi);
    1138                 :             : 
    1139                 :         611 :       if (gimple_call_internal_p (stmt, IFN_UNIQUE))
    1140                 :             :         {
    1141                 :         611 :           enum ifn_unique_kind k
    1142                 :         611 :             = ((enum ifn_unique_kind) TREE_INT_CST_LOW
    1143                 :         611 :                (gimple_call_arg (stmt, 0)));
    1144                 :             : 
    1145                 :         611 :           if (k == kind && stmt != from)
    1146                 :             :             break;
    1147                 :             :         }
    1148                 :         409 :       print_gimple_stmt (file, stmt, depth * 2 + 2);
    1149                 :             : 
    1150                 :         409 :       gsi_next (&gsi);
    1151                 :         818 :       while (gsi_end_p (gsi))
    1152                 :         818 :         gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
    1153                 :             :     }
    1154                 :         202 : }
    1155                 :             : 
    1156                 :             : /* Dump OpenACC loop LOOP, its children, and its siblings.  */
    1157                 :             : 
    1158                 :             : static void
    1159                 :         176 : dump_oacc_loop (FILE *file, oacc_loop *loop, int depth)
    1160                 :             : {
    1161                 :         208 :   int ix;
    1162                 :             : 
    1163                 :         208 :   fprintf (file, "%*sLoop %x(%x) %s:%u\n", depth * 2, "",
    1164                 :             :            loop->flags, loop->mask,
    1165                 :         208 :            LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc));
    1166                 :             : 
    1167                 :         208 :   if (loop->marker)
    1168                 :          95 :     print_gimple_stmt (file, loop->marker, depth * 2);
    1169                 :             : 
    1170                 :         208 :   if (loop->routine)
    1171                 :          44 :     fprintf (file, "%*sRoutine %s:%u:%s\n",
    1172                 :          44 :              depth * 2, "", DECL_SOURCE_FILE (loop->routine),
    1173                 :          88 :              DECL_SOURCE_LINE (loop->routine),
    1174                 :          44 :              IDENTIFIER_POINTER (DECL_NAME (loop->routine)));
    1175                 :             : 
    1176                 :         832 :   for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
    1177                 :         624 :     if (loop->heads[ix])
    1178                 :         101 :       dump_oacc_loop_part (file, loop->heads[ix], depth, "Head", ix);
    1179                 :         832 :   for (ix = GOMP_DIM_MAX; ix--;)
    1180                 :         624 :     if (loop->tails[ix])
    1181                 :         101 :       dump_oacc_loop_part (file, loop->tails[ix], depth, "Tail", ix);
    1182                 :             : 
    1183                 :         208 :   if (loop->child)
    1184                 :          63 :     dump_oacc_loop (file, loop->child, depth + 1);
    1185                 :         208 :   if (loop->sibling)
    1186                 :             :     dump_oacc_loop (file, loop->sibling, depth);
    1187                 :         176 : }
    1188                 :             : 
    1189                 :             : void debug_oacc_loop (oacc_loop *);
    1190                 :             : 
    1191                 :             : /* Dump loops to stderr.  */
    1192                 :             : 
    1193                 :             : DEBUG_FUNCTION void
    1194                 :           0 : debug_oacc_loop (oacc_loop *loop)
    1195                 :             : {
    1196                 :           0 :   dump_oacc_loop (stderr, loop, 0);
    1197                 :           0 : }
    1198                 :             : 
    1199                 :             : /* Provide diagnostics on OpenACC loop LOOP, its children, and its
    1200                 :             :    siblings.  */
    1201                 :             : 
    1202                 :             : static void
    1203                 :        2587 : inform_oacc_loop (const oacc_loop *loop)
    1204                 :             : {
    1205                 :        5174 :   const char *gang
    1206                 :        2587 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_GANG) ? " gang" : "";
    1207                 :        5174 :   const char *worker
    1208                 :        2587 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_WORKER) ? " worker" : "";
    1209                 :        5174 :   const char *vector
    1210                 :        2587 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR) ? " vector" : "";
    1211                 :        2587 :   const char *seq = loop->mask == 0 ? " seq" : "";
    1212                 :        2587 :   const dump_user_location_t loc
    1213                 :        2587 :     = dump_user_location_t::from_location_t (loop->loc);
    1214                 :        2587 :   dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
    1215                 :             :                    "assigned OpenACC%s%s%s%s loop parallelism\n", gang, worker,
    1216                 :             :                    vector, seq);
    1217                 :             : 
    1218                 :        2587 :   if (loop->child)
    1219                 :         622 :     inform_oacc_loop (loop->child);
    1220                 :        2587 :   if (loop->sibling)
    1221                 :         210 :     inform_oacc_loop (loop->sibling);
    1222                 :        2587 : }
    1223                 :             : 
    1224                 :             : /* DFS walk of basic blocks BB onwards, creating OpenACC loop
    1225                 :             :    structures as we go.  By construction these loops are properly
    1226                 :             :    nested.  */
    1227                 :             : 
    1228                 :             : static void
    1229                 :      162952 : oacc_loop_discover_walk (oacc_loop *loop, basic_block bb)
    1230                 :             : {
    1231                 :      162952 :   int marker = 0;
    1232                 :      162952 :   int remaining = 0;
    1233                 :             : 
    1234                 :      162952 :   if (bb->flags & BB_VISITED)
    1235                 :       37117 :     return;
    1236                 :             : 
    1237                 :      125835 :  follow:
    1238                 :      183915 :   bb->flags |= BB_VISITED;
    1239                 :             : 
    1240                 :             :   /* Scan for loop markers.  */
    1241                 :      724892 :   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
    1242                 :      357062 :        gsi_next (&gsi))
    1243                 :             :     {
    1244                 :      357062 :       gimple *stmt = gsi_stmt (gsi);
    1245                 :             : 
    1246                 :      357062 :       if (!is_gimple_call (stmt))
    1247                 :      212418 :         continue;
    1248                 :             : 
    1249                 :      148989 :       gcall *call = as_a <gcall *> (stmt);
    1250                 :             : 
    1251                 :             :       /* If this is a routine, make a dummy loop for it.  */
    1252                 :      148989 :       if (tree decl = gimple_call_fndecl (call))
    1253                 :        4344 :         if (tree attrs = oacc_get_fn_attrib (decl))
    1254                 :             :           {
    1255                 :        1061 :             gcc_assert (!marker);
    1256                 :        1061 :             new_oacc_loop_routine (loop, call, decl, attrs);
    1257                 :             :           }
    1258                 :             : 
    1259                 :      148989 :       if (!gimple_call_internal_p (call))
    1260                 :        4345 :         continue;
    1261                 :             : 
    1262                 :      144644 :       switch (gimple_call_internal_fn (call))
    1263                 :             :         {
    1264                 :             :         default:
    1265                 :             :           break;
    1266                 :             : 
    1267                 :       43492 :         case IFN_GOACC_LOOP:
    1268                 :       43492 :         case IFN_GOACC_TILE:
    1269                 :             :           /* Record the abstraction function, so we can manipulate it
    1270                 :             :              later.  */
    1271                 :       43492 :           loop->ifns.safe_push (call);
    1272                 :       43492 :           break;
    1273                 :             : 
    1274                 :       75138 :         case IFN_UNIQUE:
    1275                 :       75138 :           enum ifn_unique_kind kind
    1276                 :       75138 :             = (enum ifn_unique_kind) (TREE_INT_CST_LOW
    1277                 :       75138 :                                       (gimple_call_arg (call, 0)));
    1278                 :       75138 :           if (kind == IFN_UNIQUE_OACC_HEAD_MARK
    1279                 :       75138 :               || kind == IFN_UNIQUE_OACC_TAIL_MARK)
    1280                 :             :             {
    1281                 :       45964 :               if (gimple_call_num_args (call) == 2)
    1282                 :             :                 {
    1283                 :       17038 :                   gcc_assert (marker && !remaining);
    1284                 :       17038 :                   marker = 0;
    1285                 :       17038 :                   if (kind == IFN_UNIQUE_OACC_TAIL_MARK)
    1286                 :       17038 :                     loop = finish_oacc_loop (loop);
    1287                 :             :                   else
    1288                 :        8519 :                     loop->head_end = call;
    1289                 :             :                 }
    1290                 :             :               else
    1291                 :             :                 {
    1292                 :       28926 :                   int count = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
    1293                 :             : 
    1294                 :       28926 :                   if (!marker)
    1295                 :             :                     {
    1296                 :       17038 :                       if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
    1297                 :        8519 :                         loop = new_oacc_loop (loop, call);
    1298                 :             :                       remaining = count;
    1299                 :             :                     }
    1300                 :       28926 :                   gcc_assert (count == remaining);
    1301                 :       28926 :                   if (remaining)
    1302                 :             :                     {
    1303                 :       28926 :                       remaining--;
    1304                 :       28926 :                       if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
    1305                 :       14463 :                         loop->heads[marker] = call;
    1306                 :             :                       else
    1307                 :       14463 :                         loop->tails[remaining] = call;
    1308                 :             :                     }
    1309                 :       28926 :                   marker++;
    1310                 :             :                 }
    1311                 :             :             }
    1312                 :             :         }
    1313                 :             :     }
    1314                 :      183915 :   if (remaining || marker)
    1315                 :             :     {
    1316                 :       58080 :       bb = single_succ (bb);
    1317                 :      116160 :       gcc_assert (single_pred_p (bb) && !(bb->flags & BB_VISITED));
    1318                 :       58080 :       goto follow;
    1319                 :             :     }
    1320                 :             : 
    1321                 :             :   /* Walk successor blocks.  */
    1322                 :      125835 :   edge e;
    1323                 :      125835 :   edge_iterator ei;
    1324                 :             : 
    1325                 :      279334 :   FOR_EACH_EDGE (e, ei, bb->succs)
    1326                 :      153499 :     oacc_loop_discover_walk (loop, e->dest);
    1327                 :             : }
    1328                 :             : 
    1329                 :             : /* LOOP is the first sibling.  Reverse the order in place and return
    1330                 :             :    the new first sibling.  Recurse to child loops.  */
    1331                 :             : 
    1332                 :             : static oacc_loop *
    1333                 :       17194 : oacc_loop_sibling_nreverse (oacc_loop *loop)
    1334                 :             : {
    1335                 :       17194 :   oacc_loop *last = NULL;
    1336                 :       19033 :   do
    1337                 :             :     {
    1338                 :       19033 :       if (loop->child)
    1339                 :        7741 :         loop->child = oacc_loop_sibling_nreverse (loop->child);
    1340                 :             : 
    1341                 :       19033 :       oacc_loop *next = loop->sibling;
    1342                 :       19033 :       loop->sibling = last;
    1343                 :       19033 :       last = loop;
    1344                 :       19033 :       loop = next;
    1345                 :             :     }
    1346                 :       19033 :   while (loop);
    1347                 :             : 
    1348                 :       17194 :   return last;
    1349                 :             : }
    1350                 :             : 
    1351                 :             : /* Discover the OpenACC loops marked up by HEAD and TAIL markers for
    1352                 :             :    the current function.  */
    1353                 :             : 
    1354                 :             : static oacc_loop *
    1355                 :        9453 : oacc_loop_discovery ()
    1356                 :             : {
    1357                 :             :   /* Clear basic block flags, in particular BB_VISITED which we're going to use
    1358                 :             :      in the following.  */
    1359                 :        9453 :   clear_bb_flags ();
    1360                 :             : 
    1361                 :        9453 :   oacc_loop *top = new_oacc_loop_outer (current_function_decl);
    1362                 :        9453 :   oacc_loop_discover_walk (top, ENTRY_BLOCK_PTR_FOR_FN (cfun));
    1363                 :             : 
    1364                 :             :   /* The siblings were constructed in reverse order, reverse them so
    1365                 :             :      that diagnostics come out in an unsurprising order.  */
    1366                 :        9453 :   top = oacc_loop_sibling_nreverse (top);
    1367                 :             : 
    1368                 :        9453 :   return top;
    1369                 :             : }
    1370                 :             : 
    1371                 :             : /* Transform the abstract internal function markers starting at FROM
    1372                 :             :    to be for partitioning level LEVEL.  Stop when we meet another HEAD
    1373                 :             :    or TAIL  marker.  */
    1374                 :             : 
    1375                 :             : static void
    1376                 :       23332 : oacc_loop_xform_head_tail (gcall *from, int level)
    1377                 :             : {
    1378                 :       23332 :   enum ifn_unique_kind kind
    1379                 :       23332 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
    1380                 :       23332 :   tree replacement = build_int_cst (unsigned_type_node, level);
    1381                 :             : 
    1382                 :       23332 :   for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
    1383                 :             :     {
    1384                 :       99471 :       gimple *stmt = gsi_stmt (gsi);
    1385                 :             : 
    1386                 :       99471 :       if (gimple_call_internal_p (stmt, IFN_UNIQUE))
    1387                 :             :         {
    1388                 :       70219 :           enum ifn_unique_kind k
    1389                 :             :             = ((enum ifn_unique_kind)
    1390                 :       70219 :                TREE_INT_CST_LOW (gimple_call_arg (stmt, 0)));
    1391                 :             : 
    1392                 :       70219 :           if (k == IFN_UNIQUE_OACC_FORK
    1393                 :       70219 :               || k == IFN_UNIQUE_OACC_JOIN
    1394                 :       70219 :               || k == IFN_UNIQUE_OACC_PRIVATE)
    1395                 :       23555 :             *gimple_call_arg_ptr (stmt, 2) = replacement;
    1396                 :       46664 :           else if (k == kind && stmt != from)
    1397                 :             :             break;
    1398                 :             :         }
    1399                 :       29252 :       else if (gimple_call_internal_p (stmt, IFN_GOACC_REDUCTION))
    1400                 :       17424 :         *gimple_call_arg_ptr (stmt, 3) = replacement;
    1401                 :       76139 :       update_stmt (stmt);
    1402                 :             : 
    1403                 :       76139 :       gsi_next (&gsi);
    1404                 :      123026 :       while (gsi_end_p (gsi))
    1405                 :       93774 :         gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
    1406                 :             :     }
    1407                 :       23332 : }
    1408                 :             : 
    1409                 :             : /* Process the discovered OpenACC loops, setting the correct
    1410                 :             :    partitioning level etc.  */
    1411                 :             : 
    1412                 :             : static void
    1413                 :       19033 : oacc_loop_process (oacc_loop *loop, int fn_level)
    1414                 :             : {
    1415                 :       19033 :   if (loop->child)
    1416                 :        7741 :     oacc_loop_process (loop->child, fn_level);
    1417                 :             : 
    1418                 :       19033 :   if (loop->mask && !loop->routine)
    1419                 :             :     {
    1420                 :        7748 :       int ix;
    1421                 :        7748 :       tree mask_arg = build_int_cst (unsigned_type_node, loop->mask);
    1422                 :        7748 :       tree e_mask_arg = build_int_cst (unsigned_type_node, loop->e_mask);
    1423                 :        7748 :       tree chunk_arg = loop->chunk_size;
    1424                 :        7748 :       gcall *call;
    1425                 :             :       
    1426                 :       39252 :       for (ix = 0; loop->ifns.iterate (ix, &call); ix++)
    1427                 :             :         {
    1428                 :       31504 :           switch (gimple_call_internal_fn (call))
    1429                 :             :             {
    1430                 :       31293 :             case IFN_GOACC_LOOP:
    1431                 :       31293 :               {
    1432                 :       31293 :                 bool is_e = gimple_call_arg (call, 5) == integer_minus_one_node;
    1433                 :       62183 :                 gimple_call_set_arg (call, 5, is_e ? e_mask_arg : mask_arg);
    1434                 :       31293 :                 if (!is_e)
    1435                 :       30890 :                   gimple_call_set_arg (call, 4, chunk_arg);
    1436                 :             :               }
    1437                 :             :               break;
    1438                 :             : 
    1439                 :         211 :             case IFN_GOACC_TILE:
    1440                 :         211 :               gimple_call_set_arg (call, 3, mask_arg);
    1441                 :         211 :               gimple_call_set_arg (call, 4, e_mask_arg);
    1442                 :         211 :               break;
    1443                 :             : 
    1444                 :           0 :             default:
    1445                 :           0 :               gcc_unreachable ();
    1446                 :             :             }
    1447                 :       31504 :           update_stmt (call);
    1448                 :             :         }
    1449                 :             : 
    1450                 :        7748 :       unsigned dim = GOMP_DIM_GANG;
    1451                 :        7748 :       unsigned mask = loop->mask | loop->e_mask;
    1452                 :       19414 :       for (ix = 0; ix != GOMP_DIM_MAX && mask; ix++)
    1453                 :             :         {
    1454                 :       22710 :           while (!(GOMP_DIM_MASK (dim) & mask))
    1455                 :       11044 :             dim++;
    1456                 :             : 
    1457                 :       11666 :           oacc_loop_xform_head_tail (loop->heads[ix], dim);
    1458                 :       11666 :           oacc_loop_xform_head_tail (loop->tails[ix], dim);
    1459                 :             : 
    1460                 :       11666 :           mask ^= GOMP_DIM_MASK (dim);
    1461                 :             :         }
    1462                 :             :     }
    1463                 :             : 
    1464                 :       19033 :   if (loop->sibling)
    1465                 :        1839 :     oacc_loop_process (loop->sibling, fn_level);
    1466                 :             : 
    1467                 :             : 
    1468                 :             :   /* OpenACC 2.6, 2.9.11. "reduction clause" places a restriction such that
    1469                 :             :      "The 'reduction' clause may not be specified on an orphaned 'loop'
    1470                 :             :      construct with the 'gang' clause, or on an orphaned 'loop' construct that
    1471                 :             :      will generate gang parallelism in a procedure that is compiled with the
    1472                 :             :      'routine gang' clause."  */
    1473                 :       19033 :   if (fn_level == GOMP_DIM_GANG
    1474                 :         733 :       && (loop->mask & GOMP_DIM_MASK (GOMP_DIM_GANG))
    1475                 :         241 :       && (loop->flags & OLF_REDUCTION))
    1476                 :         126 :     error_at (loop->loc,
    1477                 :             :               "gang reduction on an orphan loop");
    1478                 :       19033 : }
    1479                 :             : 
    1480                 :             : /* Walk the OpenACC loop heirarchy checking and assigning the
    1481                 :             :    programmer-specified partitionings.  OUTER_MASK is the partitioning
    1482                 :             :    this loop is contained within.  Return mask of partitioning
    1483                 :             :    encountered.  If any auto loops are discovered, set GOMP_DIM_MAX
    1484                 :             :    bit.  */
    1485                 :             : 
    1486                 :             : static unsigned
    1487                 :       19033 : oacc_loop_fixed_partitions (oacc_loop *loop, unsigned outer_mask)
    1488                 :             : {
    1489                 :       19033 :   unsigned this_mask = loop->mask;
    1490                 :       19033 :   unsigned mask_all = 0;
    1491                 :       19033 :   bool noisy = true;
    1492                 :             : 
    1493                 :             : #ifdef ACCEL_COMPILER
    1494                 :             :   /* When device_type is supported, we want the device compiler to be
    1495                 :             :      noisy, if the loop parameters are device_type-specific.  */
    1496                 :             :   noisy = false;
    1497                 :             : #endif
    1498                 :             : 
    1499                 :       19033 :   if (!loop->routine)
    1500                 :             :     {
    1501                 :       17972 :       bool auto_par = (loop->flags & OLF_AUTO) != 0;
    1502                 :       17972 :       bool seq_par = (loop->flags & OLF_SEQ) != 0;
    1503                 :       17972 :       bool tiling = (loop->flags & OLF_TILE) != 0;
    1504                 :             :       
    1505                 :       17972 :       this_mask = ((loop->flags >> OLF_DIM_BASE)
    1506                 :             :                    & (GOMP_DIM_MASK (GOMP_DIM_MAX) - 1));
    1507                 :             : 
    1508                 :             :       /* Apply auto partitioning if this is a non-partitioned regular
    1509                 :             :          loop, or (no more than) single axis tiled loop.  */
    1510                 :       35944 :       bool maybe_auto
    1511                 :       17972 :         = !seq_par && this_mask == (tiling ? this_mask & -this_mask : 0);
    1512                 :             : 
    1513                 :       17972 :       if ((this_mask != 0) + auto_par + seq_par > 1)
    1514                 :             :         {
    1515                 :         102 :           if (noisy)
    1516                 :         150 :             error_at (loop->loc,
    1517                 :             :                       seq_par
    1518                 :             :                       ? G_("%<seq%> overrides other OpenACC loop specifiers")
    1519                 :             :                       : G_("%<auto%> conflicts with other OpenACC loop "
    1520                 :             :                            "specifiers"));
    1521                 :         102 :           maybe_auto = false;
    1522                 :         102 :           loop->flags &= ~OLF_AUTO;
    1523                 :         102 :           if (seq_par)
    1524                 :             :             {
    1525                 :          54 :               loop->flags
    1526                 :          54 :                 &= ~((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1) << OLF_DIM_BASE);
    1527                 :          54 :               this_mask = 0;
    1528                 :             :             }
    1529                 :             :         }
    1530                 :             : 
    1531                 :       17924 :       if (maybe_auto && (loop->flags & OLF_INDEPENDENT))
    1532                 :             :         {
    1533                 :        4747 :           loop->flags |= OLF_AUTO;
    1534                 :        4747 :           mask_all |= GOMP_DIM_MASK (GOMP_DIM_MAX);
    1535                 :             :         }
    1536                 :             :     }
    1537                 :             : 
    1538                 :       19033 :   if (this_mask & outer_mask)
    1539                 :             :     {
    1540                 :         244 :       const oacc_loop *outer;
    1541                 :         370 :       for (outer = loop->parent; outer; outer = outer->parent)
    1542                 :         244 :         if ((outer->mask | outer->e_mask) & this_mask)
    1543                 :             :           break;
    1544                 :             : 
    1545                 :         244 :       if (noisy)
    1546                 :             :         {
    1547                 :         244 :           if (outer)
    1548                 :             :             {
    1549                 :         118 :               error_at (loop->loc,
    1550                 :         118 :                         loop->routine
    1551                 :             :                         ? G_("routine call uses same OpenACC parallelism"
    1552                 :             :                              " as containing loop")
    1553                 :             :                         : G_("inner loop uses same OpenACC parallelism"
    1554                 :             :                              " as containing loop"));
    1555                 :         118 :               inform (outer->loc, "containing loop here");
    1556                 :             :             }
    1557                 :             :           else
    1558                 :         126 :             error_at (loop->loc,
    1559                 :         126 :                       loop->routine
    1560                 :             :                       ? G_("routine call uses OpenACC parallelism disallowed"
    1561                 :             :                            " by containing routine")
    1562                 :             :                       : G_("loop uses OpenACC parallelism disallowed"
    1563                 :             :                            " by containing routine"));
    1564                 :             : 
    1565                 :         244 :           if (loop->routine)
    1566                 :         152 :             inform (DECL_SOURCE_LOCATION (loop->routine),
    1567                 :             :                     "routine %qD declared here", loop->routine);
    1568                 :             :         }
    1569                 :         244 :       this_mask &= ~outer_mask;
    1570                 :             :     }
    1571                 :             :   else
    1572                 :             :     {
    1573                 :       18789 :       unsigned outermost = least_bit_hwi (this_mask);
    1574                 :             : 
    1575                 :       18789 :       if (outermost && outermost <= outer_mask)
    1576                 :             :         {
    1577                 :          26 :           if (noisy)
    1578                 :             :             {
    1579                 :          26 :               error_at (loop->loc,
    1580                 :             :                         "incorrectly nested OpenACC loop parallelism");
    1581                 :             : 
    1582                 :          26 :               const oacc_loop *outer;
    1583                 :          26 :               for (outer = loop->parent;
    1584                 :          26 :                    outer->flags && outer->flags < outermost;
    1585                 :           0 :                    outer = outer->parent)
    1586                 :           0 :                 continue;
    1587                 :          26 :               inform (outer->loc, "containing loop here");
    1588                 :           0 :             }
    1589                 :             : 
    1590                 :          26 :           this_mask &= ~outermost;
    1591                 :             :         }
    1592                 :             :     }
    1593                 :             : 
    1594                 :       19033 :   mask_all |= this_mask;
    1595                 :             : 
    1596                 :       19033 :   if (loop->flags & OLF_TILE)
    1597                 :             :     {
    1598                 :             :       /* When tiling, vector goes to the element loop, and failing
    1599                 :             :          that we put worker there.  The std doesn't contemplate
    1600                 :             :          specifying all three.  We choose to put worker and vector on
    1601                 :             :          the element loops in that case.  */
    1602                 :         146 :       unsigned this_e_mask = this_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR);
    1603                 :         146 :       if (!this_e_mask || this_mask & GOMP_DIM_MASK (GOMP_DIM_GANG))
    1604                 :         127 :         this_e_mask |= this_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER);
    1605                 :             : 
    1606                 :         146 :       loop->e_mask = this_e_mask;
    1607                 :         146 :       this_mask ^= this_e_mask;
    1608                 :             :     }
    1609                 :             : 
    1610                 :       19033 :   loop->mask = this_mask;
    1611                 :             : 
    1612                 :       19033 :   if (dump_file)
    1613                 :         208 :     fprintf (dump_file, "Loop %s:%d user specified %d & %d\n",
    1614                 :         416 :              LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
    1615                 :             :              loop->mask, loop->e_mask);
    1616                 :             : 
    1617                 :       19033 :   if (loop->child)
    1618                 :             :     {
    1619                 :        7741 :       unsigned tmp_mask = outer_mask | this_mask | loop->e_mask;
    1620                 :        7741 :       loop->inner = oacc_loop_fixed_partitions (loop->child, tmp_mask);
    1621                 :        7741 :       mask_all |= loop->inner;
    1622                 :             :     }
    1623                 :             : 
    1624                 :       19033 :   if (loop->sibling)
    1625                 :        1839 :     mask_all |= oacc_loop_fixed_partitions (loop->sibling, outer_mask);
    1626                 :             : 
    1627                 :       19033 :   return mask_all;
    1628                 :             : }
    1629                 :             : 
    1630                 :             : /* Walk the OpenACC loop heirarchy to assign auto-partitioned loops.
    1631                 :             :    OUTER_MASK is the partitioning this loop is contained within.
    1632                 :             :    OUTER_ASSIGN is true if an outer loop is being auto-partitioned.
    1633                 :             :    Return the cumulative partitioning used by this loop, siblings and
    1634                 :             :    children.  */
    1635                 :             : 
    1636                 :             : static unsigned
    1637                 :        8907 : oacc_loop_auto_partitions (oacc_loop *loop, unsigned outer_mask,
    1638                 :             :                            bool outer_assign)
    1639                 :             : {
    1640                 :        8907 :   bool assign = (loop->flags & OLF_AUTO) && (loop->flags & OLF_INDEPENDENT);
    1641                 :        8907 :   bool noisy = true;
    1642                 :        8907 :   bool tiling = loop->flags & OLF_TILE;
    1643                 :             : 
    1644                 :             : #ifdef ACCEL_COMPILER
    1645                 :             :   /* When device_type is supported, we want the device compiler to be
    1646                 :             :      noisy, if the loop parameters are device_type-specific.  */
    1647                 :             :   noisy = false;
    1648                 :             : #endif
    1649                 :             : 
    1650                 :        8907 :   if (assign && (!outer_assign || loop->inner))
    1651                 :             :     {
    1652                 :             :       /* Allocate outermost and non-innermost loops at the outermost
    1653                 :             :          non-innermost available level.  */
    1654                 :             :       unsigned this_mask = GOMP_DIM_MASK (GOMP_DIM_GANG);
    1655                 :             : 
    1656                 :             :       /* Find the first outermost available partition. */
    1657                 :        5524 :       while (this_mask <= outer_mask)
    1658                 :        1488 :         this_mask <<= 1;
    1659                 :             :       
    1660                 :             :       /* Grab two axes if tiling, and we've not assigned anything  */
    1661                 :        4036 :       if (tiling && !(loop->mask | loop->e_mask))
    1662                 :          96 :         this_mask |= this_mask << 1;
    1663                 :             : 
    1664                 :             :       /* Prohibit the innermost partitioning at the moment.  */
    1665                 :        4036 :       this_mask &= GOMP_DIM_MASK (GOMP_DIM_MAX - 1) - 1;
    1666                 :             : 
    1667                 :             :       /* Don't use any dimension explicitly claimed by an inner loop. */
    1668                 :        4036 :       this_mask &= ~loop->inner;
    1669                 :             : 
    1670                 :        4036 :       if (tiling && !loop->e_mask)
    1671                 :             :         {
    1672                 :             :           /* If we got two axes, allocate the inner one to the element
    1673                 :             :              loop.  */
    1674                 :         101 :           loop->e_mask = this_mask & (this_mask << 1);
    1675                 :         101 :           this_mask ^= loop->e_mask;
    1676                 :             :         }
    1677                 :             : 
    1678                 :        4036 :       loop->mask |= this_mask;
    1679                 :             :     }
    1680                 :             : 
    1681                 :        8907 :   if (loop->child)
    1682                 :             :     {
    1683                 :        4643 :       unsigned tmp_mask = outer_mask | loop->mask | loop->e_mask;
    1684                 :        4643 :       loop->inner = oacc_loop_auto_partitions (loop->child, tmp_mask,
    1685                 :        4643 :                                                outer_assign | assign);
    1686                 :             :     }
    1687                 :             : 
    1688                 :        8907 :   if (assign && (!loop->mask || (tiling && !loop->e_mask) || !outer_assign))
    1689                 :             :     {
    1690                 :             :       /* Allocate the loop at the innermost available level.  Note
    1691                 :             :          that we do this even if we already assigned this loop the
    1692                 :             :          outermost available level above.  That way we'll partition
    1693                 :             :          this along 2 axes, if they are available.  */
    1694                 :        4292 :       unsigned this_mask = 0;
    1695                 :             : 
    1696                 :             :       /* Determine the outermost partitioning used within this loop.  */
    1697                 :        4292 :       this_mask = loop->inner | GOMP_DIM_MASK (GOMP_DIM_MAX);
    1698                 :        4292 :       this_mask = least_bit_hwi (this_mask);
    1699                 :             : 
    1700                 :             :       /* Pick the partitioning just inside that one.  */
    1701                 :        4292 :       this_mask >>= 1;
    1702                 :             : 
    1703                 :             :       /* And avoid picking one use by an outer loop.  */
    1704                 :        4292 :       this_mask &= ~outer_mask;
    1705                 :             : 
    1706                 :             :       /* If tiling and we failed completely above, grab the next one
    1707                 :             :          too.  Making sure it doesn't hit an outer loop.  */
    1708                 :        4292 :       if (tiling)
    1709                 :             :         {
    1710                 :         116 :           this_mask &= ~(loop->e_mask | loop->mask);
    1711                 :         116 :           unsigned tile_mask = ((this_mask >> 1)
    1712                 :         116 :                                 & ~(outer_mask | loop->e_mask | loop->mask));
    1713                 :             : 
    1714                 :         116 :           if (tile_mask || loop->mask)
    1715                 :             :             {
    1716                 :         106 :               loop->e_mask |= this_mask;
    1717                 :         106 :               this_mask = tile_mask;
    1718                 :             :             }
    1719                 :         116 :           if (!loop->e_mask && noisy)
    1720                 :          10 :             warning_at (loop->loc, 0,
    1721                 :             :                         "insufficient partitioning available"
    1722                 :             :                         " to parallelize element loop");
    1723                 :             :         }
    1724                 :             : 
    1725                 :        4292 :       loop->mask |= this_mask;
    1726                 :        4292 :       if (!loop->mask && noisy)
    1727                 :         773 :         warning_at (loop->loc, 0,
    1728                 :             :                     tiling
    1729                 :             :                     ? G_("insufficient partitioning available"
    1730                 :             :                          " to parallelize tile loop")
    1731                 :             :                     : G_("insufficient partitioning available"
    1732                 :             :                          " to parallelize loop"));
    1733                 :             :     }
    1734                 :             : 
    1735                 :        4747 :   if (assign && dump_file)
    1736                 :          38 :     fprintf (dump_file, "Auto loop %s:%d assigned %d & %d\n",
    1737                 :          76 :              LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
    1738                 :             :              loop->mask, loop->e_mask);
    1739                 :             : 
    1740                 :        8907 :   unsigned inner_mask = 0;
    1741                 :             : 
    1742                 :        8907 :   if (loop->sibling)
    1743                 :        1421 :     inner_mask |= oacc_loop_auto_partitions (loop->sibling,
    1744                 :             :                                              outer_mask, outer_assign);
    1745                 :             : 
    1746                 :        8907 :   inner_mask |= loop->inner | loop->mask | loop->e_mask;
    1747                 :             : 
    1748                 :        8907 :   return inner_mask;
    1749                 :             : }
    1750                 :             : 
    1751                 :             : /* Walk the OpenACC loop heirarchy to check and assign partitioning
    1752                 :             :    axes.  Return mask of partitioning.  */
    1753                 :             : 
    1754                 :             : static unsigned
    1755                 :        9453 : oacc_loop_partition (oacc_loop *loop, unsigned outer_mask)
    1756                 :             : {
    1757                 :        9453 :   unsigned mask_all = oacc_loop_fixed_partitions (loop, outer_mask);
    1758                 :             : 
    1759                 :        9453 :   if (mask_all & GOMP_DIM_MASK (GOMP_DIM_MAX))
    1760                 :             :     {
    1761                 :        2843 :       mask_all ^= GOMP_DIM_MASK (GOMP_DIM_MAX);
    1762                 :        2843 :       mask_all |= oacc_loop_auto_partitions (loop, outer_mask, false);
    1763                 :             :     }
    1764                 :        9453 :   return mask_all;
    1765                 :             : }
    1766                 :             : 
    1767                 :             : /* Default fork/join early expander.  Delete the function calls if
    1768                 :             :    there is no RTL expander.  */
    1769                 :             : 
    1770                 :             : bool
    1771                 :       23332 : default_goacc_fork_join (gcall *ARG_UNUSED (call),
    1772                 :             :                          const int *ARG_UNUSED (dims), bool is_fork)
    1773                 :             : {
    1774                 :       23332 :   if (is_fork)
    1775                 :       11666 :     return targetm.have_oacc_fork ();
    1776                 :             :   else
    1777                 :       11666 :     return targetm.have_oacc_join ();
    1778                 :             : }
    1779                 :             : 
    1780                 :             : /* Default goacc.reduction early expander.
    1781                 :             : 
    1782                 :             :    LHS-opt = IFN_REDUCTION (KIND, RES_PTR, VAR, LEVEL, OP, OFFSET)
    1783                 :             :    If RES_PTR is not integer-zerop:
    1784                 :             :        SETUP - emit 'LHS = *RES_PTR', LHS = NULL
    1785                 :             :        TEARDOWN - emit '*RES_PTR = VAR'
    1786                 :             :    If LHS is not NULL
    1787                 :             :        emit 'LHS = VAR'   */
    1788                 :             : 
    1789                 :             : void
    1790                 :       25376 : default_goacc_reduction (gcall *call)
    1791                 :             : {
    1792                 :       25376 :   unsigned code = (unsigned)TREE_INT_CST_LOW (gimple_call_arg (call, 0));
    1793                 :       25376 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
    1794                 :       25376 :   tree lhs = gimple_call_lhs (call);
    1795                 :       25376 :   tree var = gimple_call_arg (call, 2);
    1796                 :       25376 :   gimple_seq seq = NULL;
    1797                 :             : 
    1798                 :       25376 :   if (code == IFN_GOACC_REDUCTION_SETUP
    1799                 :       25376 :       || code == IFN_GOACC_REDUCTION_TEARDOWN)
    1800                 :             :     {
    1801                 :             :       /* Setup and Teardown need to copy from/to the receiver object,
    1802                 :             :          if there is one.  */
    1803                 :       12688 :       tree ref_to_res = gimple_call_arg (call, 1);
    1804                 :             : 
    1805                 :       12688 :       if (!integer_zerop (ref_to_res))
    1806                 :             :         {
    1807                 :        4802 :           tree dst = build_simple_mem_ref (ref_to_res);
    1808                 :        4802 :           tree src = var;
    1809                 :             : 
    1810                 :        4802 :           if (code == IFN_GOACC_REDUCTION_SETUP)
    1811                 :             :             {
    1812                 :        2401 :               src = dst;
    1813                 :        2401 :               dst = lhs;
    1814                 :        2401 :               lhs = NULL;
    1815                 :             :             }
    1816                 :        4802 :           gimple_seq_add_stmt (&seq, gimple_build_assign (dst, src));
    1817                 :             :         }
    1818                 :             :     }
    1819                 :             : 
    1820                 :             :   /* Copy VAR to LHS, if there is an LHS.  */
    1821                 :       25376 :   if (lhs)
    1822                 :       21433 :     gimple_seq_add_stmt (&seq, gimple_build_assign (lhs, var));
    1823                 :             : 
    1824                 :       25376 :   gsi_replace_with_seq (&gsi, seq, true);
    1825                 :       25376 : }
    1826                 :             : 
    1827                 :             : struct var_decl_rewrite_info
    1828                 :             : {
    1829                 :             :   gimple *stmt;
    1830                 :             :   hash_map<tree, tree> *adjusted_vars;
    1831                 :             :   bool avoid_pointer_conversion;
    1832                 :             :   bool modified;
    1833                 :             : };
    1834                 :             : 
    1835                 :             : /* Helper function for execute_oacc_device_lower.  Rewrite VAR_DECLs (by
    1836                 :             :    themselves or wrapped in various other nodes) according to ADJUSTED_VARS in
    1837                 :             :    the var_decl_rewrite_info pointed to via DATA.  Used as part of coercing
    1838                 :             :    gang-private variables in OpenACC offload regions to reside in GPU shared
    1839                 :             :    memory.  */
    1840                 :             : 
    1841                 :             : static tree
    1842                 :           0 : oacc_rewrite_var_decl (tree *tp, int *walk_subtrees, void *data)
    1843                 :             : {
    1844                 :           0 :   walk_stmt_info *wi = (walk_stmt_info *) data;
    1845                 :           0 :   var_decl_rewrite_info *info = (var_decl_rewrite_info *) wi->info;
    1846                 :             : 
    1847                 :           0 :   if (TREE_CODE (*tp) == ADDR_EXPR)
    1848                 :             :     {
    1849                 :           0 :       tree arg = TREE_OPERAND (*tp, 0);
    1850                 :           0 :       tree *new_arg = info->adjusted_vars->get (arg);
    1851                 :             : 
    1852                 :           0 :       if (new_arg)
    1853                 :             :         {
    1854                 :           0 :           if (info->avoid_pointer_conversion)
    1855                 :             :             {
    1856                 :           0 :               *tp = build_fold_addr_expr (*new_arg);
    1857                 :           0 :               info->modified = true;
    1858                 :           0 :               *walk_subtrees = 0;
    1859                 :             :             }
    1860                 :             :           else
    1861                 :             :             {
    1862                 :           0 :               gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
    1863                 :           0 :               tree repl = build_fold_addr_expr (*new_arg);
    1864                 :           0 :               gimple *stmt1
    1865                 :           0 :                 = gimple_build_assign (make_ssa_name (TREE_TYPE (repl)), repl);
    1866                 :           0 :               tree conv = convert_to_pointer (TREE_TYPE (*tp),
    1867                 :             :                                               gimple_assign_lhs (stmt1));
    1868                 :           0 :               gimple *stmt2
    1869                 :           0 :                 = gimple_build_assign (make_ssa_name (TREE_TYPE (*tp)), conv);
    1870                 :           0 :               gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
    1871                 :           0 :               gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
    1872                 :           0 :               *tp = gimple_assign_lhs (stmt2);
    1873                 :           0 :               info->modified = true;
    1874                 :           0 :               *walk_subtrees = 0;
    1875                 :             :             }
    1876                 :             :         }
    1877                 :             :     }
    1878                 :           0 :   else if (TREE_CODE (*tp) == COMPONENT_REF || TREE_CODE (*tp) == ARRAY_REF)
    1879                 :             :     {
    1880                 :           0 :       tree *base = &TREE_OPERAND (*tp, 0);
    1881                 :             : 
    1882                 :           0 :       while (TREE_CODE (*base) == COMPONENT_REF
    1883                 :           0 :              || TREE_CODE (*base) == ARRAY_REF)
    1884                 :           0 :         base = &TREE_OPERAND (*base, 0);
    1885                 :             : 
    1886                 :           0 :       if (TREE_CODE (*base) != VAR_DECL)
    1887                 :             :         return NULL;
    1888                 :             : 
    1889                 :           0 :       tree *new_decl = info->adjusted_vars->get (*base);
    1890                 :           0 :       if (!new_decl)
    1891                 :             :         return NULL;
    1892                 :             : 
    1893                 :           0 :       int base_quals = TYPE_QUALS (TREE_TYPE (*new_decl));
    1894                 :           0 :       tree field = TREE_OPERAND (*tp, 1);
    1895                 :             : 
    1896                 :             :       /* Adjust the type of the field.  */
    1897                 :           0 :       int field_quals = TYPE_QUALS (TREE_TYPE (field));
    1898                 :           0 :       if (TREE_CODE (field) == FIELD_DECL && field_quals != base_quals)
    1899                 :             :         {
    1900                 :           0 :           tree *field_type = &TREE_TYPE (field);
    1901                 :           0 :           while (TREE_CODE (*field_type) == ARRAY_TYPE)
    1902                 :           0 :             field_type = &TREE_TYPE (*field_type);
    1903                 :           0 :           field_quals |= base_quals;
    1904                 :           0 :           *field_type = build_qualified_type (*field_type, field_quals);
    1905                 :             :         }
    1906                 :             : 
    1907                 :             :       /* Adjust the type of the component ref itself.  */
    1908                 :           0 :       tree comp_type = TREE_TYPE (*tp);
    1909                 :           0 :       int comp_quals = TYPE_QUALS (comp_type);
    1910                 :           0 :       if (TREE_CODE (*tp) == COMPONENT_REF && comp_quals != base_quals)
    1911                 :             :         {
    1912                 :           0 :           comp_quals |= base_quals;
    1913                 :           0 :           TREE_TYPE (*tp)
    1914                 :           0 :             = build_qualified_type (comp_type, comp_quals);
    1915                 :             :         }
    1916                 :             : 
    1917                 :           0 :       *base = *new_decl;
    1918                 :           0 :       info->modified = true;
    1919                 :           0 :     }
    1920                 :           0 :   else if (VAR_P (*tp))
    1921                 :             :     {
    1922                 :           0 :       tree *new_decl = info->adjusted_vars->get (*tp);
    1923                 :           0 :       if (new_decl)
    1924                 :             :         {
    1925                 :           0 :           *tp = *new_decl;
    1926                 :           0 :           info->modified = true;
    1927                 :             :         }
    1928                 :             :     }
    1929                 :             : 
    1930                 :             :   return NULL_TREE;
    1931                 :             : }
    1932                 :             : 
    1933                 :             : /* Return TRUE if CALL is a call to a builtin atomic/sync operation.  */
    1934                 :             : 
    1935                 :             : static bool
    1936                 :           0 : is_sync_builtin_call (gcall *call)
    1937                 :             : {
    1938                 :           0 :   tree callee = gimple_call_fndecl (call);
    1939                 :             : 
    1940                 :           0 :   if (callee != NULL_TREE
    1941                 :           0 :       && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
    1942                 :           0 :     switch (DECL_FUNCTION_CODE (callee))
    1943                 :             :       {
    1944                 :             : #undef DEF_SYNC_BUILTIN
    1945                 :             : #define DEF_SYNC_BUILTIN(ENUM, NAME, TYPE, ATTRS) case ENUM:
    1946                 :             : #include "sync-builtins.def"
    1947                 :             : #undef DEF_SYNC_BUILTIN
    1948                 :             :         return true;
    1949                 :             : 
    1950                 :             :       default:
    1951                 :             :         ;
    1952                 :             :       }
    1953                 :             : 
    1954                 :             :   return false;
    1955                 :             : }
    1956                 :             : 
    1957                 :             : /* Main entry point for oacc transformations which run on the device
    1958                 :             :    compiler after LTO, so we know what the target device is at this
    1959                 :             :    point (including the host fallback).  */
    1960                 :             : 
    1961                 :             : static unsigned int
    1962                 :       14894 : execute_oacc_loop_designation ()
    1963                 :             : {
    1964                 :       14894 :   tree attrs = oacc_get_fn_attrib (current_function_decl);
    1965                 :             : 
    1966                 :       14894 :   if (!attrs)
    1967                 :             :     /* Not an offloaded function.  */
    1968                 :             :     return 0;
    1969                 :             : 
    1970                 :             :   /* Parse the default dim argument exactly once.  */
    1971                 :        9523 :   if ((const void *)flag_openacc_dims != &flag_openacc_dims)
    1972                 :             :     {
    1973                 :        2365 :       oacc_parse_default_dims (flag_openacc_dims);
    1974                 :        2365 :       flag_openacc_dims = (char *)&flag_openacc_dims;
    1975                 :             :     }
    1976                 :             : 
    1977                 :        9523 :   bool is_oacc_parallel
    1978                 :        9523 :     = (lookup_attribute ("oacc parallel",
    1979                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1980                 :        9523 :   bool is_oacc_kernels
    1981                 :        9523 :     = (lookup_attribute ("oacc kernels",
    1982                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1983                 :        9523 :   bool is_oacc_serial
    1984                 :        9523 :     = (lookup_attribute ("oacc serial",
    1985                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1986                 :        9523 :   bool is_oacc_parallel_kernels_parallelized
    1987                 :        9523 :     = (lookup_attribute ("oacc parallel_kernels_parallelized",
    1988                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1989                 :        9523 :   bool is_oacc_parallel_kernels_gang_single
    1990                 :        9523 :     = (lookup_attribute ("oacc parallel_kernels_gang_single",
    1991                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1992                 :        9523 :   int fn_level = oacc_fn_attrib_level (attrs);
    1993                 :        9523 :   bool is_oacc_routine = (fn_level >= 0);
    1994                 :        9523 :   gcc_checking_assert (is_oacc_parallel
    1995                 :             :                        + is_oacc_kernels
    1996                 :             :                        + is_oacc_serial
    1997                 :             :                        + is_oacc_parallel_kernels_parallelized
    1998                 :             :                        + is_oacc_parallel_kernels_gang_single
    1999                 :             :                        + is_oacc_routine
    2000                 :             :                        == 1);
    2001                 :             : 
    2002                 :        9523 :   bool is_oacc_kernels_parallelized
    2003                 :        9523 :     = (lookup_attribute ("oacc kernels parallelized",
    2004                 :        9523 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    2005                 :        9523 :   if (is_oacc_kernels_parallelized)
    2006                 :         422 :     gcc_checking_assert (is_oacc_kernels);
    2007                 :             : 
    2008                 :        9523 :   if (dump_file)
    2009                 :             :     {
    2010                 :         161 :       if (is_oacc_parallel)
    2011                 :          42 :         fprintf (dump_file, "Function is OpenACC parallel offload\n");
    2012                 :         119 :       else if (is_oacc_kernels)
    2013                 :          84 :         fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
    2014                 :             :                  (is_oacc_kernels_parallelized
    2015                 :             :                   ? "parallelized" : "unparallelized"));
    2016                 :          71 :       else if (is_oacc_serial)
    2017                 :           6 :         fprintf (dump_file, "Function is OpenACC serial offload\n");
    2018                 :          65 :       else if (is_oacc_parallel_kernels_parallelized)
    2019                 :           0 :         fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
    2020                 :             :                  "parallel_kernels_parallelized");
    2021                 :          65 :       else if (is_oacc_parallel_kernels_gang_single)
    2022                 :           0 :         fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
    2023                 :             :                  "parallel_kernels_gang_single");
    2024                 :          65 :       else if (is_oacc_routine)
    2025                 :          65 :         fprintf (dump_file, "Function is OpenACC routine level %d\n",
    2026                 :             :                  fn_level);
    2027                 :             :       else
    2028                 :           0 :         gcc_unreachable ();
    2029                 :             :     }
    2030                 :             : 
    2031                 :             :   /* This doesn't belong into 'pass_oacc_loop_designation' conceptually, but
    2032                 :             :      it's a convenient place, so...  */
    2033                 :        9523 :   if (is_oacc_routine)
    2034                 :             :     {
    2035                 :         577 :       tree attr = lookup_attribute ("omp declare target",
    2036                 :         577 :                                     DECL_ATTRIBUTES (current_function_decl));
    2037                 :         577 :       gcc_checking_assert (attr);
    2038                 :         577 :       tree clauses = TREE_VALUE (attr);
    2039                 :         577 :       gcc_checking_assert (clauses);
    2040                 :             : 
    2041                 :             :       /* Should this OpenACC routine be discarded?  */
    2042                 :         577 :       bool discard = false;
    2043                 :             : 
    2044                 :         577 :       tree clause_nohost = omp_find_clause (clauses, OMP_CLAUSE_NOHOST);
    2045                 :         577 :       if (dump_file)
    2046                 :          65 :         fprintf (dump_file,
    2047                 :             :                  "OpenACC routine '%s' %s '%s' clause.\n",
    2048                 :          65 :                  lang_hooks.decl_printable_name (current_function_decl, 2),
    2049                 :             :                  clause_nohost ? "has" : "doesn't have",
    2050                 :          65 :                  omp_clause_code_name[OMP_CLAUSE_NOHOST]);
    2051                 :             :       /* Host compiler, 'nohost' clause?  */
    2052                 :             : #ifndef ACCEL_COMPILER
    2053                 :         577 :       if (clause_nohost)
    2054                 :          70 :         discard = true;
    2055                 :             : #endif
    2056                 :             : 
    2057                 :         577 :       if (dump_file)
    2058                 :         130 :         fprintf (dump_file,
    2059                 :             :                  "OpenACC routine '%s' %sdiscarded.\n",
    2060                 :          65 :                  lang_hooks.decl_printable_name (current_function_decl, 2),
    2061                 :             :                  discard ? "" : "not ");
    2062                 :         577 :       if (discard)
    2063                 :             :         {
    2064                 :          70 :           TREE_ASM_WRITTEN (current_function_decl) = 1;
    2065                 :          70 :           return TODO_discard_function;
    2066                 :             :         }
    2067                 :             :     }
    2068                 :             : 
    2069                 :             :   /* Unparallelized OpenACC kernels constructs must get launched as 1 x 1 x 1
    2070                 :             :      kernels, so remove the parallelism dimensions function attributes
    2071                 :             :      potentially set earlier on.  */
    2072                 :        9453 :   if (is_oacc_kernels && !is_oacc_kernels_parallelized)
    2073                 :             :     {
    2074                 :        1376 :       oacc_set_fn_attrib (current_function_decl, NULL, NULL);
    2075                 :        1376 :       attrs = oacc_get_fn_attrib (current_function_decl);
    2076                 :             :     }
    2077                 :             : 
    2078                 :             :   /* Discover, partition and process the loops.  */
    2079                 :        9453 :   oacc_loop *loops = oacc_loop_discovery ();
    2080                 :             : 
    2081                 :        9453 :   unsigned outer_mask = 0;
    2082                 :        9453 :   if (is_oacc_routine)
    2083                 :         507 :     outer_mask = GOMP_DIM_MASK (fn_level) - 1;
    2084                 :        9453 :   unsigned used_mask = oacc_loop_partition (loops, outer_mask);
    2085                 :             :   /* OpenACC kernels constructs are special: they currently don't use the
    2086                 :             :      generic oacc_loop infrastructure and attribute/dimension processing.  */
    2087                 :        9453 :   if (is_oacc_kernels && is_oacc_kernels_parallelized)
    2088                 :             :     {
    2089                 :             :       /* Parallelized OpenACC kernels constructs use gang parallelism.  See
    2090                 :             :          also tree-parloops.cc:create_parallel_loop.  */
    2091                 :         422 :       used_mask |= GOMP_DIM_MASK (GOMP_DIM_GANG);
    2092                 :             :     }
    2093                 :             : 
    2094                 :        9453 :   int dims[GOMP_DIM_MAX];
    2095                 :        9453 :   oacc_validate_dims (current_function_decl, attrs, dims, fn_level, used_mask);
    2096                 :             : 
    2097                 :        9453 :   if (dump_file)
    2098                 :             :     {
    2099                 :             :       const char *comma = "Compute dimensions [";
    2100                 :         452 :       for (int ix = 0; ix != GOMP_DIM_MAX; ix++, comma = ", ")
    2101                 :         339 :         fprintf (dump_file, "%s%d", comma, dims[ix]);
    2102                 :         113 :       fprintf (dump_file, "]\n");
    2103                 :             :     }
    2104                 :             : 
    2105                 :             :   /* Verify that for OpenACC 'kernels' decomposed "gang-single" parts we launch
    2106                 :             :      a single gang only.  */
    2107                 :        9453 :   if (is_oacc_parallel_kernels_gang_single)
    2108                 :         145 :     gcc_checking_assert (dims[GOMP_DIM_GANG] == 1);
    2109                 :             : 
    2110                 :        9453 :   oacc_loop_process (loops, fn_level);
    2111                 :        9453 :   if (dump_file)
    2112                 :             :     {
    2113                 :         113 :       fprintf (dump_file, "OpenACC loops\n");
    2114                 :         113 :       dump_oacc_loop (dump_file, loops, 0);
    2115                 :         113 :       fprintf (dump_file, "\n");
    2116                 :             :     }
    2117                 :        9453 :   if (dump_enabled_p ())
    2118                 :             :     {
    2119                 :        2287 :       oacc_loop *l = loops;
    2120                 :             :       /* OpenACC kernels constructs are special: they currently don't use the
    2121                 :             :          generic oacc_loop infrastructure.  */
    2122                 :        2287 :       if (is_oacc_kernels)
    2123                 :             :         {
    2124                 :             :           /* Create a fake oacc_loop for diagnostic purposes.  */
    2125                 :         694 :           l = new_oacc_loop_raw (NULL,
    2126                 :         694 :                                  DECL_SOURCE_LOCATION (current_function_decl));
    2127                 :         694 :           l->mask = used_mask;
    2128                 :             :         }
    2129                 :             :       else
    2130                 :             :         {
    2131                 :             :           /* Skip the outermost, dummy OpenACC loop  */
    2132                 :        1593 :           l = l->child;
    2133                 :             :         }
    2134                 :        2287 :       if (l)
    2135                 :        1755 :         inform_oacc_loop (l);
    2136                 :        2287 :       if (is_oacc_kernels)
    2137                 :         694 :         free_oacc_loop (l);
    2138                 :             :     }
    2139                 :             : 
    2140                 :        9453 :   free_oacc_loop (loops);
    2141                 :             : 
    2142                 :        9453 :   return 0;
    2143                 :             : }
    2144                 :             : 
    2145                 :             : static unsigned int
    2146                 :       14824 : execute_oacc_device_lower ()
    2147                 :             : {
    2148                 :       14824 :   tree attrs = oacc_get_fn_attrib (current_function_decl);
    2149                 :             : 
    2150                 :       14824 :   if (!attrs)
    2151                 :             :     /* Not an offloaded function.  */
    2152                 :             :     return 0;
    2153                 :             : 
    2154                 :             :   int dims[GOMP_DIM_MAX];
    2155                 :       37812 :   for (unsigned i = 0; i < GOMP_DIM_MAX; i++)
    2156                 :       28359 :     dims[i] = oacc_get_fn_dim_size (current_function_decl, i);
    2157                 :             : 
    2158                 :        9453 :   hash_map<tree, tree> adjusted_vars;
    2159                 :             : 
    2160                 :             :   /* Now lower internal loop functions to target-specific code
    2161                 :             :      sequences.  */
    2162                 :        9453 :   basic_block bb;
    2163                 :      168569 :   FOR_ALL_BB_FN (bb, cfun)
    2164                 :      852065 :     for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
    2165                 :             :       {
    2166                 :      533833 :         gimple *stmt = gsi_stmt (gsi);
    2167                 :      533833 :         if (!is_gimple_call (stmt))
    2168                 :             :           {
    2169                 :      356573 :             gsi_next (&gsi);
    2170                 :      356573 :             continue;
    2171                 :             :           }
    2172                 :             : 
    2173                 :      177260 :         gcall *call = as_a <gcall *> (stmt);
    2174                 :      177260 :         if (!gimple_call_internal_p (call))
    2175                 :             :           {
    2176                 :        4345 :             gsi_next (&gsi);
    2177                 :        4345 :             continue;
    2178                 :             :           }
    2179                 :             : 
    2180                 :             :         /* Rewind to allow rescan.  */
    2181                 :      172915 :         gsi_prev (&gsi);
    2182                 :      172915 :         bool rescan = false, remove = false;
    2183                 :      172915 :         enum  internal_fn ifn_code = gimple_call_internal_fn (call);
    2184                 :             : 
    2185                 :      172915 :         switch (ifn_code)
    2186                 :             :           {
    2187                 :             :           default: break;
    2188                 :             : 
    2189                 :         293 :           case IFN_GOACC_TILE:
    2190                 :         293 :             oacc_xform_tile (call);
    2191                 :         293 :             rescan = true;
    2192                 :         293 :             break;
    2193                 :             :             
    2194                 :       43199 :           case IFN_GOACC_LOOP:
    2195                 :       43199 :             oacc_xform_loop (call);
    2196                 :       43199 :             rescan = true;
    2197                 :       43199 :             break;
    2198                 :             : 
    2199                 :       25376 :           case IFN_GOACC_REDUCTION:
    2200                 :             :             /* Mark the function for SSA renaming.  */
    2201                 :       25376 :             mark_virtual_operands_for_renaming (cfun);
    2202                 :             : 
    2203                 :             :             /* If the level is -1, this ended up being an unused
    2204                 :             :                axis.  Handle as a default.  */
    2205                 :       25376 :             if (integer_minus_onep (gimple_call_arg (call, 3)))
    2206                 :        5828 :               default_goacc_reduction (call);
    2207                 :             :             else
    2208                 :       19548 :               targetm.goacc.reduction (call);
    2209                 :             :             rescan = true;
    2210                 :             :             break;
    2211                 :             : 
    2212                 :       75138 :           case IFN_UNIQUE:
    2213                 :       75138 :             {
    2214                 :       75138 :               enum ifn_unique_kind kind
    2215                 :             :                 = ((enum ifn_unique_kind)
    2216                 :       75138 :                    TREE_INT_CST_LOW (gimple_call_arg (call, 0)));
    2217                 :             : 
    2218                 :       75138 :               switch (kind)
    2219                 :             :                 {
    2220                 :             :                 default:
    2221                 :             :                   break;
    2222                 :             : 
    2223                 :       28926 :                 case IFN_UNIQUE_OACC_FORK:
    2224                 :       28926 :                 case IFN_UNIQUE_OACC_JOIN:
    2225                 :       28926 :                   if (integer_minus_onep (gimple_call_arg (call, 2)))
    2226                 :             :                     remove = true;
    2227                 :       23332 :                   else if (!targetm.goacc.fork_join
    2228                 :       23332 :                            (call, dims, kind == IFN_UNIQUE_OACC_FORK))
    2229                 :       75138 :                     remove = true;
    2230                 :             :                   break;
    2231                 :             : 
    2232                 :             :                 case IFN_UNIQUE_OACC_HEAD_MARK:
    2233                 :             :                 case IFN_UNIQUE_OACC_TAIL_MARK:
    2234                 :       75138 :                   remove = true;
    2235                 :             :                   break;
    2236                 :             : 
    2237                 :         248 :                 case IFN_UNIQUE_OACC_PRIVATE:
    2238                 :         248 :                   {
    2239                 :         248 :                     dump_flags_t l_dump_flags
    2240                 :         248 :                       = get_openacc_privatization_dump_flags ();
    2241                 :             : 
    2242                 :         248 :                     location_t loc = gimple_location (stmt);
    2243                 :         248 :                     if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
    2244                 :          20 :                       loc = DECL_SOURCE_LOCATION (current_function_decl);
    2245                 :         248 :                     const dump_user_location_t d_u_loc
    2246                 :         248 :                       = dump_user_location_t::from_location_t (loc);
    2247                 :             : 
    2248                 :         248 :                     HOST_WIDE_INT level
    2249                 :         248 :                       = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
    2250                 :         248 :                     gcc_checking_assert (level == -1
    2251                 :             :                                          || (level >= 0
    2252                 :             :                                              && level < GOMP_DIM_MAX));
    2253                 :         340 :                     for (unsigned i = 3;
    2254                 :         588 :                          i < gimple_call_num_args (call);
    2255                 :             :                          i++)
    2256                 :             :                       {
    2257                 :         340 :                         static char const *const axes[] =
    2258                 :             :                         /* Must be kept in sync with GOMP_DIM enumeration.  */
    2259                 :             :                           { "gang", "worker", "vector" };
    2260                 :             : 
    2261                 :         340 :                         tree arg = gimple_call_arg (call, i);
    2262                 :         340 :                         gcc_checking_assert (TREE_CODE (arg) == ADDR_EXPR);
    2263                 :         340 :                         tree decl = TREE_OPERAND (arg, 0);
    2264                 :         340 :                         if (dump_enabled_p ())
    2265                 :             : /* PR100695 "Format decoder, quoting in 'dump_printf' etc." */
    2266                 :             : #if __GNUC__ >= 10
    2267                 :         335 : # pragma GCC diagnostic push
    2268                 :         335 : # pragma GCC diagnostic ignored "-Wformat"
    2269                 :             : #endif
    2270                 :         335 :                           dump_printf_loc (l_dump_flags, d_u_loc,
    2271                 :             :                                            "variable %<%T%> ought to be"
    2272                 :             :                                            " adjusted for OpenACC"
    2273                 :             :                                            " privatization level: %qs\n",
    2274                 :             :                                            decl,
    2275                 :             :                                            (level == -1
    2276                 :             :                                             ? "UNKNOWN" : axes[level]));
    2277                 :             : #if __GNUC__ >= 10
    2278                 :         340 : # pragma GCC diagnostic pop
    2279                 :             : #endif
    2280                 :         340 :                         bool adjusted;
    2281                 :         340 :                         if (level == -1)
    2282                 :             :                           adjusted = false;
    2283                 :         335 :                         else if (!targetm.goacc.adjust_private_decl)
    2284                 :             :                           adjusted = false;
    2285                 :           0 :                         else if (level == GOMP_DIM_VECTOR)
    2286                 :             :                           {
    2287                 :             :                             /* That's the default behavior.  */
    2288                 :             :                             adjusted = true;
    2289                 :             :                           }
    2290                 :             :                         else
    2291                 :             :                           {
    2292                 :           0 :                             tree oldtype = TREE_TYPE (decl);
    2293                 :           0 :                             tree newdecl
    2294                 :           0 :                               = targetm.goacc.adjust_private_decl (loc, decl,
    2295                 :           0 :                                                                    level);
    2296                 :           0 :                             adjusted = (TREE_TYPE (newdecl) != oldtype
    2297                 :           0 :                                         || newdecl != decl);
    2298                 :           0 :                             if (adjusted)
    2299                 :           0 :                               adjusted_vars.put (decl, newdecl);
    2300                 :             :                           }
    2301                 :           0 :                         if (adjusted
    2302                 :           0 :                             && dump_enabled_p ())
    2303                 :             : /* PR100695 "Format decoder, quoting in 'dump_printf' etc." */
    2304                 :             : #if __GNUC__ >= 10
    2305                 :           0 : # pragma GCC diagnostic push
    2306                 :           0 : # pragma GCC diagnostic ignored "-Wformat"
    2307                 :             : #endif
    2308                 :           0 :                           dump_printf_loc (l_dump_flags, d_u_loc,
    2309                 :             :                                            "variable %<%T%> adjusted for"
    2310                 :             :                                            " OpenACC privatization level:"
    2311                 :             :                                            " %qs\n",
    2312                 :           0 :                                            decl, axes[level]);
    2313                 :             : #if __GNUC__ >= 10
    2314                 :         340 : # pragma GCC diagnostic pop
    2315                 :             : #endif
    2316                 :             :                       }
    2317                 :         248 :                     remove = true;
    2318                 :             :                   }
    2319                 :         248 :                   break;
    2320                 :             :                 }
    2321                 :             :               break;
    2322                 :             :             }
    2323                 :             :           }
    2324                 :             : 
    2325                 :      172915 :         if (gsi_end_p (gsi))
    2326                 :             :           /* We rewound past the beginning of the BB.  */
    2327                 :      164644 :           gsi = gsi_start_bb (bb);
    2328                 :             :         else
    2329                 :             :           /* Undo the rewind.  */
    2330                 :       90593 :           gsi_next (&gsi);
    2331                 :             : 
    2332                 :      172915 :         if (remove)
    2333                 :             :           {
    2334                 :      150276 :             if (gimple_vdef (call))
    2335                 :       75138 :               replace_uses_by (gimple_vdef (call), gimple_vuse (call));
    2336                 :       75138 :             if (gimple_call_lhs (call))
    2337                 :             :               {
    2338                 :             :                 /* Propagate the data dependency var.  */
    2339                 :       70118 :                 gimple *ass = gimple_build_assign (gimple_call_lhs (call),
    2340                 :             :                                                    gimple_call_arg (call, 1));
    2341                 :       70118 :                 gsi_replace (&gsi, ass,  false);
    2342                 :             :               }
    2343                 :             :             else
    2344                 :        5020 :               gsi_remove (&gsi, true);
    2345                 :             :           }
    2346                 :       97777 :         else if (!rescan)
    2347                 :             :           /* If not rescanning, advance over the call.  */
    2348                 :       28909 :           gsi_next (&gsi);
    2349                 :             :       }
    2350                 :             : 
    2351                 :             :   /* Regarding the OpenACC privatization level, we're currently only looking at
    2352                 :             :      making the gang-private level work.  Regarding that, we have the following
    2353                 :             :      configurations:
    2354                 :             : 
    2355                 :             :        - GCN offloading: 'targetm.goacc.adjust_private_decl' does the work (in
    2356                 :             :          particular, change 'TREE_TYPE', etc.) and there is no
    2357                 :             :          'targetm.goacc.expand_var_decl'.
    2358                 :             : 
    2359                 :             :        - nvptx offloading: 'targetm.goacc.adjust_private_decl' only sets a
    2360                 :             :          marker and then 'targetm.goacc.expand_var_decl' does the work.
    2361                 :             : 
    2362                 :             :      Eventually (in particular, for worker-private level?), both
    2363                 :             :      'targetm.goacc.adjust_private_decl' and 'targetm.goacc.expand_var_decl'
    2364                 :             :      may need to do things, but that's currently not meant to be addressed, and
    2365                 :             :      thus not fully worked out and implemented, and thus untested.  Hence,
    2366                 :             :      'assert' what currently is implemented/tested, only.  */
    2367                 :             : 
    2368                 :        9453 :   if (targetm.goacc.expand_var_decl)
    2369                 :           0 :     gcc_assert (adjusted_vars.is_empty ());
    2370                 :             : 
    2371                 :             :   /* Make adjustments to gang-private local variables if required by the
    2372                 :             :      target, e.g. forcing them into a particular address space.  Afterwards,
    2373                 :             :      ADDR_EXPR nodes which have adjusted variables as their argument need to
    2374                 :             :      be modified in one of two ways:
    2375                 :             : 
    2376                 :             :        1. They can be recreated, making a pointer to the variable in the new
    2377                 :             :           address space, or
    2378                 :             : 
    2379                 :             :        2. The address of the variable in the new address space can be taken,
    2380                 :             :           converted to the default (original) address space, and the result of
    2381                 :             :           that conversion subsituted in place of the original ADDR_EXPR node.
    2382                 :             : 
    2383                 :             :      Which of these is done depends on the gimple statement being processed.
    2384                 :             :      At present atomic operations and inline asms use (1), and everything else
    2385                 :             :      uses (2).  At least on AMD GCN, there are atomic operations that work
    2386                 :             :      directly in the LDS address space.
    2387                 :             : 
    2388                 :             :      COMPONENT_REFS, ARRAY_REFS and plain VAR_DECLs are also rewritten to use
    2389                 :             :      the new decl, adjusting types of appropriate tree nodes as necessary.  */
    2390                 :             : 
    2391                 :        9453 :   if (targetm.goacc.adjust_private_decl
    2392                 :        9453 :       && !adjusted_vars.is_empty ())
    2393                 :             :     {
    2394                 :           0 :       FOR_ALL_BB_FN (bb, cfun)
    2395                 :           0 :         for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
    2396                 :           0 :              !gsi_end_p (gsi);
    2397                 :           0 :              gsi_next (&gsi))
    2398                 :             :           {
    2399                 :           0 :             gimple *stmt = gsi_stmt (gsi);
    2400                 :           0 :             walk_stmt_info wi;
    2401                 :           0 :             var_decl_rewrite_info info;
    2402                 :             : 
    2403                 :           0 :             info.avoid_pointer_conversion
    2404                 :           0 :               = (is_gimple_call (stmt)
    2405                 :           0 :                  && is_sync_builtin_call (as_a <gcall *> (stmt)))
    2406                 :           0 :                 || gimple_code (stmt) == GIMPLE_ASM;
    2407                 :           0 :             info.stmt = stmt;
    2408                 :           0 :             info.modified = false;
    2409                 :           0 :             info.adjusted_vars = &adjusted_vars;
    2410                 :             : 
    2411                 :           0 :             memset (&wi, 0, sizeof (wi));
    2412                 :           0 :             wi.info = &info;
    2413                 :             : 
    2414                 :           0 :             walk_gimple_op (stmt, oacc_rewrite_var_decl, &wi);
    2415                 :             : 
    2416                 :           0 :             if (info.modified)
    2417                 :           0 :               update_stmt (stmt);
    2418                 :             :           }
    2419                 :             :     }
    2420                 :             : 
    2421                 :        9453 :   return 0;
    2422                 :        9453 : }
    2423                 :             : 
    2424                 :             : /* Default launch dimension validator.  Force everything to 1.  A
    2425                 :             :    backend that wants to provide larger dimensions must override this
    2426                 :             :    hook.  */
    2427                 :             : 
    2428                 :             : bool
    2429                 :       14183 : default_goacc_validate_dims (tree ARG_UNUSED (decl), int *dims,
    2430                 :             :                              int ARG_UNUSED (fn_level),
    2431                 :             :                              unsigned ARG_UNUSED (used))
    2432                 :             : {
    2433                 :       14183 :   bool changed = false;
    2434                 :             : 
    2435                 :       56732 :   for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
    2436                 :             :     {
    2437                 :       42549 :       if (dims[ix] != 1)
    2438                 :             :         {
    2439                 :       33947 :           dims[ix] = 1;
    2440                 :       33947 :           changed = true;
    2441                 :             :         }
    2442                 :             :     }
    2443                 :             : 
    2444                 :       14183 :   return changed;
    2445                 :             : }
    2446                 :             : 
    2447                 :             : /* Default dimension bound is unknown on accelerator and 1 on host.  */
    2448                 :             : 
    2449                 :             : int
    2450                 :           0 : default_goacc_dim_limit (int ARG_UNUSED (axis))
    2451                 :             : {
    2452                 :             : #ifdef ACCEL_COMPILER
    2453                 :             :   return 0;
    2454                 :             : #else
    2455                 :           0 :   return 1;
    2456                 :             : #endif
    2457                 :             : }
    2458                 :             : 
    2459                 :             : namespace {
    2460                 :             : 
    2461                 :             : const pass_data pass_data_oacc_loop_designation =
    2462                 :             : {
    2463                 :             :   GIMPLE_PASS, /* type */
    2464                 :             :   "oaccloops", /* name */
    2465                 :             :   OPTGROUP_OMP, /* optinfo_flags */
    2466                 :             :   TV_NONE, /* tv_id */
    2467                 :             :   PROP_cfg, /* properties_required */
    2468                 :             :   0 /* Possibly PROP_gimple_eomp.  */, /* properties_provided */
    2469                 :             :   0, /* properties_destroyed */
    2470                 :             :   0, /* todo_flags_start */
    2471                 :             :   TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
    2472                 :             : };
    2473                 :             : 
    2474                 :             : class pass_oacc_loop_designation : public gimple_opt_pass
    2475                 :             : {
    2476                 :             : public:
    2477                 :      285617 :   pass_oacc_loop_designation (gcc::context *ctxt)
    2478                 :      571234 :     : gimple_opt_pass (pass_data_oacc_loop_designation, ctxt)
    2479                 :             :   {}
    2480                 :             : 
    2481                 :             :   /* opt_pass methods: */
    2482                 :     1420522 :   bool gate (function *) final override { return flag_openacc; };
    2483                 :             : 
    2484                 :       14894 :   unsigned int execute (function *) final override
    2485                 :             :     {
    2486                 :       14894 :       return execute_oacc_loop_designation ();
    2487                 :             :     }
    2488                 :             : 
    2489                 :             : }; // class pass_oacc_loop_designation
    2490                 :             : 
    2491                 :             : const pass_data pass_data_oacc_device_lower =
    2492                 :             : {
    2493                 :             :   GIMPLE_PASS, /* type */
    2494                 :             :   "oaccdevlow", /* name */
    2495                 :             :   OPTGROUP_OMP, /* optinfo_flags */
    2496                 :             :   TV_NONE, /* tv_id */
    2497                 :             :   PROP_cfg, /* properties_required */
    2498                 :             :   0 /* Possibly PROP_gimple_eomp.  */, /* properties_provided */
    2499                 :             :   0, /* properties_destroyed */
    2500                 :             :   0, /* todo_flags_start */
    2501                 :             :   TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
    2502                 :             : };
    2503                 :             : 
    2504                 :             : class pass_oacc_device_lower : public gimple_opt_pass
    2505                 :             : {
    2506                 :             : public:
    2507                 :      285617 :   pass_oacc_device_lower (gcc::context *ctxt)
    2508                 :      571234 :     : gimple_opt_pass (pass_data_oacc_device_lower, ctxt)
    2509                 :             :   {}
    2510                 :             : 
    2511                 :             :   /* opt_pass methods: */
    2512                 :     1420452 :   bool gate (function *) final override { return flag_openacc; };
    2513                 :             : 
    2514                 :       14824 :   unsigned int execute (function *) final override
    2515                 :             :     {
    2516                 :       14824 :       return execute_oacc_device_lower ();
    2517                 :             :     }
    2518                 :             : 
    2519                 :             : }; // class pass_oacc_device_lower
    2520                 :             : 
    2521                 :             : } // anon namespace
    2522                 :             : 
    2523                 :             : gimple_opt_pass *
    2524                 :      285617 : make_pass_oacc_loop_designation (gcc::context *ctxt)
    2525                 :             : {
    2526                 :      285617 :   return new pass_oacc_loop_designation (ctxt);
    2527                 :             : }
    2528                 :             : 
    2529                 :             : gimple_opt_pass *
    2530                 :      285617 : make_pass_oacc_device_lower (gcc::context *ctxt)
    2531                 :             : {
    2532                 :      285617 :   return new pass_oacc_device_lower (ctxt);
    2533                 :             : }
    2534                 :             : 
    2535                 :             : 
    2536                 :             : /* Rewrite GOMP_SIMT_ENTER_ALLOC call given by GSI and remove the preceding
    2537                 :             :    GOMP_SIMT_ENTER call identifying the privatized variables, which are
    2538                 :             :    turned to structure fields and receive a DECL_VALUE_EXPR accordingly.
    2539                 :             :    Set *REGIMPLIFY to true, except if no privatized variables were seen.  */
    2540                 :             : 
    2541                 :             : static void
    2542                 :           0 : ompdevlow_adjust_simt_enter (gimple_stmt_iterator *gsi, bool *regimplify)
    2543                 :             : {
    2544                 :           0 :   gimple *alloc_stmt = gsi_stmt (*gsi);
    2545                 :           0 :   tree simtrec = gimple_call_lhs (alloc_stmt);
    2546                 :           0 :   tree simduid = gimple_call_arg (alloc_stmt, 0);
    2547                 :           0 :   gimple *enter_stmt = SSA_NAME_DEF_STMT (simduid);
    2548                 :           0 :   gcc_assert (gimple_call_internal_p (enter_stmt, IFN_GOMP_SIMT_ENTER));
    2549                 :           0 :   tree rectype = lang_hooks.types.make_type (RECORD_TYPE);
    2550                 :           0 :   TYPE_ARTIFICIAL (rectype) = TYPE_NAMELESS (rectype) = 1;
    2551                 :           0 :   TREE_ADDRESSABLE (rectype) = 1;
    2552                 :           0 :   TREE_TYPE (simtrec) = build_pointer_type (rectype);
    2553                 :           0 :   for (unsigned i = 1; i < gimple_call_num_args (enter_stmt); i++)
    2554                 :             :     {
    2555                 :           0 :       tree *argp = gimple_call_arg_ptr (enter_stmt, i);
    2556                 :           0 :       if (*argp == null_pointer_node)
    2557                 :           0 :         continue;
    2558                 :           0 :       gcc_assert (TREE_CODE (*argp) == ADDR_EXPR
    2559                 :             :                   && VAR_P (TREE_OPERAND (*argp, 0)));
    2560                 :           0 :       tree var = TREE_OPERAND (*argp, 0);
    2561                 :             : 
    2562                 :           0 :       tree field = build_decl (DECL_SOURCE_LOCATION (var), FIELD_DECL,
    2563                 :           0 :                                DECL_NAME (var), TREE_TYPE (var));
    2564                 :           0 :       SET_DECL_ALIGN (field, DECL_ALIGN (var));
    2565                 :           0 :       DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var);
    2566                 :           0 :       TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var);
    2567                 :             : 
    2568                 :           0 :       insert_field_into_struct (rectype, field);
    2569                 :             : 
    2570                 :           0 :       tree t = build_simple_mem_ref (simtrec);
    2571                 :           0 :       t = build3 (COMPONENT_REF, TREE_TYPE (var), t, field, NULL);
    2572                 :           0 :       TREE_THIS_VOLATILE (t) = TREE_THIS_VOLATILE (var);
    2573                 :           0 :       SET_DECL_VALUE_EXPR (var, t);
    2574                 :           0 :       DECL_HAS_VALUE_EXPR_P (var) = 1;
    2575                 :           0 :       *regimplify = true;
    2576                 :             :     }
    2577                 :           0 :   layout_type (rectype);
    2578                 :           0 :   tree size = TYPE_SIZE_UNIT (rectype);
    2579                 :           0 :   tree align = build_int_cst (TREE_TYPE (size), TYPE_ALIGN_UNIT (rectype));
    2580                 :             : 
    2581                 :           0 :   alloc_stmt
    2582                 :           0 :     = gimple_build_call_internal (IFN_GOMP_SIMT_ENTER_ALLOC, 2, size, align);
    2583                 :           0 :   gimple_call_set_lhs (alloc_stmt, simtrec);
    2584                 :           0 :   gsi_replace (gsi, alloc_stmt, false);
    2585                 :           0 :   gimple_stmt_iterator enter_gsi = gsi_for_stmt (enter_stmt);
    2586                 :           0 :   enter_stmt = gimple_build_assign (simduid, gimple_call_arg (enter_stmt, 0));
    2587                 :           0 :   gsi_replace (&enter_gsi, enter_stmt, false);
    2588                 :             : 
    2589                 :           0 :   use_operand_p use;
    2590                 :           0 :   gimple *exit_stmt;
    2591                 :           0 :   if (single_imm_use (simtrec, &use, &exit_stmt))
    2592                 :             :     {
    2593                 :           0 :       gcc_assert (gimple_call_internal_p (exit_stmt, IFN_GOMP_SIMT_EXIT));
    2594                 :           0 :       gimple_stmt_iterator exit_gsi = gsi_for_stmt (exit_stmt);
    2595                 :           0 :       tree clobber = build_clobber (rectype);
    2596                 :           0 :       exit_stmt = gimple_build_assign (build_simple_mem_ref (simtrec), clobber);
    2597                 :           0 :       gsi_insert_before (&exit_gsi, exit_stmt, GSI_SAME_STMT);
    2598                 :             :     }
    2599                 :             :   else
    2600                 :           0 :     gcc_checking_assert (has_zero_uses (simtrec));
    2601                 :           0 : }
    2602                 :             : 
    2603                 :             : /* Callback for walk_gimple_stmt used to scan for SIMT-privatized variables.  */
    2604                 :             : 
    2605                 :             : static tree
    2606                 :           0 : find_simtpriv_var_op (tree *tp, int *walk_subtrees, void *)
    2607                 :             : {
    2608                 :           0 :   tree t = *tp;
    2609                 :             : 
    2610                 :           0 :   if (VAR_P (t)
    2611                 :           0 :       && DECL_HAS_VALUE_EXPR_P (t)
    2612                 :           0 :       && lookup_attribute ("omp simt private", DECL_ATTRIBUTES (t)))
    2613                 :             :     {
    2614                 :           0 :       *walk_subtrees = 0;
    2615                 :           0 :       return t;
    2616                 :             :     }
    2617                 :             :   return NULL_TREE;
    2618                 :             : }
    2619                 :             : 
    2620                 :             : /* Cleanup uses of SIMT placeholder internal functions: on non-SIMT targets,
    2621                 :             :    VF is 1 and LANE is 0; on SIMT targets, VF is folded to a constant, and
    2622                 :             :    LANE is kept to be expanded to RTL later on.  Also cleanup all other SIMT
    2623                 :             :    internal functions on non-SIMT targets, and likewise some SIMD internal
    2624                 :             :    functions on SIMT targets.  */
    2625                 :             : 
    2626                 :             : static unsigned int
    2627                 :       19255 : execute_omp_device_lower ()
    2628                 :             : {
    2629                 :       19255 :   int vf = targetm.simt.vf ? targetm.simt.vf () : 1;
    2630                 :       19255 :   bool regimplify = false;
    2631                 :       19255 :   basic_block bb;
    2632                 :       19255 :   gimple_stmt_iterator gsi;
    2633                 :       19255 :   bool calls_declare_variant_alt
    2634                 :       19255 :     = cgraph_node::get (cfun->decl)->calls_declare_variant_alt;
    2635                 :             : #ifdef ACCEL_COMPILER
    2636                 :             :   bool omp_redirect_indirect_calls = vec_safe_length (offload_ind_funcs) > 0;
    2637                 :             :   tree map_ptr_fn
    2638                 :             :     = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_MAP_INDIRECT_PTR);
    2639                 :             : #endif
    2640                 :       49175 :   FOR_EACH_BB_FN (bb, cfun)
    2641                 :      208016 :     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    2642                 :             :       {
    2643                 :      148176 :         gimple *stmt = gsi_stmt (gsi);
    2644                 :      148176 :         if (!is_gimple_call (stmt))
    2645                 :      131507 :           continue;
    2646                 :       16669 :         if (!gimple_call_internal_p (stmt))
    2647                 :             :           {
    2648                 :       16530 :             if (calls_declare_variant_alt)
    2649                 :         163 :               if (tree fndecl = gimple_call_fndecl (stmt))
    2650                 :             :                 {
    2651                 :         163 :                   tree new_fndecl = omp_resolve_declare_variant (fndecl);
    2652                 :         163 :                   if (new_fndecl != fndecl)
    2653                 :             :                     {
    2654                 :         126 :                       gimple_call_set_fndecl (stmt, new_fndecl);
    2655                 :         126 :                       update_stmt (stmt);
    2656                 :             :                     }
    2657                 :             :                 }
    2658                 :             : #ifdef ACCEL_COMPILER
    2659                 :             :             if (omp_redirect_indirect_calls
    2660                 :             :                 && gimple_call_fndecl (stmt) == NULL_TREE)
    2661                 :             :               {
    2662                 :             :                 gcall *orig_call = dyn_cast <gcall *> (stmt);
    2663                 :             :                 tree call_fn = gimple_call_fn (stmt);
    2664                 :             :                 tree fn_ty = TREE_TYPE (call_fn);
    2665                 :             : 
    2666                 :             :                 if (TREE_CODE (call_fn) == OBJ_TYPE_REF)
    2667                 :             :                   {
    2668                 :             :                     tree obj_ref = create_tmp_reg (TREE_TYPE (call_fn),
    2669                 :             :                                                    ".ind_fn_objref");
    2670                 :             :                     gimple *gassign = gimple_build_assign (obj_ref, call_fn);
    2671                 :             :                     gsi_insert_before  (&gsi, gassign, GSI_SAME_STMT);
    2672                 :             :                     call_fn = obj_ref;
    2673                 :             :                   }
    2674                 :             :                 tree mapped_fn = create_tmp_reg (fn_ty, ".ind_fn");
    2675                 :             :                 gimple *gcall =
    2676                 :             :                     gimple_build_call (map_ptr_fn, 1, call_fn);
    2677                 :             :                 gimple_set_location (gcall, gimple_location (stmt));
    2678                 :             :                 gimple_call_set_lhs (gcall, mapped_fn);
    2679                 :             :                 gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
    2680                 :             : 
    2681                 :             :                 gimple_call_set_fn (orig_call, mapped_fn);
    2682                 :             :                 update_stmt (orig_call);
    2683                 :             :               }
    2684                 :             : #endif
    2685                 :       16530 :             continue;
    2686                 :       16530 :           }
    2687                 :         139 :         tree lhs = gimple_call_lhs (stmt), rhs = NULL_TREE;
    2688                 :         139 :         tree type = lhs ? TREE_TYPE (lhs) : integer_type_node;
    2689                 :         139 :         switch (gimple_call_internal_fn (stmt))
    2690                 :             :           {
    2691                 :           0 :           case IFN_GOMP_TARGET_REV:
    2692                 :           0 :             {
    2693                 :             : #ifndef ACCEL_COMPILER
    2694                 :           0 :               gimple_stmt_iterator gsi2 = gsi;
    2695                 :           0 :               gsi_next (&gsi2);
    2696                 :           0 :               gcc_assert (!gsi_end_p (gsi2));
    2697                 :           0 :               gcc_assert (gimple_call_builtin_p (gsi_stmt (gsi2),
    2698                 :             :                                                  BUILT_IN_GOMP_TARGET));
    2699                 :           0 :               tree old_decl
    2700                 :           0 :                 = TREE_OPERAND (gimple_call_arg (gsi_stmt (gsi2), 1), 0);
    2701                 :           0 :               tree new_decl = gimple_call_arg (gsi_stmt (gsi), 0);
    2702                 :           0 :               gimple_call_set_arg (gsi_stmt (gsi2), 1, new_decl);
    2703                 :           0 :               update_stmt (gsi_stmt (gsi2));
    2704                 :           0 :               new_decl = TREE_OPERAND (new_decl, 0);
    2705                 :           0 :               unsigned i;
    2706                 :           0 :               unsigned num_funcs = vec_safe_length (offload_funcs);
    2707                 :           0 :               for (i = 0; i < num_funcs; i++)
    2708                 :             :                 {
    2709                 :           0 :                   if ((*offload_funcs)[i] == old_decl)
    2710                 :             :                     {
    2711                 :           0 :                       (*offload_funcs)[i] = new_decl;
    2712                 :           0 :                       break;
    2713                 :             :                     }
    2714                 :           0 :                   else if ((*offload_funcs)[i] == new_decl)
    2715                 :             :                     break;  /* This can happen due to inlining.  */
    2716                 :             :                 }
    2717                 :           0 :               gcc_assert (i < num_funcs);
    2718                 :             : #else
    2719                 :             :               tree old_decl = TREE_OPERAND (gimple_call_arg (gsi_stmt (gsi), 0),
    2720                 :             :                                             0);
    2721                 :             : #endif
    2722                 :             :               /* FIXME: Find a way to actually prevent outputting the empty-body
    2723                 :             :                  old_decl as debug symbol + function in the assembly file.  */
    2724                 :           0 :               cgraph_node *node = cgraph_node::get (old_decl);
    2725                 :           0 :               node->address_taken = false;
    2726                 :           0 :               node->need_lto_streaming = false;
    2727                 :           0 :               node->offloadable = false;
    2728                 :             : 
    2729                 :           0 :               unlink_stmt_vdef (stmt);
    2730                 :             :             }
    2731                 :           0 :             break;
    2732                 :           0 :           case IFN_GOMP_USE_SIMT:
    2733                 :           0 :             rhs = vf == 1 ? integer_zero_node : integer_one_node;
    2734                 :             :             break;
    2735                 :           0 :           case IFN_GOMP_SIMT_ENTER:
    2736                 :           0 :             rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
    2737                 :           0 :             goto simtreg_enter_exit;
    2738                 :           0 :           case IFN_GOMP_SIMT_ENTER_ALLOC:
    2739                 :           0 :             if (vf != 1)
    2740                 :           0 :               ompdevlow_adjust_simt_enter (&gsi, &regimplify);
    2741                 :           0 :             rhs = vf == 1 ? null_pointer_node : NULL_TREE;
    2742                 :           0 :             goto simtreg_enter_exit;
    2743                 :           0 :           case IFN_GOMP_SIMT_EXIT:
    2744                 :           0 :           simtreg_enter_exit:
    2745                 :           0 :             if (vf != 1)
    2746                 :           0 :               continue;
    2747                 :           0 :             unlink_stmt_vdef (stmt);
    2748                 :           0 :             break;
    2749                 :           0 :           case IFN_GOMP_SIMT_LANE:
    2750                 :           0 :           case IFN_GOMP_SIMT_LAST_LANE:
    2751                 :           0 :             rhs = vf == 1 ? build_zero_cst (type) : NULL_TREE;
    2752                 :             :             break;
    2753                 :           0 :           case IFN_GOMP_SIMT_VF:
    2754                 :           0 :             rhs = build_int_cst (type, vf);
    2755                 :           0 :             break;
    2756                 :           0 :           case IFN_GOMP_SIMT_ORDERED_PRED:
    2757                 :           0 :             rhs = vf == 1 ? integer_zero_node : NULL_TREE;
    2758                 :           0 :             if (rhs || !lhs)
    2759                 :           0 :               unlink_stmt_vdef (stmt);
    2760                 :             :             break;
    2761                 :           0 :           case IFN_GOMP_SIMT_VOTE_ANY:
    2762                 :           0 :           case IFN_GOMP_SIMT_XCHG_BFLY:
    2763                 :           0 :           case IFN_GOMP_SIMT_XCHG_IDX:
    2764                 :           0 :             rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
    2765                 :             :             break;
    2766                 :           7 :           case IFN_GOMP_SIMD_LANE:
    2767                 :           7 :           case IFN_GOMP_SIMD_LAST_LANE:
    2768                 :           7 :             rhs = vf != 1 ? build_zero_cst (type) : NULL_TREE;
    2769                 :             :             break;
    2770                 :           0 :           case IFN_GOMP_SIMD_VF:
    2771                 :           0 :             rhs = vf != 1 ? build_one_cst (type) : NULL_TREE;
    2772                 :             :             break;
    2773                 :         132 :           default:
    2774                 :         132 :             continue;
    2775                 :         132 :           }
    2776                 :           7 :         if (lhs && !rhs)
    2777                 :           7 :           continue;
    2778                 :           0 :         stmt = lhs ? gimple_build_assign (lhs, rhs) : gimple_build_nop ();
    2779                 :           0 :         gsi_replace (&gsi, stmt, false);
    2780                 :             :       }
    2781                 :       19255 :   if (regimplify)
    2782                 :           0 :     FOR_EACH_BB_REVERSE_FN (bb, cfun)
    2783                 :           0 :       for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
    2784                 :           0 :         if (walk_gimple_stmt (&gsi, NULL, find_simtpriv_var_op, NULL))
    2785                 :             :           {
    2786                 :           0 :             if (gimple_clobber_p (gsi_stmt (gsi)))
    2787                 :           0 :               gsi_remove (&gsi, true);
    2788                 :             :             else
    2789                 :           0 :               gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
    2790                 :             :           }
    2791                 :       19255 :   if (vf != 1)
    2792                 :           0 :     cfun->has_force_vectorize_loops = false;
    2793                 :       19255 :   return 0;
    2794                 :             : }
    2795                 :             : 
    2796                 :             : namespace {
    2797                 :             : 
    2798                 :             : const pass_data pass_data_omp_device_lower =
    2799                 :             : {
    2800                 :             :   GIMPLE_PASS, /* type */
    2801                 :             :   "ompdevlow", /* name */
    2802                 :             :   OPTGROUP_OMP, /* optinfo_flags */
    2803                 :             :   TV_NONE, /* tv_id */
    2804                 :             :   PROP_cfg, /* properties_required */
    2805                 :             :   PROP_gimple_lomp_dev, /* properties_provided */
    2806                 :             :   0, /* properties_destroyed */
    2807                 :             :   0, /* todo_flags_start */
    2808                 :             :   TODO_update_ssa, /* todo_flags_finish */
    2809                 :             : };
    2810                 :             : 
    2811                 :             : class pass_omp_device_lower : public gimple_opt_pass
    2812                 :             : {
    2813                 :             : public:
    2814                 :      285617 :   pass_omp_device_lower (gcc::context *ctxt)
    2815                 :      571234 :     : gimple_opt_pass (pass_data_omp_device_lower, ctxt)
    2816                 :             :   {}
    2817                 :             : 
    2818                 :             :   /* opt_pass methods: */
    2819                 :     1420452 :   bool gate (function *fun) final override
    2820                 :             :     {
    2821                 :             : #ifdef ACCEL_COMPILER
    2822                 :             :       bool offload_ind_funcs_p = vec_safe_length (offload_ind_funcs) > 0;
    2823                 :             : #else
    2824                 :     1420452 :       bool offload_ind_funcs_p = false;
    2825                 :             : #endif
    2826                 :     1420452 :       return (!(fun->curr_properties & PROP_gimple_lomp_dev)
    2827                 :     1420452 :               || (flag_openmp
    2828                 :       59601 :                   && (cgraph_node::get (fun->decl)->calls_declare_variant_alt
    2829                 :     1420452 :                       || offload_ind_funcs_p)));
    2830                 :             :     }
    2831                 :       19255 :   unsigned int execute (function *) final override
    2832                 :             :     {
    2833                 :       19255 :       return execute_omp_device_lower ();
    2834                 :             :     }
    2835                 :             : 
    2836                 :             : }; // class pass_expand_omp_ssa
    2837                 :             : 
    2838                 :             : } // anon namespace
    2839                 :             : 
    2840                 :             : gimple_opt_pass *
    2841                 :      285617 : make_pass_omp_device_lower (gcc::context *ctxt)
    2842                 :             : {
    2843                 :      285617 :   return new pass_omp_device_lower (ctxt);
    2844                 :             : }
    2845                 :             : 
    2846                 :             : /* "omp declare target link" handling pass.  */
    2847                 :             : 
    2848                 :             : namespace {
    2849                 :             : 
    2850                 :             : const pass_data pass_data_omp_target_link =
    2851                 :             : {
    2852                 :             :   GIMPLE_PASS,                  /* type */
    2853                 :             :   "omptargetlink",            /* name */
    2854                 :             :   OPTGROUP_OMP,                 /* optinfo_flags */
    2855                 :             :   TV_NONE,                      /* tv_id */
    2856                 :             :   PROP_ssa,                     /* properties_required */
    2857                 :             :   0,                            /* properties_provided */
    2858                 :             :   0,                            /* properties_destroyed */
    2859                 :             :   0,                            /* todo_flags_start */
    2860                 :             :   TODO_update_ssa,              /* todo_flags_finish */
    2861                 :             : };
    2862                 :             : 
    2863                 :             : class pass_omp_target_link : public gimple_opt_pass
    2864                 :             : {
    2865                 :             : public:
    2866                 :      285617 :   pass_omp_target_link (gcc::context *ctxt)
    2867                 :      571234 :     : gimple_opt_pass (pass_data_omp_target_link, ctxt)
    2868                 :             :   {}
    2869                 :             : 
    2870                 :             :   /* opt_pass methods: */
    2871                 :     1420452 :   bool gate (function *fun) final override
    2872                 :             :     {
    2873                 :             : #ifdef ACCEL_COMPILER
    2874                 :             :       return offloading_function_p (fun->decl);
    2875                 :             : #else
    2876                 :     1420452 :       (void) fun;
    2877                 :     1420452 :       return false;
    2878                 :             : #endif
    2879                 :             :     }
    2880                 :             : 
    2881                 :             :   unsigned execute (function *) final override;
    2882                 :             : };
    2883                 :             : 
    2884                 :             : /* Callback for walk_gimple_stmt used to scan for link var operands.  */
    2885                 :             : 
    2886                 :             : static tree
    2887                 :           0 : find_link_var_op (tree *tp, int *walk_subtrees, void *)
    2888                 :             : {
    2889                 :           0 :   tree t = *tp;
    2890                 :             : 
    2891                 :           0 :   if (VAR_P (t)
    2892                 :           0 :       && DECL_HAS_VALUE_EXPR_P (t)
    2893                 :           0 :       && is_global_var (t)
    2894                 :           0 :       && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (t)))
    2895                 :             :     {
    2896                 :           0 :       *walk_subtrees = 0;
    2897                 :           0 :       return t;
    2898                 :             :     }
    2899                 :             : 
    2900                 :             :   return NULL_TREE;
    2901                 :             : }
    2902                 :             : 
    2903                 :             : unsigned
    2904                 :           0 : pass_omp_target_link::execute (function *fun)
    2905                 :             : {
    2906                 :           0 :   basic_block bb;
    2907                 :           0 :   FOR_EACH_BB_FN (bb, fun)
    2908                 :             :     {
    2909                 :           0 :       gimple_stmt_iterator gsi;
    2910                 :           0 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    2911                 :             :         {
    2912                 :           0 :           if (gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_GOMP_TARGET))
    2913                 :             :             {
    2914                 :           0 :               tree dev = gimple_call_arg (gsi_stmt (gsi), 0);
    2915                 :           0 :               tree fn = gimple_call_arg (gsi_stmt (gsi), 1);
    2916                 :           0 :               if (POINTER_TYPE_P (TREE_TYPE (fn)))
    2917                 :           0 :                 fn = TREE_OPERAND (fn, 0);
    2918                 :           0 :               if (TREE_CODE (dev) == INTEGER_CST
    2919                 :           0 :                   && wi::to_wide (dev) == GOMP_DEVICE_HOST_FALLBACK
    2920                 :           0 :                   && lookup_attribute ("omp target device_ancestor_nohost",
    2921                 :           0 :                                        DECL_ATTRIBUTES (fn)) != NULL_TREE)
    2922                 :           0 :                 continue;  /* ancestor:1  */
    2923                 :             :               /* Nullify the second argument of __builtin_GOMP_target_ext.  */
    2924                 :           0 :               gimple_call_set_arg (gsi_stmt (gsi), 1, null_pointer_node);
    2925                 :           0 :               update_stmt (gsi_stmt (gsi));
    2926                 :             :             }
    2927                 :           0 :           if (walk_gimple_stmt (&gsi, NULL, find_link_var_op, NULL))
    2928                 :           0 :             gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
    2929                 :             :         }
    2930                 :             :     }
    2931                 :             : 
    2932                 :           0 :   return 0;
    2933                 :             : }
    2934                 :             : 
    2935                 :             : } // anon namespace
    2936                 :             : 
    2937                 :             : gimple_opt_pass *
    2938                 :      285617 : make_pass_omp_target_link (gcc::context *ctxt)
    2939                 :             : {
    2940                 :      285617 :   return new pass_omp_target_link (ctxt);
    2941                 :             : }
        

Generated by: LCOV version 2.0-1

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.