LCOV - code coverage report
Current view: top level - gcc - omp-offload.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 644 841 76.6 %
Date: 2020-04-04 11:58:09 Functions: 36 47 76.6 %
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-2020 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                 :            : 
      56                 :            : /* Describe the OpenACC looping structure of a function.  The entire
      57                 :            :    function is held in a 'NULL' loop.  */
      58                 :            : 
      59                 :            : struct oacc_loop
      60                 :            : {
      61                 :            :   oacc_loop *parent; /* Containing loop.  */
      62                 :            : 
      63                 :            :   oacc_loop *child; /* First inner loop.  */
      64                 :            : 
      65                 :            :   oacc_loop *sibling; /* Next loop within same parent.  */
      66                 :            : 
      67                 :            :   location_t loc; /* Location of the loop start.  */
      68                 :            : 
      69                 :            :   gcall *marker; /* Initial head marker.  */
      70                 :            : 
      71                 :            :   gcall *heads[GOMP_DIM_MAX];  /* Head marker functions.  */
      72                 :            :   gcall *tails[GOMP_DIM_MAX];  /* Tail marker functions.  */
      73                 :            : 
      74                 :            :   tree routine;  /* Pseudo-loop enclosing a routine.  */
      75                 :            : 
      76                 :            :   unsigned mask;   /* Partitioning mask.  */
      77                 :            :   unsigned e_mask; /* Partitioning of element loops (when tiling).  */
      78                 :            :   unsigned inner;  /* Partitioning of inner loops.  */
      79                 :            :   unsigned flags;  /* Partitioning flags.  */
      80                 :            :   vec<gcall *> ifns;  /* Contained loop abstraction functions.  */
      81                 :            :   tree chunk_size; /* Chunk size.  */
      82                 :            :   gcall *head_end; /* Final marker of head sequence.  */
      83                 :            : };
      84                 :            : 
      85                 :            : /* Holds offload tables with decls.  */
      86                 :            : vec<tree, va_gc> *offload_funcs, *offload_vars;
      87                 :            : 
      88                 :            : /* Return level at which oacc routine may spawn a partitioned loop, or
      89                 :            :    -1 if it is not a routine (i.e. is an offload fn).  */
      90                 :            : 
      91                 :            : int
      92                 :       8542 : oacc_fn_attrib_level (tree attr)
      93                 :            : {
      94                 :       8542 :   tree pos = TREE_VALUE (attr);
      95                 :            : 
      96                 :       8542 :   if (!TREE_PURPOSE (pos))
      97                 :            :     return -1;
      98                 :            : 
      99                 :            :   int ix = 0;
     100                 :       5868 :   for (ix = 0; ix != GOMP_DIM_MAX;
     101                 :       2355 :        ix++, pos = TREE_CHAIN (pos))
     102                 :       2909 :     if (!integer_zerop (TREE_PURPOSE (pos)))
     103                 :            :       break;
     104                 :            : 
     105                 :            :   return ix;
     106                 :            : }
     107                 :            : 
     108                 :            : /* Helper function for omp_finish_file routine.  Takes decls from V_DECLS and
     109                 :            :    adds their addresses and sizes to constructor-vector V_CTOR.  */
     110                 :            : 
     111                 :            : static void
     112                 :          0 : add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls,
     113                 :            :                                          vec<constructor_elt, va_gc> *v_ctor)
     114                 :            : {
     115                 :          0 :   unsigned len = vec_safe_length (v_decls);
     116                 :          0 :   for (unsigned i = 0; i < len; i++)
     117                 :            :     {
     118                 :          0 :       tree it = (*v_decls)[i];
     119                 :          0 :       bool is_var = VAR_P (it);
     120                 :          0 :       bool is_link_var
     121                 :            :         = is_var
     122                 :            : #ifdef ACCEL_COMPILER
     123                 :            :           && DECL_HAS_VALUE_EXPR_P (it)
     124                 :            : #endif
     125                 :          0 :           && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (it));
     126                 :            : 
     127                 :          0 :       tree size = NULL_TREE;
     128                 :          0 :       if (is_var)
     129                 :          0 :         size = fold_convert (const_ptr_type_node, DECL_SIZE_UNIT (it));
     130                 :            : 
     131                 :          0 :       tree addr;
     132                 :          0 :       if (!is_link_var)
     133                 :          0 :         addr = build_fold_addr_expr (it);
     134                 :            :       else
     135                 :            :         {
     136                 :            : #ifdef ACCEL_COMPILER
     137                 :            :           /* For "omp declare target link" vars add address of the pointer to
     138                 :            :              the target table, instead of address of the var.  */
     139                 :            :           tree value_expr = DECL_VALUE_EXPR (it);
     140                 :            :           tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
     141                 :            :           varpool_node::finalize_decl (link_ptr_decl);
     142                 :            :           addr = build_fold_addr_expr (link_ptr_decl);
     143                 :            : #else
     144                 :          0 :           addr = build_fold_addr_expr (it);
     145                 :            : #endif
     146                 :            : 
     147                 :            :           /* Most significant bit of the size marks "omp declare target link"
     148                 :            :              vars in host and target tables.  */
     149                 :          0 :           unsigned HOST_WIDE_INT isize = tree_to_uhwi (size);
     150                 :          0 :           isize |= 1ULL << (int_size_in_bytes (const_ptr_type_node)
     151                 :          0 :                             * BITS_PER_UNIT - 1);
     152                 :          0 :           size = wide_int_to_tree (const_ptr_type_node, isize);
     153                 :            :         }
     154                 :            : 
     155                 :          0 :       CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, addr);
     156                 :          0 :       if (is_var)
     157                 :          0 :         CONSTRUCTOR_APPEND_ELT (v_ctor, NULL_TREE, size);
     158                 :            :     }
     159                 :          0 : }
     160                 :            : 
     161                 :            : /* Create new symbols containing (address, size) pairs for global variables,
     162                 :            :    marked with "omp declare target" attribute, as well as addresses for the
     163                 :            :    functions, which are outlined offloading regions.  */
     164                 :            : void
     165                 :     163841 : omp_finish_file (void)
     166                 :            : {
     167                 :     163841 :   unsigned num_funcs = vec_safe_length (offload_funcs);
     168                 :     163841 :   unsigned num_vars = vec_safe_length (offload_vars);
     169                 :            : 
     170                 :     163841 :   if (num_funcs == 0 && num_vars == 0)
     171                 :     163841 :     return;
     172                 :            : 
     173                 :          0 :   if (targetm_common.have_named_sections)
     174                 :            :     {
     175                 :          0 :       vec<constructor_elt, va_gc> *v_f, *v_v;
     176                 :          0 :       vec_alloc (v_f, num_funcs);
     177                 :          0 :       vec_alloc (v_v, num_vars * 2);
     178                 :            : 
     179                 :          0 :       add_decls_addresses_to_decl_constructor (offload_funcs, v_f);
     180                 :          0 :       add_decls_addresses_to_decl_constructor (offload_vars, v_v);
     181                 :            : 
     182                 :          0 :       tree vars_decl_type = build_array_type_nelts (pointer_sized_int_node,
     183                 :          0 :                                                     num_vars * 2);
     184                 :          0 :       tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node,
     185                 :            :                                                      num_funcs);
     186                 :          0 :       SET_TYPE_ALIGN (vars_decl_type, TYPE_ALIGN (pointer_sized_int_node));
     187                 :          0 :       SET_TYPE_ALIGN (funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node));
     188                 :          0 :       tree ctor_v = build_constructor (vars_decl_type, v_v);
     189                 :          0 :       tree ctor_f = build_constructor (funcs_decl_type, v_f);
     190                 :          0 :       TREE_CONSTANT (ctor_v) = TREE_CONSTANT (ctor_f) = 1;
     191                 :          0 :       TREE_STATIC (ctor_v) = TREE_STATIC (ctor_f) = 1;
     192                 :          0 :       tree funcs_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     193                 :            :                                     get_identifier (".offload_func_table"),
     194                 :            :                                     funcs_decl_type);
     195                 :          0 :       tree vars_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     196                 :            :                                    get_identifier (".offload_var_table"),
     197                 :            :                                    vars_decl_type);
     198                 :          0 :       TREE_STATIC (funcs_decl) = TREE_STATIC (vars_decl) = 1;
     199                 :            :       /* Do not align tables more than TYPE_ALIGN (pointer_sized_int_node),
     200                 :            :          otherwise a joint table in a binary will contain padding between
     201                 :            :          tables from multiple object files.  */
     202                 :          0 :       DECL_USER_ALIGN (funcs_decl) = DECL_USER_ALIGN (vars_decl) = 1;
     203                 :          0 :       SET_DECL_ALIGN (funcs_decl, TYPE_ALIGN (funcs_decl_type));
     204                 :          0 :       SET_DECL_ALIGN (vars_decl, TYPE_ALIGN (vars_decl_type));
     205                 :          0 :       DECL_INITIAL (funcs_decl) = ctor_f;
     206                 :          0 :       DECL_INITIAL (vars_decl) = ctor_v;
     207                 :          0 :       set_decl_section_name (funcs_decl, OFFLOAD_FUNC_TABLE_SECTION_NAME);
     208                 :          0 :       set_decl_section_name (vars_decl, OFFLOAD_VAR_TABLE_SECTION_NAME);
     209                 :            : 
     210                 :          0 :       varpool_node::finalize_decl (vars_decl);
     211                 :          0 :       varpool_node::finalize_decl (funcs_decl);
     212                 :            :     }
     213                 :            :   else
     214                 :            :     {
     215                 :          0 :       for (unsigned i = 0; i < num_funcs; i++)
     216                 :            :         {
     217                 :          0 :           tree it = (*offload_funcs)[i];
     218                 :          0 :           targetm.record_offload_symbol (it);
     219                 :            :         }
     220                 :          0 :       for (unsigned i = 0; i < num_vars; i++)
     221                 :            :         {
     222                 :          0 :           tree it = (*offload_vars)[i];
     223                 :            : #ifdef ACCEL_COMPILER
     224                 :            :           if (DECL_HAS_VALUE_EXPR_P (it)
     225                 :            :               && lookup_attribute ("omp declare target link",
     226                 :            :                                    DECL_ATTRIBUTES (it)))
     227                 :            :             {
     228                 :            :               tree value_expr = DECL_VALUE_EXPR (it);
     229                 :            :               tree link_ptr_decl = TREE_OPERAND (value_expr, 0);
     230                 :            :               targetm.record_offload_symbol (link_ptr_decl);
     231                 :            :               varpool_node::finalize_decl (link_ptr_decl);
     232                 :            :             }
     233                 :            :           else
     234                 :            : #endif
     235                 :          0 :             targetm.record_offload_symbol (it);
     236                 :            :         }
     237                 :            :     }
     238                 :            : }
     239                 :            : 
     240                 :            : /* Call dim_pos (POS == true) or dim_size (POS == false) builtins for
     241                 :            :    axis DIM.  Return a tmp var holding the result.  */
     242                 :            : 
     243                 :            : static tree
     244                 :      25016 : oacc_dim_call (bool pos, int dim, gimple_seq *seq)
     245                 :            : {
     246                 :      25016 :   tree arg = build_int_cst (unsigned_type_node, dim);
     247                 :      25016 :   tree size = create_tmp_var (integer_type_node);
     248                 :      25016 :   enum internal_fn fn = pos ? IFN_GOACC_DIM_POS : IFN_GOACC_DIM_SIZE;
     249                 :      25016 :   gimple *call = gimple_build_call_internal (fn, 1, arg);
     250                 :            : 
     251                 :      25016 :   gimple_call_set_lhs (call, size);
     252                 :      25016 :   gimple_seq_add_stmt (seq, call);
     253                 :            : 
     254                 :      25016 :   return size;
     255                 :            : }
     256                 :            : 
     257                 :            : /* Find the number of threads (POS = false), or thread number (POS =
     258                 :            :    true) for an OpenACC region partitioned as MASK.  Setup code
     259                 :            :    required for the calculation is added to SEQ.  */
     260                 :            : 
     261                 :            : static tree
     262                 :      18269 : oacc_thread_numbers (bool pos, int mask, gimple_seq *seq)
     263                 :            : {
     264                 :      18269 :   tree res = pos ? NULL_TREE : build_int_cst (unsigned_type_node, 1);
     265                 :      18269 :   unsigned ix;
     266                 :            : 
     267                 :            :   /* Start at gang level, and examine relevant dimension indices.  */
     268                 :      73076 :   for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
     269                 :      54807 :     if (GOMP_DIM_MASK (ix) & mask)
     270                 :            :       {
     271                 :      21633 :         if (res)
     272                 :            :           {
     273                 :            :             /* We had an outer index, so scale that by the size of
     274                 :            :                this dimension.  */
     275                 :      14143 :             tree n = oacc_dim_call (false, ix, seq);
     276                 :      14143 :             res = fold_build2 (MULT_EXPR, integer_type_node, res, n);
     277                 :            :           }
     278                 :      21633 :         if (pos)
     279                 :            :           {
     280                 :            :             /* Determine index in this dimension.  */
     281                 :      10873 :             tree id = oacc_dim_call (true, ix, seq);
     282                 :      10873 :             if (res)
     283                 :       3383 :               res = fold_build2 (PLUS_EXPR, integer_type_node, res, id);
     284                 :            :             else
     285                 :            :               res = id;
     286                 :            :           }
     287                 :            :       }
     288                 :            : 
     289                 :      18269 :   if (res == NULL_TREE)
     290                 :       1696 :     res = integer_zero_node;
     291                 :            : 
     292                 :      18269 :   return res;
     293                 :            : }
     294                 :            : 
     295                 :            : /* Transform IFN_GOACC_LOOP calls to actual code.  See
     296                 :            :    expand_oacc_for for where these are generated.  At the vector
     297                 :            :    level, we stride loops, such that each member of a warp will
     298                 :            :    operate on adjacent iterations.  At the worker and gang level,
     299                 :            :    each gang/warp executes a set of contiguous iterations.  Chunking
     300                 :            :    can override this such that each iteration engine executes a
     301                 :            :    contiguous chunk, and then moves on to stride to the next chunk.  */
     302                 :            : 
     303                 :            : static void
     304                 :      36153 : oacc_xform_loop (gcall *call)
     305                 :            : {
     306                 :      36153 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
     307                 :      36153 :   enum ifn_goacc_loop_kind code
     308                 :      36153 :     = (enum ifn_goacc_loop_kind) TREE_INT_CST_LOW (gimple_call_arg (call, 0));
     309                 :      36153 :   tree dir = gimple_call_arg (call, 1);
     310                 :      36153 :   tree range = gimple_call_arg (call, 2);
     311                 :      36153 :   tree step = gimple_call_arg (call, 3);
     312                 :      36153 :   tree chunk_size = NULL_TREE;
     313                 :      36153 :   unsigned mask = (unsigned) TREE_INT_CST_LOW (gimple_call_arg (call, 5));
     314                 :      36153 :   tree lhs = gimple_call_lhs (call);
     315                 :      36153 :   tree type = NULL_TREE;
     316                 :      36153 :   tree diff_type = TREE_TYPE (range);
     317                 :      36153 :   tree r = NULL_TREE;
     318                 :      36153 :   gimple_seq seq = NULL;
     319                 :      36153 :   bool chunking = false, striding = true;
     320                 :      36153 :   unsigned outer_mask = mask & (~mask + 1); // Outermost partitioning
     321                 :      36153 :   unsigned inner_mask = mask & ~outer_mask; // Inner partitioning (if any)
     322                 :            : 
     323                 :            :   /* Skip lowering if return value of IFN_GOACC_LOOP call is not used.  */
     324                 :      36153 :   if (!lhs)
     325                 :            :     {
     326                 :        125 :       gsi_replace_with_seq (&gsi, seq, true);
     327                 :        125 :       return;
     328                 :            :     }
     329                 :            : 
     330                 :      36028 :   type = TREE_TYPE (lhs);
     331                 :            : 
     332                 :            : #ifdef ACCEL_COMPILER
     333                 :            :   chunk_size = gimple_call_arg (call, 4);
     334                 :            :   if (integer_minus_onep (chunk_size)  /* Force static allocation.  */
     335                 :            :       || integer_zerop (chunk_size))   /* Default (also static).  */
     336                 :            :     {
     337                 :            :       /* If we're at the gang level, we want each to execute a
     338                 :            :          contiguous run of iterations.  Otherwise we want each element
     339                 :            :          to stride.  */
     340                 :            :       striding = !(outer_mask & GOMP_DIM_MASK (GOMP_DIM_GANG));
     341                 :            :       chunking = false;
     342                 :            :     }
     343                 :            :   else
     344                 :            :     {
     345                 :            :       /* Chunk of size 1 is striding.  */
     346                 :            :       striding = integer_onep (chunk_size);
     347                 :            :       chunking = !striding;
     348                 :            :     }
     349                 :            : #endif
     350                 :            : 
     351                 :            :   /* striding=true, chunking=true
     352                 :            :        -> invalid.
     353                 :            :      striding=true, chunking=false
     354                 :            :        -> chunks=1
     355                 :            :      striding=false,chunking=true
     356                 :            :        -> chunks=ceil (range/(chunksize*threads*step))
     357                 :            :      striding=false,chunking=false
     358                 :            :        -> chunk_size=ceil(range/(threads*step)),chunks=1  */
     359                 :      36028 :   push_gimplify_context (true);
     360                 :            : 
     361                 :      36028 :   switch (code)
     362                 :            :     {
     363                 :          0 :     default: gcc_unreachable ();
     364                 :            : 
     365                 :       8578 :     case IFN_GOACC_LOOP_CHUNKS:
     366                 :       8578 :       if (!chunking)
     367                 :       8578 :         r = build_int_cst (type, 1);
     368                 :            :       else
     369                 :            :         {
     370                 :            :           /* chunk_max
     371                 :            :              = (range - dir) / (chunks * step * num_threads) + dir  */
     372                 :            :           tree per = oacc_thread_numbers (false, mask, &seq);
     373                 :            :           per = fold_convert (type, per);
     374                 :            :           chunk_size = fold_convert (type, chunk_size);
     375                 :            :           per = fold_build2 (MULT_EXPR, type, per, chunk_size);
     376                 :            :           per = fold_build2 (MULT_EXPR, type, per, step);
     377                 :            :           r = build2 (MINUS_EXPR, type, range, dir);
     378                 :            :           r = build2 (PLUS_EXPR, type, r, per);
     379                 :            :           r = build2 (TRUNC_DIV_EXPR, type, r, per);
     380                 :            :         }
     381                 :            :       break;
     382                 :            : 
     383                 :       9083 :     case IFN_GOACC_LOOP_STEP:
     384                 :       9083 :       {
     385                 :            :         /* If striding, step by the entire compute volume, otherwise
     386                 :            :            step by the inner volume.  */
     387                 :       9083 :         unsigned volume = striding ? mask : inner_mask;
     388                 :            : 
     389                 :       9083 :         r = oacc_thread_numbers (false, volume, &seq);
     390                 :       9083 :         r = build2 (MULT_EXPR, type, fold_convert (type, r), step);
     391                 :            :       }
     392                 :       9083 :       break;
     393                 :            : 
     394                 :       9186 :     case IFN_GOACC_LOOP_OFFSET:
     395                 :            :       /* Enable vectorization on non-SIMT targets.  */
     396                 :       9186 :       if (!targetm.simt.vf
     397                 :       9186 :           && outer_mask == GOMP_DIM_MASK (GOMP_DIM_VECTOR)
     398                 :            :           /* If not -fno-tree-loop-vectorize, hint that we want to vectorize
     399                 :            :              the loop.  */
     400                 :       1632 :           && (flag_tree_loop_vectorize
     401                 :       1506 :               || !global_options_set.x_flag_tree_loop_vectorize))
     402                 :            :         {
     403                 :       1632 :           basic_block bb = gsi_bb (gsi);
     404                 :       1632 :           class loop *parent = bb->loop_father;
     405                 :       1632 :           class loop *body = parent->inner;
     406                 :            : 
     407                 :       1632 :           parent->force_vectorize = true;
     408                 :       1632 :           parent->safelen = INT_MAX;
     409                 :            : 
     410                 :            :           /* "Chunking loops" may have inner loops.  */
     411                 :       1632 :           if (parent->inner)
     412                 :            :             {
     413                 :       1620 :               body->force_vectorize = true;
     414                 :       1620 :               body->safelen = INT_MAX;
     415                 :            :             }
     416                 :            : 
     417                 :       1632 :           cfun->has_force_vectorize_loops = true;
     418                 :            :         }
     419                 :       9186 :       if (striding)
     420                 :            :         {
     421                 :       9186 :           r = oacc_thread_numbers (true, mask, &seq);
     422                 :       9186 :           r = fold_convert (diff_type, r);
     423                 :            :         }
     424                 :            :       else
     425                 :            :         {
     426                 :            :           tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
     427                 :            :           tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
     428                 :            :           tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
     429                 :            :                                      inner_size, outer_size);
     430                 :            : 
     431                 :            :           volume = fold_convert (diff_type, volume);
     432                 :            :           if (chunking)
     433                 :            :             chunk_size = fold_convert (diff_type, chunk_size);
     434                 :            :           else
     435                 :            :             {
     436                 :            :               tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
     437                 :            : 
     438                 :            :               chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
     439                 :            :               chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
     440                 :            :               chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
     441                 :            :             }
     442                 :            : 
     443                 :            :           tree span = build2 (MULT_EXPR, diff_type, chunk_size,
     444                 :            :                               fold_convert (diff_type, inner_size));
     445                 :            :           r = oacc_thread_numbers (true, outer_mask, &seq);
     446                 :            :           r = fold_convert (diff_type, r);
     447                 :            :           r = build2 (MULT_EXPR, diff_type, r, span);
     448                 :            : 
     449                 :            :           tree inner = oacc_thread_numbers (true, inner_mask, &seq);
     450                 :            :           inner = fold_convert (diff_type, inner);
     451                 :            :           r = fold_build2 (PLUS_EXPR, diff_type, r, inner);
     452                 :            : 
     453                 :            :           if (chunking)
     454                 :            :             {
     455                 :            :               tree chunk = fold_convert (diff_type, gimple_call_arg (call, 6));
     456                 :            :               tree per
     457                 :            :                 = fold_build2 (MULT_EXPR, diff_type, volume, chunk_size);
     458                 :            :               per = build2 (MULT_EXPR, diff_type, per, chunk);
     459                 :            : 
     460                 :            :               r = build2 (PLUS_EXPR, diff_type, r, per);
     461                 :            :             }
     462                 :            :         }
     463                 :       9186 :       r = fold_build2 (MULT_EXPR, diff_type, r, step);
     464                 :       9186 :       if (type != diff_type)
     465                 :        197 :         r = fold_convert (type, r);
     466                 :            :       break;
     467                 :            : 
     468                 :       9181 :     case IFN_GOACC_LOOP_BOUND:
     469                 :       9181 :       if (striding)
     470                 :       9181 :         r = range;
     471                 :            :       else
     472                 :            :         {
     473                 :            :           tree inner_size = oacc_thread_numbers (false, inner_mask, &seq);
     474                 :            :           tree outer_size = oacc_thread_numbers (false, outer_mask, &seq);
     475                 :            :           tree volume = fold_build2 (MULT_EXPR, TREE_TYPE (inner_size),
     476                 :            :                                      inner_size, outer_size);
     477                 :            : 
     478                 :            :           volume = fold_convert (diff_type, volume);
     479                 :            :           if (chunking)
     480                 :            :             chunk_size = fold_convert (diff_type, chunk_size);
     481                 :            :           else
     482                 :            :             {
     483                 :            :               tree per = fold_build2 (MULT_EXPR, diff_type, volume, step);
     484                 :            : 
     485                 :            :               chunk_size = build2 (MINUS_EXPR, diff_type, range, dir);
     486                 :            :               chunk_size = build2 (PLUS_EXPR, diff_type, chunk_size, per);
     487                 :            :               chunk_size = build2 (TRUNC_DIV_EXPR, diff_type, chunk_size, per);
     488                 :            :             }
     489                 :            : 
     490                 :            :           tree span = build2 (MULT_EXPR, diff_type, chunk_size,
     491                 :            :                               fold_convert (diff_type, inner_size));
     492                 :            : 
     493                 :            :           r = fold_build2 (MULT_EXPR, diff_type, span, step);
     494                 :            : 
     495                 :            :           tree offset = gimple_call_arg (call, 6);
     496                 :            :           r = build2 (PLUS_EXPR, diff_type, r,
     497                 :            :                       fold_convert (diff_type, offset));
     498                 :            :           r = build2 (integer_onep (dir) ? MIN_EXPR : MAX_EXPR,
     499                 :            :                       diff_type, r, range);
     500                 :            :         }
     501                 :       9181 :       if (diff_type != type)
     502                 :        197 :         r = fold_convert (type, r);
     503                 :            :       break;
     504                 :            :     }
     505                 :            : 
     506                 :      36028 :   gimplify_assign (lhs, r, &seq);
     507                 :            : 
     508                 :      36028 :   pop_gimplify_context (NULL);
     509                 :            : 
     510                 :      36028 :   gsi_replace_with_seq (&gsi, seq, true);
     511                 :            : }
     512                 :            : 
     513                 :            : /* Transform a GOACC_TILE call.  Determines the element loop span for
     514                 :            :    the specified loop of the nest.  This is 1 if we're not tiling.
     515                 :            :    
     516                 :            :    GOACC_TILE (collapse_count, loop_no, tile_arg, gwv_tile, gwv_element);  */
     517                 :            : 
     518                 :            : static void
     519                 :        271 : oacc_xform_tile (gcall *call)
     520                 :            : {
     521                 :        271 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
     522                 :        271 :   unsigned collapse = tree_to_uhwi (gimple_call_arg (call, 0));
     523                 :            :   /* Inner loops have higher loop_nos.  */
     524                 :        271 :   unsigned loop_no = tree_to_uhwi (gimple_call_arg (call, 1));
     525                 :        271 :   tree tile_size = gimple_call_arg (call, 2);
     526                 :        271 :   unsigned e_mask = tree_to_uhwi (gimple_call_arg (call, 4));
     527                 :        271 :   tree lhs = gimple_call_lhs (call);
     528                 :        271 :   tree type = TREE_TYPE (lhs);
     529                 :        271 :   gimple_seq seq = NULL;
     530                 :        271 :   tree span = build_int_cst (type, 1);
     531                 :            : 
     532                 :        271 :   gcc_assert (!(e_mask
     533                 :            :                 & ~(GOMP_DIM_MASK (GOMP_DIM_VECTOR)
     534                 :            :                     | GOMP_DIM_MASK (GOMP_DIM_WORKER))));
     535                 :        271 :   push_gimplify_context (!seen_error ());
     536                 :            : 
     537                 :            : #ifndef ACCEL_COMPILER
     538                 :            :   /* Partitioning disabled on host compilers.  */
     539                 :        271 :   e_mask = 0;
     540                 :            : #endif
     541                 :        271 :   if (!e_mask)
     542                 :            :     /* Not paritioning.  */
     543                 :        271 :     span = integer_one_node;
     544                 :            :   else if (!integer_zerop (tile_size))
     545                 :            :     /* User explicitly specified size.  */
     546                 :            :     span = tile_size;
     547                 :            :   else
     548                 :            :     {
     549                 :            :       /* Pick a size based on the paritioning of the element loop and
     550                 :            :          the number of loop nests.  */
     551                 :            :       tree first_size = NULL_TREE;
     552                 :            :       tree second_size = NULL_TREE;
     553                 :            : 
     554                 :            :       if (e_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR))
     555                 :            :         first_size = oacc_dim_call (false, GOMP_DIM_VECTOR, &seq);
     556                 :            :       if (e_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER))
     557                 :            :         second_size = oacc_dim_call (false, GOMP_DIM_WORKER, &seq);
     558                 :            : 
     559                 :            :       if (!first_size)
     560                 :            :         {
     561                 :            :           first_size = second_size;
     562                 :            :           second_size = NULL_TREE;
     563                 :            :         }
     564                 :            : 
     565                 :            :       if (loop_no + 1 == collapse)
     566                 :            :         {
     567                 :            :           span = first_size;
     568                 :            :           if (!loop_no && second_size)
     569                 :            :             span = fold_build2 (MULT_EXPR, TREE_TYPE (span),
     570                 :            :                                 span, second_size);
     571                 :            :         }
     572                 :            :       else if (loop_no + 2 == collapse)
     573                 :            :         span = second_size;
     574                 :            :       else
     575                 :            :         span = NULL_TREE;
     576                 :            : 
     577                 :            :       if (!span)
     578                 :            :         /* There's no obvious element size for this loop.  Options
     579                 :            :            are 1, first_size or some non-unity constant (32 is my
     580                 :            :            favourite).   We should gather some statistics.  */
     581                 :            :         span = first_size;
     582                 :            :     }
     583                 :            : 
     584                 :        271 :   span = fold_convert (type, span);
     585                 :        271 :   gimplify_assign (lhs, span, &seq);
     586                 :            : 
     587                 :        271 :   pop_gimplify_context (NULL);
     588                 :            : 
     589                 :        271 :   gsi_replace_with_seq (&gsi, seq, true);
     590                 :        271 : }
     591                 :            : 
     592                 :            : /* Default partitioned and minimum partitioned dimensions.  */
     593                 :            : 
     594                 :            : static int oacc_default_dims[GOMP_DIM_MAX];
     595                 :            : static int oacc_min_dims[GOMP_DIM_MAX];
     596                 :            : 
     597                 :            : int
     598                 :          0 : oacc_get_default_dim (int dim)
     599                 :            : {
     600                 :          0 :   gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
     601                 :          0 :   return oacc_default_dims[dim];
     602                 :            : }
     603                 :            : 
     604                 :            : int
     605                 :          0 : oacc_get_min_dim (int dim)
     606                 :            : {
     607                 :          0 :   gcc_assert (0 <= dim && dim < GOMP_DIM_MAX);
     608                 :          0 :   return oacc_min_dims[dim];
     609                 :            : }
     610                 :            : 
     611                 :            : /* Parse the default dimension parameter.  This is a set of
     612                 :            :    :-separated optional compute dimensions.  Each specified dimension
     613                 :            :    is a positive integer.  When device type support is added, it is
     614                 :            :    planned to be a comma separated list of such compute dimensions,
     615                 :            :    with all but the first prefixed by the colon-terminated device
     616                 :            :    type.  */
     617                 :            : 
     618                 :            : static void
     619                 :       1929 : oacc_parse_default_dims (const char *dims)
     620                 :            : {
     621                 :       1929 :   int ix;
     622                 :            : 
     623                 :       7716 :   for (ix = GOMP_DIM_MAX; ix--;)
     624                 :            :     {
     625                 :       5787 :       oacc_default_dims[ix] = -1;
     626                 :       5787 :       oacc_min_dims[ix] = 1;
     627                 :            :     }
     628                 :            : 
     629                 :            : #ifndef ACCEL_COMPILER
     630                 :            :   /* Cannot be overridden on the host.  */
     631                 :       1929 :   dims = NULL;
     632                 :            : #endif
     633                 :       1929 :   if (dims)
     634                 :            :     {
     635                 :            :       const char *pos = dims;
     636                 :            : 
     637                 :            :       for (ix = 0; *pos && ix != GOMP_DIM_MAX; ix++)
     638                 :            :         {
     639                 :            :           if (ix)
     640                 :            :             {
     641                 :            :               if (*pos != ':')
     642                 :            :                 goto malformed;
     643                 :            :               pos++;
     644                 :            :             }
     645                 :            : 
     646                 :            :           if (*pos != ':')
     647                 :            :             {
     648                 :            :               long val;
     649                 :            :               const char *eptr;
     650                 :            : 
     651                 :            :               errno = 0;
     652                 :            :               val = strtol (pos, CONST_CAST (char **, &eptr), 10);
     653                 :            :               if (errno || val <= 0 || (int) val != val)
     654                 :            :                 goto malformed;
     655                 :            :               pos = eptr;
     656                 :            :               oacc_default_dims[ix] = (int) val;
     657                 :            :             }
     658                 :            :         }
     659                 :            :       if (*pos)
     660                 :            :         {
     661                 :            :         malformed:
     662                 :            :           error_at (UNKNOWN_LOCATION,
     663                 :            :                     "%<-fopenacc-dim%> operand is malformed at %qs", pos);
     664                 :            :         }
     665                 :            :     }
     666                 :            : 
     667                 :            :   /* Allow the backend to validate the dimensions.  */
     668                 :       1929 :   targetm.goacc.validate_dims (NULL_TREE, oacc_default_dims, -1, 0);
     669                 :       1929 :   targetm.goacc.validate_dims (NULL_TREE, oacc_min_dims, -2, 0);
     670                 :       1929 : }
     671                 :            : 
     672                 :            : /* Validate and update the dimensions for offloaded FN.  ATTRS is the
     673                 :            :    raw attribute.  DIMS is an array of dimensions, which is filled in.
     674                 :            :    LEVEL is the partitioning level of a routine, or -1 for an offload
     675                 :            :    region itself.  USED is the mask of partitioned execution in the
     676                 :            :    function.  */
     677                 :            : 
     678                 :            : static void
     679                 :       7725 : oacc_validate_dims (tree fn, tree attrs, int *dims, int level, unsigned used)
     680                 :            : {
     681                 :       7725 :   tree purpose[GOMP_DIM_MAX];
     682                 :       7725 :   unsigned ix;
     683                 :       7725 :   tree pos = TREE_VALUE (attrs);
     684                 :            : 
     685                 :            :   /* Make sure the attribute creator attached the dimension
     686                 :            :      information.  */
     687                 :       7725 :   gcc_assert (pos);
     688                 :            : 
     689                 :      30900 :   for (ix = 0; ix != GOMP_DIM_MAX; ix++)
     690                 :            :     {
     691                 :      23175 :       purpose[ix] = TREE_PURPOSE (pos);
     692                 :      23175 :       tree val = TREE_VALUE (pos);
     693                 :      23175 :       dims[ix] = val ? TREE_INT_CST_LOW (val) : -1;
     694                 :      23175 :       pos = TREE_CHAIN (pos);
     695                 :            :     }
     696                 :            : 
     697                 :       7725 :   bool changed = targetm.goacc.validate_dims (fn, dims, level, used);
     698                 :            : 
     699                 :            :   /* Default anything left to 1 or a partitioned default.  */
     700                 :      30900 :   for (ix = 0; ix != GOMP_DIM_MAX; ix++)
     701                 :      23175 :     if (dims[ix] < 0)
     702                 :            :       {
     703                 :            :         /* The OpenACC spec says 'If the [num_gangs] clause is not
     704                 :            :            specified, an implementation-defined default will be used;
     705                 :            :            the default may depend on the code within the construct.'
     706                 :            :            (2.5.6).  Thus an implementation is free to choose
     707                 :            :            non-unity default for a parallel region that doesn't have
     708                 :            :            any gang-partitioned loops.  However, it appears that there
     709                 :            :            is a sufficient body of user code that expects non-gang
     710                 :            :            partitioned regions to not execute in gang-redundant mode.
     711                 :            :            So we (a) don't warn about the non-portability and (b) pick
     712                 :            :            the minimum permissible dimension size when there is no
     713                 :            :            partitioned execution.  Otherwise we pick the global
     714                 :            :            default for the dimension, which the user can control.  The
     715                 :            :            same wording and logic applies to num_workers and
     716                 :            :            vector_length, however the worker- or vector- single
     717                 :            :            execution doesn't have the same impact as gang-redundant
     718                 :            :            execution.  (If the minimum gang-level partioning is not 1,
     719                 :            :            the target is probably too confusing.)  */
     720                 :          0 :         dims[ix] = (used & GOMP_DIM_MASK (ix)
     721                 :          0 :                     ? oacc_default_dims[ix] : oacc_min_dims[ix]);
     722                 :          0 :         changed = true;
     723                 :            :       }
     724                 :            : 
     725                 :       7725 :   if (changed)
     726                 :            :     {
     727                 :            :       /* Replace the attribute with new values.  */
     728                 :            :       pos = NULL_TREE;
     729                 :      30140 :       for (ix = GOMP_DIM_MAX; ix--;)
     730                 :      22605 :         pos = tree_cons (purpose[ix],
     731                 :      22605 :                          build_int_cst (integer_type_node, dims[ix]), pos);
     732                 :       7535 :       oacc_replace_fn_attrib (fn, pos);
     733                 :            :     }
     734                 :       7725 : }
     735                 :            : 
     736                 :            : /* Create an empty OpenACC loop structure at LOC.  */
     737                 :            : 
     738                 :            : static oacc_loop *
     739                 :      16259 : new_oacc_loop_raw (oacc_loop *parent, location_t loc)
     740                 :            : {
     741                 :       8491 :   oacc_loop *loop = XCNEW (oacc_loop);
     742                 :            : 
     743                 :      16259 :   loop->parent = parent;
     744                 :            : 
     745                 :       8491 :   if (parent)
     746                 :            :     {
     747                 :       8491 :       loop->sibling = parent->child;
     748                 :       8491 :       parent->child = loop;
     749                 :            :     }
     750                 :            : 
     751                 :      16259 :   loop->loc = loc;
     752                 :      16259 :   return loop;
     753                 :            : }
     754                 :            : 
     755                 :            : /* Create an outermost, dummy OpenACC loop for offloaded function
     756                 :            :    DECL.  */
     757                 :            : 
     758                 :            : static oacc_loop *
     759                 :       7725 : new_oacc_loop_outer (tree decl)
     760                 :            : {
     761                 :       7725 :   return new_oacc_loop_raw (NULL, DECL_SOURCE_LOCATION (decl));
     762                 :            : }
     763                 :            : 
     764                 :            : /* Start a new OpenACC loop  structure beginning at head marker HEAD.
     765                 :            :    Link into PARENT loop.  Return the new loop.  */
     766                 :            : 
     767                 :            : static oacc_loop *
     768                 :       7674 : new_oacc_loop (oacc_loop *parent, gcall *marker)
     769                 :            : {
     770                 :       7674 :   oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (marker));
     771                 :            : 
     772                 :       7674 :   loop->marker = marker;
     773                 :            : 
     774                 :            :   /* TODO: This is where device_type flattening would occur for the loop
     775                 :            :      flags.  */
     776                 :            : 
     777                 :       7674 :   loop->flags = TREE_INT_CST_LOW (gimple_call_arg (marker, 3));
     778                 :            : 
     779                 :       7674 :   tree chunk_size = integer_zero_node;
     780                 :       7674 :   if (loop->flags & OLF_GANG_STATIC)
     781                 :        131 :     chunk_size = gimple_call_arg (marker, 4);
     782                 :       7674 :   loop->chunk_size = chunk_size;
     783                 :            : 
     784                 :       7674 :   return loop;
     785                 :            : }
     786                 :            : 
     787                 :            : /* Create a dummy loop encompassing a call to a openACC routine.
     788                 :            :    Extract the routine's partitioning requirements.  */
     789                 :            : 
     790                 :            : static void
     791                 :        817 : new_oacc_loop_routine (oacc_loop *parent, gcall *call, tree decl, tree attrs)
     792                 :            : {
     793                 :        817 :   oacc_loop *loop = new_oacc_loop_raw (parent, gimple_location (call));
     794                 :        817 :   int level = oacc_fn_attrib_level (attrs);
     795                 :            : 
     796                 :        817 :   gcc_assert (level >= 0);
     797                 :            : 
     798                 :        817 :   loop->marker = call;
     799                 :        817 :   loop->routine = decl;
     800                 :        817 :   loop->mask = ((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1)
     801                 :        817 :                 ^ (GOMP_DIM_MASK (level) - 1));
     802                 :        817 : }
     803                 :            : 
     804                 :            : /* Finish off the current OpenACC loop ending at tail marker TAIL.
     805                 :            :    Return the parent loop.  */
     806                 :            : 
     807                 :            : static oacc_loop *
     808                 :       7674 : finish_oacc_loop (oacc_loop *loop)
     809                 :            : {
     810                 :            :   /* If the loop has been collapsed, don't partition it.  */
     811                 :          0 :   if (loop->ifns.is_empty ())
     812                 :          0 :     loop->mask = loop->flags = 0;
     813                 :       7674 :   return loop->parent;
     814                 :            : }
     815                 :            : 
     816                 :            : /* Free all OpenACC loop structures within LOOP (inclusive).  */
     817                 :            : 
     818                 :            : static void
     819                 :      16259 : free_oacc_loop (oacc_loop *loop)
     820                 :            : {
     821                 :      16259 :   if (loop->sibling)
     822                 :       1718 :     free_oacc_loop (loop->sibling);
     823                 :      16259 :   if (loop->child)
     824                 :       6773 :     free_oacc_loop (loop->child);
     825                 :            : 
     826                 :      16259 :   loop->ifns.release ();
     827                 :      16259 :   free (loop);
     828                 :      16259 : }
     829                 :            : 
     830                 :            : /* Dump out the OpenACC loop head or tail beginning at FROM.  */
     831                 :            : 
     832                 :            : static void
     833                 :         54 : dump_oacc_loop_part (FILE *file, gcall *from, int depth,
     834                 :            :                      const char *title, int level)
     835                 :            : {
     836                 :         54 :   enum ifn_unique_kind kind
     837                 :         54 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
     838                 :            : 
     839                 :         54 :   fprintf (file, "%*s%s-%d:\n", depth * 2, "", title, level);
     840                 :         54 :   for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
     841                 :            :     {
     842                 :        162 :       gimple *stmt = gsi_stmt (gsi);
     843                 :            : 
     844                 :        162 :       if (gimple_call_internal_p (stmt, IFN_UNIQUE))
     845                 :            :         {
     846                 :        162 :           enum ifn_unique_kind k
     847                 :        162 :             = ((enum ifn_unique_kind) TREE_INT_CST_LOW
     848                 :        162 :                (gimple_call_arg (stmt, 0)));
     849                 :            : 
     850                 :        162 :           if (k == kind && stmt != from)
     851                 :            :             break;
     852                 :            :         }
     853                 :        108 :       print_gimple_stmt (file, stmt, depth * 2 + 2);
     854                 :            : 
     855                 :        108 :       gsi_next (&gsi);
     856                 :        216 :       while (gsi_end_p (gsi))
     857                 :        216 :         gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
     858                 :            :     }
     859                 :         54 : }
     860                 :            : 
     861                 :            : /* Dump OpenACC loop LOOP, its children, and its siblings.  */
     862                 :            : 
     863                 :            : static void
     864                 :         39 : dump_oacc_loop (FILE *file, oacc_loop *loop, int depth)
     865                 :            : {
     866                 :         39 :   int ix;
     867                 :            : 
     868                 :         39 :   fprintf (file, "%*sLoop %x(%x) %s:%u\n", depth * 2, "",
     869                 :            :            loop->flags, loop->mask,
     870                 :         39 :            LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc));
     871                 :            : 
     872                 :         39 :   if (loop->marker)
     873                 :         14 :     print_gimple_stmt (file, loop->marker, depth * 2);
     874                 :            : 
     875                 :         39 :   if (loop->routine)
     876                 :          0 :     fprintf (file, "%*sRoutine %s:%u:%s\n",
     877                 :          0 :              depth * 2, "", DECL_SOURCE_FILE (loop->routine),
     878                 :          0 :              DECL_SOURCE_LINE (loop->routine),
     879                 :          0 :              IDENTIFIER_POINTER (DECL_NAME (loop->routine)));
     880                 :            : 
     881                 :        156 :   for (ix = GOMP_DIM_GANG; ix != GOMP_DIM_MAX; ix++)
     882                 :        117 :     if (loop->heads[ix])
     883                 :         27 :       dump_oacc_loop_part (file, loop->heads[ix], depth, "Head", ix);
     884                 :        156 :   for (ix = GOMP_DIM_MAX; ix--;)
     885                 :        117 :     if (loop->tails[ix])
     886                 :         27 :       dump_oacc_loop_part (file, loop->tails[ix], depth, "Tail", ix);
     887                 :            : 
     888                 :         39 :   if (loop->child)
     889                 :         14 :     dump_oacc_loop (file, loop->child, depth + 1);
     890                 :         39 :   if (loop->sibling)
     891                 :            :     dump_oacc_loop (file, loop->sibling, depth);
     892                 :         39 : }
     893                 :            : 
     894                 :            : void debug_oacc_loop (oacc_loop *);
     895                 :            : 
     896                 :            : /* Dump loops to stderr.  */
     897                 :            : 
     898                 :            : DEBUG_FUNCTION void
     899                 :          0 : debug_oacc_loop (oacc_loop *loop)
     900                 :            : {
     901                 :          0 :   dump_oacc_loop (stderr, loop, 0);
     902                 :          0 : }
     903                 :            : 
     904                 :            : /* Provide diagnostics on OpenACC loop LOOP, its children, and its
     905                 :            :    siblings.  */
     906                 :            : 
     907                 :            : static void
     908                 :        489 : inform_oacc_loop (const oacc_loop *loop)
     909                 :            : {
     910                 :        978 :   const char *gang
     911                 :        489 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_GANG) ? " gang" : "";
     912                 :        978 :   const char *worker
     913                 :        489 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_WORKER) ? " worker" : "";
     914                 :        978 :   const char *vector
     915                 :        489 :     = loop->mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR) ? " vector" : "";
     916                 :        489 :   const char *seq = loop->mask == 0 ? " seq" : "";
     917                 :        489 :   const dump_user_location_t loc
     918                 :        489 :     = dump_user_location_t::from_location_t (loop->loc);
     919                 :        489 :   dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
     920                 :            :                    "assigned OpenACC%s%s%s%s loop parallelism\n", gang, worker,
     921                 :            :                    vector, seq);
     922                 :            : 
     923                 :        489 :   if (loop->child)
     924                 :        189 :     inform_oacc_loop (loop->child);
     925                 :        489 :   if (loop->sibling)
     926                 :         26 :     inform_oacc_loop (loop->sibling);
     927                 :        489 : }
     928                 :            : 
     929                 :            : /* DFS walk of basic blocks BB onwards, creating OpenACC loop
     930                 :            :    structures as we go.  By construction these loops are properly
     931                 :            :    nested.  */
     932                 :            : 
     933                 :            : static void
     934                 :     136341 : oacc_loop_discover_walk (oacc_loop *loop, basic_block bb)
     935                 :            : {
     936                 :     136341 :   int marker = 0;
     937                 :     136341 :   int remaining = 0;
     938                 :            : 
     939                 :     136341 :   if (bb->flags & BB_VISITED)
     940                 :      31009 :     return;
     941                 :            : 
     942                 :     105332 :  follow:
     943                 :     157428 :   bb->flags |= BB_VISITED;
     944                 :            : 
     945                 :            :   /* Scan for loop markers.  */
     946                 :     618104 :   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
     947                 :     303248 :        gsi_next (&gsi))
     948                 :            :     {
     949                 :     303248 :       gimple *stmt = gsi_stmt (gsi);
     950                 :            : 
     951                 :     303248 :       if (!is_gimple_call (stmt))
     952                 :     174275 :         continue;
     953                 :            : 
     954                 :     132871 :       gcall *call = as_a <gcall *> (stmt);
     955                 :            : 
     956                 :            :       /* If this is a routine, make a dummy loop for it.  */
     957                 :     132871 :       if (tree decl = gimple_call_fndecl (call))
     958                 :       3897 :         if (tree attrs = oacc_get_fn_attrib (decl))
     959                 :            :           {
     960                 :        817 :             gcc_assert (!marker);
     961                 :        817 :             new_oacc_loop_routine (loop, call, decl, attrs);
     962                 :            :           }
     963                 :            : 
     964                 :     132871 :       if (!gimple_call_internal_p (call))
     965                 :       3898 :         continue;
     966                 :            : 
     967                 :     128973 :       switch (gimple_call_internal_fn (call))
     968                 :            :         {
     969                 :            :         default:
     970                 :            :           break;
     971                 :            : 
     972                 :      36424 :         case IFN_GOACC_LOOP:
     973                 :      36424 :         case IFN_GOACC_TILE:
     974                 :            :           /* Record the abstraction function, so we can manipulate it
     975                 :            :              later.  */
     976                 :      36424 :           loop->ifns.safe_push (call);
     977                 :      36424 :           break;
     978                 :            : 
     979                 :      67444 :         case IFN_UNIQUE:
     980                 :      67444 :           enum ifn_unique_kind kind
     981                 :      67444 :             = (enum ifn_unique_kind) (TREE_INT_CST_LOW
     982                 :      67444 :                                       (gimple_call_arg (call, 0)));
     983                 :      67444 :           if (kind == IFN_UNIQUE_OACC_HEAD_MARK
     984                 :      67444 :               || kind == IFN_UNIQUE_OACC_TAIL_MARK)
     985                 :            :             {
     986                 :      41396 :               if (gimple_call_num_args (call) == 2)
     987                 :            :                 {
     988                 :      15348 :                   gcc_assert (marker && !remaining);
     989                 :      15348 :                   marker = 0;
     990                 :      15348 :                   if (kind == IFN_UNIQUE_OACC_TAIL_MARK)
     991                 :      15348 :                     loop = finish_oacc_loop (loop);
     992                 :            :                   else
     993                 :       7674 :                     loop->head_end = call;
     994                 :            :                 }
     995                 :            :               else
     996                 :            :                 {
     997                 :      26048 :                   int count = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
     998                 :            : 
     999                 :      26048 :                   if (!marker)
    1000                 :            :                     {
    1001                 :      15348 :                       if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
    1002                 :       7674 :                         loop = new_oacc_loop (loop, call);
    1003                 :            :                       remaining = count;
    1004                 :            :                     }
    1005                 :      26048 :                   gcc_assert (count == remaining);
    1006                 :      26048 :                   if (remaining)
    1007                 :            :                     {
    1008                 :      26048 :                       remaining--;
    1009                 :      26048 :                       if (kind == IFN_UNIQUE_OACC_HEAD_MARK)
    1010                 :      13024 :                         loop->heads[marker] = call;
    1011                 :            :                       else
    1012                 :      13024 :                         loop->tails[remaining] = call;
    1013                 :            :                     }
    1014                 :      26048 :                   marker++;
    1015                 :            :                 }
    1016                 :            :             }
    1017                 :            :         }
    1018                 :            :     }
    1019                 :     157428 :   if (remaining || marker)
    1020                 :            :     {
    1021                 :      52096 :       bb = single_succ (bb);
    1022                 :      52096 :       gcc_assert (single_pred_p (bb) && !(bb->flags & BB_VISITED));
    1023                 :      52096 :       goto follow;
    1024                 :            :     }
    1025                 :            : 
    1026                 :            :   /* Walk successor blocks.  */
    1027                 :     105332 :   edge e;
    1028                 :     105332 :   edge_iterator ei;
    1029                 :            : 
    1030                 :     233948 :   FOR_EACH_EDGE (e, ei, bb->succs)
    1031                 :     128616 :     oacc_loop_discover_walk (loop, e->dest);
    1032                 :            : }
    1033                 :            : 
    1034                 :            : /* LOOP is the first sibling.  Reverse the order in place and return
    1035                 :            :    the new first sibling.  Recurse to child loops.  */
    1036                 :            : 
    1037                 :            : static oacc_loop *
    1038                 :      14498 : oacc_loop_sibling_nreverse (oacc_loop *loop)
    1039                 :            : {
    1040                 :      14498 :   oacc_loop *last = NULL;
    1041                 :      16216 :   do
    1042                 :            :     {
    1043                 :      16216 :       if (loop->child)
    1044                 :       6773 :         loop->child = oacc_loop_sibling_nreverse (loop->child);
    1045                 :            : 
    1046                 :      16216 :       oacc_loop *next = loop->sibling;
    1047                 :      16216 :       loop->sibling = last;
    1048                 :      16216 :       last = loop;
    1049                 :      16216 :       loop = next;
    1050                 :            :     }
    1051                 :      16216 :   while (loop);
    1052                 :            : 
    1053                 :      14498 :   return last;
    1054                 :            : }
    1055                 :            : 
    1056                 :            : /* Discover the OpenACC loops marked up by HEAD and TAIL markers for
    1057                 :            :    the current function.  */
    1058                 :            : 
    1059                 :            : static oacc_loop *
    1060                 :       7725 : oacc_loop_discovery ()
    1061                 :            : {
    1062                 :            :   /* Clear basic block flags, in particular BB_VISITED which we're going to use
    1063                 :            :      in the following.  */
    1064                 :       7725 :   clear_bb_flags ();
    1065                 :            : 
    1066                 :       7725 :   oacc_loop *top = new_oacc_loop_outer (current_function_decl);
    1067                 :       7725 :   oacc_loop_discover_walk (top, ENTRY_BLOCK_PTR_FOR_FN (cfun));
    1068                 :            : 
    1069                 :            :   /* The siblings were constructed in reverse order, reverse them so
    1070                 :            :      that diagnostics come out in an unsurprising order.  */
    1071                 :       7725 :   top = oacc_loop_sibling_nreverse (top);
    1072                 :            : 
    1073                 :       7725 :   return top;
    1074                 :            : }
    1075                 :            : 
    1076                 :            : /* Transform the abstract internal function markers starting at FROM
    1077                 :            :    to be for partitioning level LEVEL.  Stop when we meet another HEAD
    1078                 :            :    or TAIL  marker.  */
    1079                 :            : 
    1080                 :            : static void
    1081                 :      20694 : oacc_loop_xform_head_tail (gcall *from, int level)
    1082                 :            : {
    1083                 :      20694 :   enum ifn_unique_kind kind
    1084                 :      20694 :     = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (from, 0));
    1085                 :      20694 :   tree replacement = build_int_cst (unsigned_type_node, level);
    1086                 :            : 
    1087                 :      20694 :   for (gimple_stmt_iterator gsi = gsi_for_stmt (from);;)
    1088                 :            :     {
    1089                 :      90589 :       gimple *stmt = gsi_stmt (gsi);
    1090                 :            : 
    1091                 :      90589 :       if (gimple_call_internal_p (stmt, IFN_UNIQUE))
    1092                 :            :         {
    1093                 :      62082 :           enum ifn_unique_kind k
    1094                 :            :             = ((enum ifn_unique_kind)
    1095                 :      62082 :                TREE_INT_CST_LOW (gimple_call_arg (stmt, 0)));
    1096                 :            : 
    1097                 :      62082 :           if (k == IFN_UNIQUE_OACC_FORK || k == IFN_UNIQUE_OACC_JOIN)
    1098                 :      20694 :             *gimple_call_arg_ptr (stmt, 2) = replacement;
    1099                 :      41388 :           else if (k == kind && stmt != from)
    1100                 :            :             break;
    1101                 :            :         }
    1102                 :      28507 :       else if (gimple_call_internal_p (stmt, IFN_GOACC_REDUCTION))
    1103                 :      17104 :         *gimple_call_arg_ptr (stmt, 3) = replacement;
    1104                 :            : 
    1105                 :      69895 :       gsi_next (&gsi);
    1106                 :     111283 :       while (gsi_end_p (gsi))
    1107                 :      82776 :         gsi = gsi_start_bb (single_succ (gsi_bb (gsi)));
    1108                 :            :     }
    1109                 :      20694 : }
    1110                 :            : 
    1111                 :            : /* Process the discovered OpenACC loops, setting the correct
    1112                 :            :    partitioning level etc.  */
    1113                 :            : 
    1114                 :            : static void
    1115                 :      14498 : oacc_loop_process (oacc_loop *loop)
    1116                 :            : {
    1117                 :      16216 :   if (loop->child)
    1118                 :       6773 :     oacc_loop_process (loop->child);
    1119                 :            : 
    1120                 :      16216 :   if (loop->mask && !loop->routine)
    1121                 :            :     {
    1122                 :       6953 :       int ix;
    1123                 :       6953 :       tree mask_arg = build_int_cst (unsigned_type_node, loop->mask);
    1124                 :       6953 :       tree e_mask_arg = build_int_cst (unsigned_type_node, loop->e_mask);
    1125                 :       6953 :       tree chunk_arg = loop->chunk_size;
    1126                 :       6953 :       gcall *call;
    1127                 :            :       
    1128                 :      35329 :       for (ix = 0; loop->ifns.iterate (ix, &call); ix++)
    1129                 :      28376 :         switch (gimple_call_internal_fn (call))
    1130                 :            :           {
    1131                 :      28187 :           case IFN_GOACC_LOOP:
    1132                 :      28187 :             {
    1133                 :      28187 :               bool is_e = gimple_call_arg (call, 5) == integer_minus_one_node;
    1134                 :      55999 :               gimple_call_set_arg (call, 5, is_e ? e_mask_arg : mask_arg);
    1135                 :      28187 :               if (!is_e)
    1136                 :      27812 :                 gimple_call_set_arg (call, 4, chunk_arg);
    1137                 :            :             }
    1138                 :            :             break;
    1139                 :            : 
    1140                 :        189 :           case IFN_GOACC_TILE:
    1141                 :        189 :             gimple_call_set_arg (call, 3, mask_arg);
    1142                 :      28565 :             gimple_call_set_arg (call, 4, e_mask_arg);
    1143                 :            :             break;
    1144                 :            : 
    1145                 :          0 :           default:
    1146                 :          0 :             gcc_unreachable ();
    1147                 :            :           }
    1148                 :            : 
    1149                 :       6953 :       unsigned dim = GOMP_DIM_GANG;
    1150                 :       6953 :       unsigned mask = loop->mask | loop->e_mask;
    1151                 :      17300 :       for (ix = 0; ix != GOMP_DIM_MAX && mask; ix++)
    1152                 :            :         {
    1153                 :      20250 :           while (!(GOMP_DIM_MASK (dim) & mask))
    1154                 :       9903 :             dim++;
    1155                 :            : 
    1156                 :      10347 :           oacc_loop_xform_head_tail (loop->heads[ix], dim);
    1157                 :      10347 :           oacc_loop_xform_head_tail (loop->tails[ix], dim);
    1158                 :            : 
    1159                 :      10347 :           mask ^= GOMP_DIM_MASK (dim);
    1160                 :            :         }
    1161                 :            :     }
    1162                 :            : 
    1163                 :      16216 :   if (loop->sibling)
    1164                 :            :     oacc_loop_process (loop->sibling);
    1165                 :      14498 : }
    1166                 :            : 
    1167                 :            : /* Walk the OpenACC loop heirarchy checking and assigning the
    1168                 :            :    programmer-specified partitionings.  OUTER_MASK is the partitioning
    1169                 :            :    this loop is contained within.  Return mask of partitioning
    1170                 :            :    encountered.  If any auto loops are discovered, set GOMP_DIM_MAX
    1171                 :            :    bit.  */
    1172                 :            : 
    1173                 :            : static unsigned
    1174                 :      16216 : oacc_loop_fixed_partitions (oacc_loop *loop, unsigned outer_mask)
    1175                 :            : {
    1176                 :      16216 :   unsigned this_mask = loop->mask;
    1177                 :      16216 :   unsigned mask_all = 0;
    1178                 :      16216 :   bool noisy = true;
    1179                 :            : 
    1180                 :            : #ifdef ACCEL_COMPILER
    1181                 :            :   /* When device_type is supported, we want the device compiler to be
    1182                 :            :      noisy, if the loop parameters are device_type-specific.  */
    1183                 :            :   noisy = false;
    1184                 :            : #endif
    1185                 :            : 
    1186                 :      16216 :   if (!loop->routine)
    1187                 :            :     {
    1188                 :      15399 :       bool auto_par = (loop->flags & OLF_AUTO) != 0;
    1189                 :      15399 :       bool seq_par = (loop->flags & OLF_SEQ) != 0;
    1190                 :      15399 :       bool tiling = (loop->flags & OLF_TILE) != 0;
    1191                 :            :       
    1192                 :      15399 :       this_mask = ((loop->flags >> OLF_DIM_BASE)
    1193                 :            :                    & (GOMP_DIM_MASK (GOMP_DIM_MAX) - 1));
    1194                 :            : 
    1195                 :            :       /* Apply auto partitioning if this is a non-partitioned regular
    1196                 :            :          loop, or (no more than) single axis tiled loop.  */
    1197                 :      30798 :       bool maybe_auto
    1198                 :      15399 :         = !seq_par && this_mask == (tiling ? this_mask & -this_mask : 0);
    1199                 :            : 
    1200                 :      15399 :       if ((this_mask != 0) + auto_par + seq_par > 1)
    1201                 :            :         {
    1202                 :        102 :           if (noisy)
    1203                 :        150 :             error_at (loop->loc,
    1204                 :            :                       seq_par
    1205                 :            :                       ? G_("%<seq%> overrides other OpenACC loop specifiers")
    1206                 :            :                       : G_("%<auto%> conflicts with other OpenACC loop "
    1207                 :            :                            "specifiers"));
    1208                 :        102 :           maybe_auto = false;
    1209                 :        102 :           loop->flags &= ~OLF_AUTO;
    1210                 :        102 :           if (seq_par)
    1211                 :            :             {
    1212                 :         54 :               loop->flags
    1213                 :         54 :                 &= ~((GOMP_DIM_MASK (GOMP_DIM_MAX) - 1) << OLF_DIM_BASE);
    1214                 :         54 :               this_mask = 0;
    1215                 :            :             }
    1216                 :            :         }
    1217                 :            : 
    1218                 :      15351 :       if (maybe_auto && (loop->flags & OLF_INDEPENDENT))
    1219                 :            :         {
    1220                 :       4225 :           loop->flags |= OLF_AUTO;
    1221                 :       4225 :           mask_all |= GOMP_DIM_MASK (GOMP_DIM_MAX);
    1222                 :            :         }
    1223                 :            :     }
    1224                 :            : 
    1225                 :      16216 :   if (this_mask & outer_mask)
    1226                 :            :     {
    1227                 :        238 :       const oacc_loop *outer;
    1228                 :        364 :       for (outer = loop->parent; outer; outer = outer->parent)
    1229                 :        238 :         if ((outer->mask | outer->e_mask) & this_mask)
    1230                 :            :           break;
    1231                 :            : 
    1232                 :        238 :       if (noisy)
    1233                 :            :         {
    1234                 :        238 :           if (outer)
    1235                 :            :             {
    1236                 :        112 :               error_at (loop->loc,
    1237                 :        112 :                         loop->routine
    1238                 :            :                         ? G_("routine call uses same OpenACC parallelism"
    1239                 :            :                              " as containing loop")
    1240                 :            :                         : G_("inner loop uses same OpenACC parallelism"
    1241                 :            :                              " as containing loop"));
    1242                 :        112 :               inform (outer->loc, "containing loop here");
    1243                 :            :             }
    1244                 :            :           else
    1245                 :        126 :             error_at (loop->loc,
    1246                 :        126 :                       loop->routine
    1247                 :            :                       ? G_("routine call uses OpenACC parallelism disallowed"
    1248                 :            :                            " by containing routine")
    1249                 :            :                       : G_("loop uses OpenACC parallelism disallowed"
    1250                 :            :                            " by containing routine"));
    1251                 :            : 
    1252                 :        238 :           if (loop->routine)
    1253                 :        146 :             inform (DECL_SOURCE_LOCATION (loop->routine),
    1254                 :            :                     "routine %qD declared here", loop->routine);
    1255                 :            :         }
    1256                 :        238 :       this_mask &= ~outer_mask;
    1257                 :            :     }
    1258                 :            :   else
    1259                 :            :     {
    1260                 :      15978 :       unsigned outermost = least_bit_hwi (this_mask);
    1261                 :            : 
    1262                 :      15978 :       if (outermost && outermost <= outer_mask)
    1263                 :            :         {
    1264                 :         26 :           if (noisy)
    1265                 :            :             {
    1266                 :         26 :               error_at (loop->loc,
    1267                 :            :                         "incorrectly nested OpenACC loop parallelism");
    1268                 :            : 
    1269                 :         26 :               const oacc_loop *outer;
    1270                 :         26 :               for (outer = loop->parent;
    1271                 :         26 :                    outer->flags && outer->flags < outermost;
    1272                 :          0 :                    outer = outer->parent)
    1273                 :          0 :                 continue;
    1274                 :         26 :               inform (outer->loc, "containing loop here");
    1275                 :            :             }
    1276                 :            : 
    1277                 :         26 :           this_mask &= ~outermost;
    1278                 :            :         }
    1279                 :            :     }
    1280                 :            : 
    1281                 :      16216 :   mask_all |= this_mask;
    1282                 :            : 
    1283                 :      16216 :   if (loop->flags & OLF_TILE)
    1284                 :            :     {
    1285                 :            :       /* When tiling, vector goes to the element loop, and failing
    1286                 :            :          that we put worker there.  The std doesn't contemplate
    1287                 :            :          specifying all three.  We choose to put worker and vector on
    1288                 :            :          the element loops in that case.  */
    1289                 :        135 :       unsigned this_e_mask = this_mask & GOMP_DIM_MASK (GOMP_DIM_VECTOR);
    1290                 :        135 :       if (!this_e_mask || this_mask & GOMP_DIM_MASK (GOMP_DIM_GANG))
    1291                 :        116 :         this_e_mask |= this_mask & GOMP_DIM_MASK (GOMP_DIM_WORKER);
    1292                 :            : 
    1293                 :        135 :       loop->e_mask = this_e_mask;
    1294                 :        135 :       this_mask ^= this_e_mask;
    1295                 :            :     }
    1296                 :            : 
    1297                 :      16216 :   loop->mask = this_mask;
    1298                 :            : 
    1299                 :      16216 :   if (dump_file)
    1300                 :         39 :     fprintf (dump_file, "Loop %s:%d user specified %d & %d\n",
    1301                 :         78 :              LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
    1302                 :            :              loop->mask, loop->e_mask);
    1303                 :            : 
    1304                 :      16216 :   if (loop->child)
    1305                 :            :     {
    1306                 :       6773 :       unsigned tmp_mask = outer_mask | this_mask | loop->e_mask;
    1307                 :       6773 :       loop->inner = oacc_loop_fixed_partitions (loop->child, tmp_mask);
    1308                 :       6773 :       mask_all |= loop->inner;
    1309                 :            :     }
    1310                 :            : 
    1311                 :      16216 :   if (loop->sibling)
    1312                 :       1718 :     mask_all |= oacc_loop_fixed_partitions (loop->sibling, outer_mask);
    1313                 :            : 
    1314                 :      16216 :   return mask_all;
    1315                 :            : }
    1316                 :            : 
    1317                 :            : /* Walk the OpenACC loop heirarchy to assign auto-partitioned loops.
    1318                 :            :    OUTER_MASK is the partitioning this loop is contained within.
    1319                 :            :    OUTER_ASSIGN is true if an outer loop is being auto-partitioned.
    1320                 :            :    Return the cumulative partitioning used by this loop, siblings and
    1321                 :            :    children.  */
    1322                 :            : 
    1323                 :            : static unsigned
    1324                 :       7817 : oacc_loop_auto_partitions (oacc_loop *loop, unsigned outer_mask,
    1325                 :            :                            bool outer_assign)
    1326                 :            : {
    1327                 :       7817 :   bool assign = (loop->flags & OLF_AUTO) && (loop->flags & OLF_INDEPENDENT);
    1328                 :       7817 :   bool noisy = true;
    1329                 :       7817 :   bool tiling = loop->flags & OLF_TILE;
    1330                 :            : 
    1331                 :            : #ifdef ACCEL_COMPILER
    1332                 :            :   /* When device_type is supported, we want the device compiler to be
    1333                 :            :      noisy, if the loop parameters are device_type-specific.  */
    1334                 :            :   noisy = false;
    1335                 :            : #endif
    1336                 :            : 
    1337                 :       7817 :   if (assign && (!outer_assign || loop->inner))
    1338                 :            :     {
    1339                 :            :       /* Allocate outermost and non-innermost loops at the outermost
    1340                 :            :          non-innermost available level.  */
    1341                 :            :       unsigned this_mask = GOMP_DIM_MASK (GOMP_DIM_GANG);
    1342                 :            : 
    1343                 :            :       /* Find the first outermost available partition. */
    1344                 :       4988 :       while (this_mask <= outer_mask)
    1345                 :       1456 :         this_mask <<= 1;
    1346                 :            :       
    1347                 :            :       /* Grab two axes if tiling, and we've not assigned anything  */
    1348                 :       3532 :       if (tiling && !(loop->mask | loop->e_mask))
    1349                 :         85 :         this_mask |= this_mask << 1;
    1350                 :            : 
    1351                 :            :       /* Prohibit the innermost partitioning at the moment.  */
    1352                 :       3532 :       this_mask &= GOMP_DIM_MASK (GOMP_DIM_MAX - 1) - 1;
    1353                 :            : 
    1354                 :            :       /* Don't use any dimension explicitly claimed by an inner loop. */
    1355                 :       3532 :       this_mask &= ~loop->inner;
    1356                 :            : 
    1357                 :       3532 :       if (tiling && !loop->e_mask)
    1358                 :            :         {
    1359                 :            :           /* If we got two axes, allocate the inner one to the element
    1360                 :            :              loop.  */
    1361                 :         90 :           loop->e_mask = this_mask & (this_mask << 1);
    1362                 :         90 :           this_mask ^= loop->e_mask;
    1363                 :            :         }
    1364                 :            : 
    1365                 :       3532 :       loop->mask |= this_mask;
    1366                 :            :     }
    1367                 :            : 
    1368                 :       7817 :   if (loop->child)
    1369                 :            :     {
    1370                 :       4057 :       unsigned tmp_mask = outer_mask | loop->mask | loop->e_mask;
    1371                 :       4057 :       loop->inner = oacc_loop_auto_partitions (loop->child, tmp_mask,
    1372                 :       4057 :                                                outer_assign | assign);
    1373                 :            :     }
    1374                 :            : 
    1375                 :       7817 :   if (assign && (!loop->mask || (tiling && !loop->e_mask) || !outer_assign))
    1376                 :            :     {
    1377                 :            :       /* Allocate the loop at the innermost available level.  Note
    1378                 :            :          that we do this even if we already assigned this loop the
    1379                 :            :          outermost available level above.  That way we'll partition
    1380                 :            :          this along 2 axes, if they are available.  */
    1381                 :       3788 :       unsigned this_mask = 0;
    1382                 :            : 
    1383                 :            :       /* Determine the outermost partitioning used within this loop.  */
    1384                 :       3788 :       this_mask = loop->inner | GOMP_DIM_MASK (GOMP_DIM_MAX);
    1385                 :       3788 :       this_mask = least_bit_hwi (this_mask);
    1386                 :            : 
    1387                 :            :       /* Pick the partitioning just inside that one.  */
    1388                 :       3788 :       this_mask >>= 1;
    1389                 :            : 
    1390                 :            :       /* And avoid picking one use by an outer loop.  */
    1391                 :       3788 :       this_mask &= ~outer_mask;
    1392                 :            : 
    1393                 :            :       /* If tiling and we failed completely above, grab the next one
    1394                 :            :          too.  Making sure it doesn't hit an outer loop.  */
    1395                 :       3788 :       if (tiling)
    1396                 :            :         {
    1397                 :        105 :           this_mask &= ~(loop->e_mask | loop->mask);
    1398                 :        105 :           unsigned tile_mask = ((this_mask >> 1)
    1399                 :        105 :                                 & ~(outer_mask | loop->e_mask | loop->mask));
    1400                 :            : 
    1401                 :        105 :           if (tile_mask || loop->mask)
    1402                 :            :             {
    1403                 :         95 :               loop->e_mask |= this_mask;
    1404                 :         95 :               this_mask = tile_mask;
    1405                 :            :             }
    1406                 :        105 :           if (!loop->e_mask && noisy)
    1407                 :         10 :             warning_at (loop->loc, 0,
    1408                 :            :                         "insufficient partitioning available"
    1409                 :            :                         " to parallelize element loop");
    1410                 :            :         }
    1411                 :            : 
    1412                 :       3788 :       loop->mask |= this_mask;
    1413                 :       3788 :       if (!loop->mask && noisy)
    1414                 :        753 :         warning_at (loop->loc, 0,
    1415                 :            :                     tiling
    1416                 :            :                     ? G_("insufficient partitioning available"
    1417                 :            :                          " to parallelize tile loop")
    1418                 :            :                     : G_("insufficient partitioning available"
    1419                 :            :                          " to parallelize loop"));
    1420                 :            :     }
    1421                 :            : 
    1422                 :       7817 :   if (assign && dump_file)
    1423                 :         13 :     fprintf (dump_file, "Auto loop %s:%d assigned %d & %d\n",
    1424                 :         26 :              LOCATION_FILE (loop->loc), LOCATION_LINE (loop->loc),
    1425                 :            :              loop->mask, loop->e_mask);
    1426                 :            : 
    1427                 :       7817 :   unsigned inner_mask = 0;
    1428                 :            : 
    1429                 :       7817 :   if (loop->sibling)
    1430                 :       1409 :     inner_mask |= oacc_loop_auto_partitions (loop->sibling,
    1431                 :            :                                              outer_mask, outer_assign);
    1432                 :            : 
    1433                 :       7817 :   inner_mask |= loop->inner | loop->mask | loop->e_mask;
    1434                 :            : 
    1435                 :       7817 :   return inner_mask;
    1436                 :            : }
    1437                 :            : 
    1438                 :            : /* Walk the OpenACC loop heirarchy to check and assign partitioning
    1439                 :            :    axes.  Return mask of partitioning.  */
    1440                 :            : 
    1441                 :            : static unsigned
    1442                 :       7725 : oacc_loop_partition (oacc_loop *loop, unsigned outer_mask)
    1443                 :            : {
    1444                 :       7725 :   unsigned mask_all = oacc_loop_fixed_partitions (loop, outer_mask);
    1445                 :            : 
    1446                 :       7725 :   if (mask_all & GOMP_DIM_MASK (GOMP_DIM_MAX))
    1447                 :            :     {
    1448                 :       2351 :       mask_all ^= GOMP_DIM_MASK (GOMP_DIM_MAX);
    1449                 :       2351 :       mask_all |= oacc_loop_auto_partitions (loop, outer_mask, false);
    1450                 :            :     }
    1451                 :       7725 :   return mask_all;
    1452                 :            : }
    1453                 :            : 
    1454                 :            : /* Default fork/join early expander.  Delete the function calls if
    1455                 :            :    there is no RTL expander.  */
    1456                 :            : 
    1457                 :            : bool
    1458                 :      20694 : default_goacc_fork_join (gcall *ARG_UNUSED (call),
    1459                 :            :                          const int *ARG_UNUSED (dims), bool is_fork)
    1460                 :            : {
    1461                 :      20694 :   if (is_fork)
    1462                 :      10347 :     return targetm.have_oacc_fork ();
    1463                 :            :   else
    1464                 :      10347 :     return targetm.have_oacc_join ();
    1465                 :            : }
    1466                 :            : 
    1467                 :            : /* Default goacc.reduction early expander.
    1468                 :            : 
    1469                 :            :    LHS-opt = IFN_REDUCTION (KIND, RES_PTR, VAR, LEVEL, OP, OFFSET)
    1470                 :            :    If RES_PTR is not integer-zerop:
    1471                 :            :        SETUP - emit 'LHS = *RES_PTR', LHS = NULL
    1472                 :            :        TEARDOWN - emit '*RES_PTR = VAR'
    1473                 :            :    If LHS is not NULL
    1474                 :            :        emit 'LHS = VAR'   */
    1475                 :            : 
    1476                 :            : void
    1477                 :      24996 : default_goacc_reduction (gcall *call)
    1478                 :            : {
    1479                 :      24996 :   unsigned code = (unsigned)TREE_INT_CST_LOW (gimple_call_arg (call, 0));
    1480                 :      24996 :   gimple_stmt_iterator gsi = gsi_for_stmt (call);
    1481                 :      24996 :   tree lhs = gimple_call_lhs (call);
    1482                 :      24996 :   tree var = gimple_call_arg (call, 2);
    1483                 :      24996 :   gimple_seq seq = NULL;
    1484                 :            : 
    1485                 :      24996 :   if (code == IFN_GOACC_REDUCTION_SETUP
    1486                 :      24996 :       || code == IFN_GOACC_REDUCTION_TEARDOWN)
    1487                 :            :     {
    1488                 :            :       /* Setup and Teardown need to copy from/to the receiver object,
    1489                 :            :          if there is one.  */
    1490                 :      12498 :       tree ref_to_res = gimple_call_arg (call, 1);
    1491                 :            : 
    1492                 :      12498 :       if (!integer_zerop (ref_to_res))
    1493                 :            :         {
    1494                 :       4630 :           tree dst = build_simple_mem_ref (ref_to_res);
    1495                 :       4630 :           tree src = var;
    1496                 :            : 
    1497                 :       4630 :           if (code == IFN_GOACC_REDUCTION_SETUP)
    1498                 :            :             {
    1499                 :       2315 :               src = dst;
    1500                 :       2315 :               dst = lhs;
    1501                 :       2315 :               lhs = NULL;
    1502                 :            :             }
    1503                 :       4630 :           gimple_seq_add_stmt (&seq, gimple_build_assign (dst, src));
    1504                 :            :         }
    1505                 :            :     }
    1506                 :            : 
    1507                 :            :   /* Copy VAR to LHS, if there is an LHS.  */
    1508                 :      24996 :   if (lhs)
    1509                 :      21211 :     gimple_seq_add_stmt (&seq, gimple_build_assign (lhs, var));
    1510                 :            : 
    1511                 :      24996 :   gsi_replace_with_seq (&gsi, seq, true);
    1512                 :      24996 : }
    1513                 :            : 
    1514                 :            : /* Main entry point for oacc transformations which run on the device
    1515                 :            :    compiler after LTO, so we know what the target device is at this
    1516                 :            :    point (including the host fallback).  */
    1517                 :            : 
    1518                 :            : static unsigned int
    1519                 :      12124 : execute_oacc_device_lower ()
    1520                 :            : {
    1521                 :      12124 :   tree attrs = oacc_get_fn_attrib (current_function_decl);
    1522                 :            : 
    1523                 :      12124 :   if (!attrs)
    1524                 :            :     /* Not an offloaded function.  */
    1525                 :            :     return 0;
    1526                 :            : 
    1527                 :            :   /* Parse the default dim argument exactly once.  */
    1528                 :       7725 :   if ((const void *)flag_openacc_dims != &flag_openacc_dims)
    1529                 :            :     {
    1530                 :       1929 :       oacc_parse_default_dims (flag_openacc_dims);
    1531                 :       1929 :       flag_openacc_dims = (char *)&flag_openacc_dims;
    1532                 :            :     }
    1533                 :            : 
    1534                 :       7725 :   bool is_oacc_kernels
    1535                 :       7725 :     = (lookup_attribute ("oacc kernels",
    1536                 :       7725 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1537                 :       7725 :   bool is_oacc_kernels_parallelized
    1538                 :       7725 :     = (lookup_attribute ("oacc kernels parallelized",
    1539                 :       7725 :                          DECL_ATTRIBUTES (current_function_decl)) != NULL);
    1540                 :            : 
    1541                 :            :   /* Unparallelized OpenACC kernels constructs must get launched as 1 x 1 x 1
    1542                 :            :      kernels, so remove the parallelism dimensions function attributes
    1543                 :            :      potentially set earlier on.  */
    1544                 :       7725 :   if (is_oacc_kernels && !is_oacc_kernels_parallelized)
    1545                 :            :     {
    1546                 :       1094 :       oacc_set_fn_attrib (current_function_decl, NULL, NULL);
    1547                 :       1094 :       attrs = oacc_get_fn_attrib (current_function_decl);
    1548                 :            :     }
    1549                 :            : 
    1550                 :            :   /* Discover, partition and process the loops.  */
    1551                 :       7725 :   oacc_loop *loops = oacc_loop_discovery ();
    1552                 :       7725 :   int fn_level = oacc_fn_attrib_level (attrs);
    1553                 :            : 
    1554                 :       7725 :   if (dump_file)
    1555                 :            :     {
    1556                 :         25 :       if (fn_level >= 0)
    1557                 :          6 :         fprintf (dump_file, "Function is OpenACC routine level %d\n",
    1558                 :            :                  fn_level);
    1559                 :         19 :       else if (is_oacc_kernels)
    1560                 :         18 :         fprintf (dump_file, "Function is %s OpenACC kernels offload\n",
    1561                 :            :                  (is_oacc_kernels_parallelized
    1562                 :            :                   ? "parallelized" : "unparallelized"));
    1563                 :            :       else
    1564                 :          7 :         fprintf (dump_file, "Function is OpenACC parallel offload\n");
    1565                 :            :     }
    1566                 :            : 
    1567                 :       7725 :   unsigned outer_mask = fn_level >= 0 ? GOMP_DIM_MASK (fn_level) - 1 : 0;
    1568                 :       7725 :   unsigned used_mask = oacc_loop_partition (loops, outer_mask);
    1569                 :            :   /* OpenACC kernels constructs are special: they currently don't use the
    1570                 :            :      generic oacc_loop infrastructure and attribute/dimension processing.  */
    1571                 :       7725 :   if (is_oacc_kernels && is_oacc_kernels_parallelized)
    1572                 :            :     {
    1573                 :            :       /* Parallelized OpenACC kernels constructs use gang parallelism.  See
    1574                 :            :          also tree-parloops.c:create_parallel_loop.  */
    1575                 :        370 :       used_mask |= GOMP_DIM_MASK (GOMP_DIM_GANG);
    1576                 :            :     }
    1577                 :            : 
    1578                 :       7725 :   int dims[GOMP_DIM_MAX];
    1579                 :       7725 :   oacc_validate_dims (current_function_decl, attrs, dims, fn_level, used_mask);
    1580                 :            : 
    1581                 :       7725 :   if (dump_file)
    1582                 :            :     {
    1583                 :            :       const char *comma = "Compute dimensions [";
    1584                 :        100 :       for (int ix = 0; ix != GOMP_DIM_MAX; ix++, comma = ", ")
    1585                 :         75 :         fprintf (dump_file, "%s%d", comma, dims[ix]);
    1586                 :         25 :       fprintf (dump_file, "]\n");
    1587                 :            :     }
    1588                 :            : 
    1589                 :       7725 :   oacc_loop_process (loops);
    1590                 :       7725 :   if (dump_file)
    1591                 :            :     {
    1592                 :         25 :       fprintf (dump_file, "OpenACC loops\n");
    1593                 :         25 :       dump_oacc_loop (dump_file, loops, 0);
    1594                 :         25 :       fprintf (dump_file, "\n");
    1595                 :            :     }
    1596                 :       7725 :   if (dump_enabled_p ())
    1597                 :            :     {
    1598                 :        280 :       oacc_loop *l = loops;
    1599                 :            :       /* OpenACC kernels constructs are special: they currently don't use the
    1600                 :            :          generic oacc_loop infrastructure.  */
    1601                 :        280 :       if (is_oacc_kernels)
    1602                 :            :         {
    1603                 :            :           /* Create a fake oacc_loop for diagnostic purposes.  */
    1604                 :        129 :           l = new_oacc_loop_raw (NULL,
    1605                 :         43 :                                  DECL_SOURCE_LOCATION (current_function_decl));
    1606                 :         43 :           l->mask = used_mask;
    1607                 :            :         }
    1608                 :            :       else
    1609                 :            :         {
    1610                 :            :           /* Skip the outermost, dummy OpenACC loop  */
    1611                 :        237 :           l = l->child;
    1612                 :            :         }
    1613                 :        280 :       if (l)
    1614                 :        274 :         inform_oacc_loop (l);
    1615                 :        280 :       if (is_oacc_kernels)
    1616                 :         43 :         free_oacc_loop (l);
    1617                 :            :     }
    1618                 :            : 
    1619                 :            :   /* Offloaded targets may introduce new basic blocks, which require
    1620                 :            :      dominance information to update SSA.  */
    1621                 :       7725 :   calculate_dominance_info (CDI_DOMINATORS);
    1622                 :            : 
    1623                 :            :   /* Now lower internal loop functions to target-specific code
    1624                 :            :      sequences.  */
    1625                 :       7725 :   basic_block bb;
    1626                 :     165221 :   FOR_ALL_BB_FN (bb, cfun)
    1627                 :     776139 :     for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
    1628                 :            :       {
    1629                 :     461147 :         gimple *stmt = gsi_stmt (gsi);
    1630                 :     461147 :         if (!is_gimple_call (stmt))
    1631                 :            :           {
    1632                 :     303260 :             gsi_next (&gsi);
    1633                 :     303260 :             continue;
    1634                 :            :           }
    1635                 :            : 
    1636                 :     157887 :         gcall *call = as_a <gcall *> (stmt);
    1637                 :     157887 :         if (!gimple_call_internal_p (call))
    1638                 :            :           {
    1639                 :       3898 :             gsi_next (&gsi);
    1640                 :       3898 :             continue;
    1641                 :            :           }
    1642                 :            : 
    1643                 :            :         /* Rewind to allow rescan.  */
    1644                 :     153989 :         gsi_prev (&gsi);
    1645                 :     153989 :         bool rescan = false, remove = false;
    1646                 :     153989 :         enum  internal_fn ifn_code = gimple_call_internal_fn (call);
    1647                 :            : 
    1648                 :     153989 :         switch (ifn_code)
    1649                 :            :           {
    1650                 :            :           default: break;
    1651                 :            : 
    1652                 :        271 :           case IFN_GOACC_TILE:
    1653                 :        271 :             oacc_xform_tile (call);
    1654                 :        271 :             rescan = true;
    1655                 :        271 :             break;
    1656                 :            :             
    1657                 :      36153 :           case IFN_GOACC_LOOP:
    1658                 :      36153 :             oacc_xform_loop (call);
    1659                 :      36153 :             rescan = true;
    1660                 :      36153 :             break;
    1661                 :            : 
    1662                 :      24996 :           case IFN_GOACC_REDUCTION:
    1663                 :            :             /* Mark the function for SSA renaming.  */
    1664                 :      24996 :             mark_virtual_operands_for_renaming (cfun);
    1665                 :            : 
    1666                 :            :             /* If the level is -1, this ended up being an unused
    1667                 :            :                axis.  Handle as a default.  */
    1668                 :      24996 :             if (integer_minus_onep (gimple_call_arg (call, 3)))
    1669                 :       5984 :               default_goacc_reduction (call);
    1670                 :            :             else
    1671                 :      19012 :               targetm.goacc.reduction (call);
    1672                 :            :             rescan = true;
    1673                 :            :             break;
    1674                 :            : 
    1675                 :      67444 :           case IFN_UNIQUE:
    1676                 :      67444 :             {
    1677                 :      67444 :               enum ifn_unique_kind kind
    1678                 :            :                 = ((enum ifn_unique_kind)
    1679                 :      67444 :                    TREE_INT_CST_LOW (gimple_call_arg (call, 0)));
    1680                 :            : 
    1681                 :      67444 :               switch (kind)
    1682                 :            :                 {
    1683                 :            :                 default:
    1684                 :            :                   break;
    1685                 :            : 
    1686                 :      26048 :                 case IFN_UNIQUE_OACC_FORK:
    1687                 :      26048 :                 case IFN_UNIQUE_OACC_JOIN:
    1688                 :      26048 :                   if (integer_minus_onep (gimple_call_arg (call, 2)))
    1689                 :            :                     remove = true;
    1690                 :      20694 :                   else if (!targetm.goacc.fork_join
    1691                 :      20694 :                            (call, dims, kind == IFN_UNIQUE_OACC_FORK))
    1692                 :      20694 :                     remove = true;
    1693                 :            :                   break;
    1694                 :            : 
    1695                 :      41396 :                 case IFN_UNIQUE_OACC_HEAD_MARK:
    1696                 :      41396 :                 case IFN_UNIQUE_OACC_TAIL_MARK:
    1697                 :      41396 :                   remove = true;
    1698                 :      41396 :                   break;
    1699                 :            :                 }
    1700                 :            :               break;
    1701                 :            :             }
    1702                 :            :           }
    1703                 :            : 
    1704                 :     153989 :         if (gsi_end_p (gsi))
    1705                 :            :           /* We rewound past the beginning of the BB.  */
    1706                 :     150236 :           gsi = gsi_start_bb (bb);
    1707                 :            :         else
    1708                 :            :           /* Undo the rewind.  */
    1709                 :      78871 :           gsi_next (&gsi);
    1710                 :            : 
    1711                 :     153989 :         if (remove)
    1712                 :            :           {
    1713                 :     134888 :             if (gimple_vdef (call))
    1714                 :      67444 :               replace_uses_by (gimple_vdef (call), gimple_vuse (call));
    1715                 :      67444 :             if (gimple_call_lhs (call))
    1716                 :            :               {
    1717                 :            :                 /* Propagate the data dependency var.  */
    1718                 :      62988 :                 gimple *ass = gimple_build_assign (gimple_call_lhs (call),
    1719                 :            :                                                    gimple_call_arg (call, 1));
    1720                 :      62988 :                 gsi_replace (&gsi, ass,  false);
    1721                 :            :               }
    1722                 :            :             else
    1723                 :       4456 :               gsi_remove (&gsi, true);
    1724                 :            :           }
    1725                 :      86545 :         else if (!rescan)
    1726                 :            :           /* If not rescanning, advance over the call.  */
    1727                 :      25125 :           gsi_next (&gsi);
    1728                 :            :       }
    1729                 :            : 
    1730                 :       7725 :   free_oacc_loop (loops);
    1731                 :            : 
    1732                 :       7725 :   return 0;
    1733                 :            : }
    1734                 :            : 
    1735                 :            : /* Default launch dimension validator.  Force everything to 1.  A
    1736                 :            :    backend that wants to provide larger dimensions must override this
    1737                 :            :    hook.  */
    1738                 :            : 
    1739                 :            : bool
    1740                 :      11583 : default_goacc_validate_dims (tree ARG_UNUSED (decl), int *dims,
    1741                 :            :                              int ARG_UNUSED (fn_level),
    1742                 :            :                              unsigned ARG_UNUSED (used))
    1743                 :            : {
    1744                 :      11583 :   bool changed = false;
    1745                 :            : 
    1746                 :      46332 :   for (unsigned ix = 0; ix != GOMP_DIM_MAX; ix++)
    1747                 :            :     {
    1748                 :      34749 :       if (dims[ix] != 1)
    1749                 :            :         {
    1750                 :      28162 :           dims[ix] = 1;
    1751                 :      28162 :           changed = true;
    1752                 :            :         }
    1753                 :            :     }
    1754                 :            : 
    1755                 :      11583 :   return changed;
    1756                 :            : }
    1757                 :            : 
    1758                 :            : /* Default dimension bound is unknown on accelerator and 1 on host.  */
    1759                 :            : 
    1760                 :            : int
    1761                 :          0 : default_goacc_dim_limit (int ARG_UNUSED (axis))
    1762                 :            : {
    1763                 :            : #ifdef ACCEL_COMPILER
    1764                 :            :   return 0;
    1765                 :            : #else
    1766                 :          0 :   return 1;
    1767                 :            : #endif
    1768                 :            : }
    1769                 :            : 
    1770                 :            : namespace {
    1771                 :            : 
    1772                 :            : const pass_data pass_data_oacc_device_lower =
    1773                 :            : {
    1774                 :            :   GIMPLE_PASS, /* type */
    1775                 :            :   "oaccdevlow", /* name */
    1776                 :            :   OPTGROUP_OMP, /* optinfo_flags */
    1777                 :            :   TV_NONE, /* tv_id */
    1778                 :            :   PROP_cfg, /* properties_required */
    1779                 :            :   0 /* Possibly PROP_gimple_eomp.  */, /* properties_provided */
    1780                 :            :   0, /* properties_destroyed */
    1781                 :            :   0, /* todo_flags_start */
    1782                 :            :   TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
    1783                 :            : };
    1784                 :            : 
    1785                 :            : class pass_oacc_device_lower : public gimple_opt_pass
    1786                 :            : {
    1787                 :            : public:
    1788                 :     200773 :   pass_oacc_device_lower (gcc::context *ctxt)
    1789                 :     401546 :     : gimple_opt_pass (pass_data_oacc_device_lower, ctxt)
    1790                 :            :   {}
    1791                 :            : 
    1792                 :            :   /* opt_pass methods: */
    1793                 :     944512 :   virtual bool gate (function *) { return flag_openacc; };
    1794                 :            : 
    1795                 :      12124 :   virtual unsigned int execute (function *)
    1796                 :            :     {
    1797                 :      12124 :       return execute_oacc_device_lower ();
    1798                 :            :     }
    1799                 :            : 
    1800                 :            : }; // class pass_oacc_device_lower
    1801                 :            : 
    1802                 :            : } // anon namespace
    1803                 :            : 
    1804                 :            : gimple_opt_pass *
    1805                 :     200773 : make_pass_oacc_device_lower (gcc::context *ctxt)
    1806                 :            : {
    1807                 :     200773 :   return new pass_oacc_device_lower (ctxt);
    1808                 :            : }
    1809                 :            : 
    1810                 :            : 
    1811                 :            : /* Rewrite GOMP_SIMT_ENTER_ALLOC call given by GSI and remove the preceding
    1812                 :            :    GOMP_SIMT_ENTER call identifying the privatized variables, which are
    1813                 :            :    turned to structure fields and receive a DECL_VALUE_EXPR accordingly.
    1814                 :            :    Set *REGIMPLIFY to true, except if no privatized variables were seen.  */
    1815                 :            : 
    1816                 :            : static void
    1817                 :          0 : ompdevlow_adjust_simt_enter (gimple_stmt_iterator *gsi, bool *regimplify)
    1818                 :            : {
    1819                 :          0 :   gimple *alloc_stmt = gsi_stmt (*gsi);
    1820                 :          0 :   tree simtrec = gimple_call_lhs (alloc_stmt);
    1821                 :          0 :   tree simduid = gimple_call_arg (alloc_stmt, 0);
    1822                 :          0 :   gimple *enter_stmt = SSA_NAME_DEF_STMT (simduid);
    1823                 :          0 :   gcc_assert (gimple_call_internal_p (enter_stmt, IFN_GOMP_SIMT_ENTER));
    1824                 :          0 :   tree rectype = lang_hooks.types.make_type (RECORD_TYPE);
    1825                 :          0 :   TYPE_ARTIFICIAL (rectype) = TYPE_NAMELESS (rectype) = 1;
    1826                 :          0 :   TREE_ADDRESSABLE (rectype) = 1;
    1827                 :          0 :   TREE_TYPE (simtrec) = build_pointer_type (rectype);
    1828                 :          0 :   for (unsigned i = 1; i < gimple_call_num_args (enter_stmt); i++)
    1829                 :            :     {
    1830                 :          0 :       tree *argp = gimple_call_arg_ptr (enter_stmt, i);
    1831                 :          0 :       if (*argp == null_pointer_node)
    1832                 :          0 :         continue;
    1833                 :          0 :       gcc_assert (TREE_CODE (*argp) == ADDR_EXPR
    1834                 :            :                   && VAR_P (TREE_OPERAND (*argp, 0)));
    1835                 :          0 :       tree var = TREE_OPERAND (*argp, 0);
    1836                 :            : 
    1837                 :          0 :       tree field = build_decl (DECL_SOURCE_LOCATION (var), FIELD_DECL,
    1838                 :          0 :                                DECL_NAME (var), TREE_TYPE (var));
    1839                 :          0 :       SET_DECL_ALIGN (field, DECL_ALIGN (var));
    1840                 :          0 :       DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var);
    1841                 :          0 :       TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var);
    1842                 :            : 
    1843                 :          0 :       insert_field_into_struct (rectype, field);
    1844                 :            : 
    1845                 :          0 :       tree t = build_simple_mem_ref (simtrec);
    1846                 :          0 :       t = build3 (COMPONENT_REF, TREE_TYPE (var), t, field, NULL);
    1847                 :          0 :       TREE_THIS_VOLATILE (t) = TREE_THIS_VOLATILE (var);
    1848                 :          0 :       SET_DECL_VALUE_EXPR (var, t);
    1849                 :          0 :       DECL_HAS_VALUE_EXPR_P (var) = 1;
    1850                 :          0 :       *regimplify = true;
    1851                 :            :     }
    1852                 :          0 :   layout_type (rectype);
    1853                 :          0 :   tree size = TYPE_SIZE_UNIT (rectype);
    1854                 :          0 :   tree align = build_int_cst (TREE_TYPE (size), TYPE_ALIGN_UNIT (rectype));
    1855                 :            : 
    1856                 :          0 :   alloc_stmt
    1857                 :          0 :     = gimple_build_call_internal (IFN_GOMP_SIMT_ENTER_ALLOC, 2, size, align);
    1858                 :          0 :   gimple_call_set_lhs (alloc_stmt, simtrec);
    1859                 :          0 :   gsi_replace (gsi, alloc_stmt, false);
    1860                 :          0 :   gimple_stmt_iterator enter_gsi = gsi_for_stmt (enter_stmt);
    1861                 :          0 :   enter_stmt = gimple_build_assign (simduid, gimple_call_arg (enter_stmt, 0));
    1862                 :          0 :   gsi_replace (&enter_gsi, enter_stmt, false);
    1863                 :            : 
    1864                 :          0 :   use_operand_p use;
    1865                 :          0 :   gimple *exit_stmt;
    1866                 :          0 :   if (single_imm_use (simtrec, &use, &exit_stmt))
    1867                 :            :     {
    1868                 :          0 :       gcc_assert (gimple_call_internal_p (exit_stmt, IFN_GOMP_SIMT_EXIT));
    1869                 :          0 :       gimple_stmt_iterator exit_gsi = gsi_for_stmt (exit_stmt);
    1870                 :          0 :       tree clobber = build_clobber (rectype);
    1871                 :          0 :       exit_stmt = gimple_build_assign (build_simple_mem_ref (simtrec), clobber);
    1872                 :          0 :       gsi_insert_before (&exit_gsi, exit_stmt, GSI_SAME_STMT);
    1873                 :            :     }
    1874                 :            :   else
    1875                 :          0 :     gcc_checking_assert (has_zero_uses (simtrec));
    1876                 :          0 : }
    1877                 :            : 
    1878                 :            : /* Callback for walk_gimple_stmt used to scan for SIMT-privatized variables.  */
    1879                 :            : 
    1880                 :            : static tree
    1881                 :          0 : find_simtpriv_var_op (tree *tp, int *walk_subtrees, void *)
    1882                 :            : {
    1883                 :          0 :   tree t = *tp;
    1884                 :            : 
    1885                 :          0 :   if (VAR_P (t)
    1886                 :          0 :       && DECL_HAS_VALUE_EXPR_P (t)
    1887                 :          0 :       && lookup_attribute ("omp simt private", DECL_ATTRIBUTES (t)))
    1888                 :            :     {
    1889                 :          0 :       *walk_subtrees = 0;
    1890                 :          0 :       return t;
    1891                 :            :     }
    1892                 :            :   return NULL_TREE;
    1893                 :            : }
    1894                 :            : 
    1895                 :            : /* Cleanup uses of SIMT placeholder internal functions: on non-SIMT targets,
    1896                 :            :    VF is 1 and LANE is 0; on SIMT targets, VF is folded to a constant, and
    1897                 :            :    LANE is kept to be expanded to RTL later on.  Also cleanup all other SIMT
    1898                 :            :    internal functions on non-SIMT targets, and likewise some SIMD internal
    1899                 :            :    functions on SIMT targets.  */
    1900                 :            : 
    1901                 :            : static unsigned int
    1902                 :      19828 : execute_omp_device_lower ()
    1903                 :            : {
    1904                 :      19828 :   int vf = targetm.simt.vf ? targetm.simt.vf () : 1;
    1905                 :      19828 :   bool regimplify = false;
    1906                 :      19828 :   basic_block bb;
    1907                 :      19828 :   gimple_stmt_iterator gsi;
    1908                 :      47604 :   FOR_EACH_BB_FN (bb, cfun)
    1909                 :     219833 :     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    1910                 :            :       {
    1911                 :     164281 :         gimple *stmt = gsi_stmt (gsi);
    1912                 :     164281 :         if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt))
    1913                 :     163556 :           continue;
    1914                 :        725 :         tree lhs = gimple_call_lhs (stmt), rhs = NULL_TREE;
    1915                 :        763 :         tree type = lhs ? TREE_TYPE (lhs) : integer_type_node;
    1916                 :        725 :         switch (gimple_call_internal_fn (stmt))
    1917                 :            :           {
    1918                 :          0 :           case IFN_GOMP_USE_SIMT:
    1919                 :          0 :             rhs = vf == 1 ? integer_zero_node : integer_one_node;
    1920                 :            :             break;
    1921                 :          0 :           case IFN_GOMP_SIMT_ENTER:
    1922                 :          0 :             rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
    1923                 :          0 :             goto simtreg_enter_exit;
    1924                 :          0 :           case IFN_GOMP_SIMT_ENTER_ALLOC:
    1925                 :          0 :             if (vf != 1)
    1926                 :          0 :               ompdevlow_adjust_simt_enter (&gsi, &regimplify);
    1927                 :          0 :             rhs = vf == 1 ? null_pointer_node : NULL_TREE;
    1928                 :          0 :             goto simtreg_enter_exit;
    1929                 :          0 :           case IFN_GOMP_SIMT_EXIT:
    1930                 :          0 :           simtreg_enter_exit:
    1931                 :          0 :             if (vf != 1)
    1932                 :          0 :               continue;
    1933                 :          0 :             unlink_stmt_vdef (stmt);
    1934                 :          0 :             break;
    1935                 :          0 :           case IFN_GOMP_SIMT_LANE:
    1936                 :          0 :           case IFN_GOMP_SIMT_LAST_LANE:
    1937                 :          0 :             rhs = vf == 1 ? build_zero_cst (type) : NULL_TREE;
    1938                 :            :             break;
    1939                 :          0 :           case IFN_GOMP_SIMT_VF:
    1940                 :          0 :             rhs = build_int_cst (type, vf);
    1941                 :          0 :             break;
    1942                 :          0 :           case IFN_GOMP_SIMT_ORDERED_PRED:
    1943                 :          0 :             rhs = vf == 1 ? integer_zero_node : NULL_TREE;
    1944                 :          0 :             if (rhs || !lhs)
    1945                 :          0 :               unlink_stmt_vdef (stmt);
    1946                 :            :             break;
    1947                 :          0 :           case IFN_GOMP_SIMT_VOTE_ANY:
    1948                 :          0 :           case IFN_GOMP_SIMT_XCHG_BFLY:
    1949                 :          0 :           case IFN_GOMP_SIMT_XCHG_IDX:
    1950                 :          0 :             rhs = vf == 1 ? gimple_call_arg (stmt, 0) : NULL_TREE;
    1951                 :            :             break;
    1952                 :          0 :           case IFN_GOMP_SIMD_LANE:
    1953                 :          0 :           case IFN_GOMP_SIMD_LAST_LANE:
    1954                 :          0 :             rhs = vf != 1 ? build_zero_cst (type) : NULL_TREE;
    1955                 :            :             break;
    1956                 :          0 :           case IFN_GOMP_SIMD_VF:
    1957                 :          0 :             rhs = vf != 1 ? build_one_cst (type) : NULL_TREE;
    1958                 :            :             break;
    1959                 :        725 :           default:
    1960                 :        725 :             continue;
    1961                 :            :           }
    1962                 :          0 :         if (lhs && !rhs)
    1963                 :          0 :           continue;
    1964                 :          0 :         stmt = lhs ? gimple_build_assign (lhs, rhs) : gimple_build_nop ();
    1965                 :          0 :         gsi_replace (&gsi, stmt, false);
    1966                 :            :       }
    1967                 :      19828 :   if (regimplify)
    1968                 :          0 :     FOR_EACH_BB_REVERSE_FN (bb, cfun)
    1969                 :          0 :       for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
    1970                 :          0 :         if (walk_gimple_stmt (&gsi, NULL, find_simtpriv_var_op, NULL))
    1971                 :            :           {
    1972                 :          0 :             if (gimple_clobber_p (gsi_stmt (gsi)))
    1973                 :          0 :               gsi_remove (&gsi, true);
    1974                 :            :             else
    1975                 :          0 :               gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
    1976                 :            :           }
    1977                 :      19828 :   if (vf != 1)
    1978                 :          0 :     cfun->has_force_vectorize_loops = false;
    1979                 :      19828 :   return 0;
    1980                 :            : }
    1981                 :            : 
    1982                 :            : namespace {
    1983                 :            : 
    1984                 :            : const pass_data pass_data_omp_device_lower =
    1985                 :            : {
    1986                 :            :   GIMPLE_PASS, /* type */
    1987                 :            :   "ompdevlow", /* name */
    1988                 :            :   OPTGROUP_OMP, /* optinfo_flags */
    1989                 :            :   TV_NONE, /* tv_id */
    1990                 :            :   PROP_cfg, /* properties_required */
    1991                 :            :   PROP_gimple_lomp_dev, /* properties_provided */
    1992                 :            :   0, /* properties_destroyed */
    1993                 :            :   0, /* todo_flags_start */
    1994                 :            :   TODO_update_ssa, /* todo_flags_finish */
    1995                 :            : };
    1996                 :            : 
    1997                 :            : class pass_omp_device_lower : public gimple_opt_pass
    1998                 :            : {
    1999                 :            : public:
    2000                 :     200773 :   pass_omp_device_lower (gcc::context *ctxt)
    2001                 :     401546 :     : gimple_opt_pass (pass_data_omp_device_lower, ctxt)
    2002                 :            :   {}
    2003                 :            : 
    2004                 :            :   /* opt_pass methods: */
    2005                 :     944512 :   virtual bool gate (function *fun)
    2006                 :            :     {
    2007                 :     944512 :       return !(fun->curr_properties & PROP_gimple_lomp_dev);
    2008                 :            :     }
    2009                 :      19828 :   virtual unsigned int execute (function *)
    2010                 :            :     {
    2011                 :      19828 :       return execute_omp_device_lower ();
    2012                 :            :     }
    2013                 :            : 
    2014                 :            : }; // class pass_expand_omp_ssa
    2015                 :            : 
    2016                 :            : } // anon namespace
    2017                 :            : 
    2018                 :            : gimple_opt_pass *
    2019                 :     200773 : make_pass_omp_device_lower (gcc::context *ctxt)
    2020                 :            : {
    2021                 :     200773 :   return new pass_omp_device_lower (ctxt);
    2022                 :            : }
    2023                 :            : 
    2024                 :            : /* "omp declare target link" handling pass.  */
    2025                 :            : 
    2026                 :            : namespace {
    2027                 :            : 
    2028                 :            : const pass_data pass_data_omp_target_link =
    2029                 :            : {
    2030                 :            :   GIMPLE_PASS,                  /* type */
    2031                 :            :   "omptargetlink",            /* name */
    2032                 :            :   OPTGROUP_OMP,                 /* optinfo_flags */
    2033                 :            :   TV_NONE,                      /* tv_id */
    2034                 :            :   PROP_ssa,                     /* properties_required */
    2035                 :            :   0,                            /* properties_provided */
    2036                 :            :   0,                            /* properties_destroyed */
    2037                 :            :   0,                            /* todo_flags_start */
    2038                 :            :   TODO_update_ssa,              /* todo_flags_finish */
    2039                 :            : };
    2040                 :            : 
    2041                 :            : class pass_omp_target_link : public gimple_opt_pass
    2042                 :            : {
    2043                 :            : public:
    2044                 :     200773 :   pass_omp_target_link (gcc::context *ctxt)
    2045                 :     401546 :     : gimple_opt_pass (pass_data_omp_target_link, ctxt)
    2046                 :            :   {}
    2047                 :            : 
    2048                 :            :   /* opt_pass methods: */
    2049                 :     944512 :   virtual bool gate (function *fun)
    2050                 :            :     {
    2051                 :            : #ifdef ACCEL_COMPILER
    2052                 :            :       return offloading_function_p (fun->decl);
    2053                 :            : #else
    2054                 :     944512 :       (void) fun;
    2055                 :     944512 :       return false;
    2056                 :            : #endif
    2057                 :            :     }
    2058                 :            : 
    2059                 :            :   virtual unsigned execute (function *);
    2060                 :            : };
    2061                 :            : 
    2062                 :            : /* Callback for walk_gimple_stmt used to scan for link var operands.  */
    2063                 :            : 
    2064                 :            : static tree
    2065                 :          0 : find_link_var_op (tree *tp, int *walk_subtrees, void *)
    2066                 :            : {
    2067                 :          0 :   tree t = *tp;
    2068                 :            : 
    2069                 :          0 :   if (VAR_P (t)
    2070                 :          0 :       && DECL_HAS_VALUE_EXPR_P (t)
    2071                 :          0 :       && is_global_var (t)
    2072                 :          0 :       && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (t)))
    2073                 :            :     {
    2074                 :          0 :       *walk_subtrees = 0;
    2075                 :          0 :       return t;
    2076                 :            :     }
    2077                 :            : 
    2078                 :            :   return NULL_TREE;
    2079                 :            : }
    2080                 :            : 
    2081                 :            : unsigned
    2082                 :          0 : pass_omp_target_link::execute (function *fun)
    2083                 :            : {
    2084                 :          0 :   basic_block bb;
    2085                 :          0 :   FOR_EACH_BB_FN (bb, fun)
    2086                 :            :     {
    2087                 :          0 :       gimple_stmt_iterator gsi;
    2088                 :          0 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    2089                 :          0 :         if (walk_gimple_stmt (&gsi, NULL, find_link_var_op, NULL))
    2090                 :          0 :           gimple_regimplify_operands (gsi_stmt (gsi), &gsi);
    2091                 :            :     }
    2092                 :            : 
    2093                 :          0 :   return 0;
    2094                 :            : }
    2095                 :            : 
    2096                 :            : } // anon namespace
    2097                 :            : 
    2098                 :            : gimple_opt_pass *
    2099                 :     200773 : make_pass_omp_target_link (gcc::context *ctxt)
    2100                 :            : {
    2101                 :     200773 :   return new pass_omp_target_link (ctxt);
    2102                 :            : }

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.