mirror of git://gcc.gnu.org/git/gcc.git
3583 lines
104 KiB
C++
3583 lines
104 KiB
C++
/* Copyright (C) 2002-2025 Free Software Foundation, Inc.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tree.h"
|
|
#include "fold-const.h"
|
|
#include "gfortran.h"
|
|
#include "trans.h"
|
|
#include "trans-const.h"
|
|
#include "trans-types.h"
|
|
#include "trans-array.h"
|
|
#include "trans-descriptor.h"
|
|
|
|
|
|
/******************************************************************************/
|
|
/* BIND(C) array descriptor (AKA CFI array descriptor) access routines */
|
|
/******************************************************************************/
|
|
|
|
/* Build expressions to access members of the CFI descriptor. */
|
|
#define CFI_FIELD_BASE_ADDR 0
|
|
#define CFI_FIELD_ELEM_LEN 1
|
|
#define CFI_FIELD_VERSION 2
|
|
#define CFI_FIELD_RANK 3
|
|
#define CFI_FIELD_ATTRIBUTE 4
|
|
#define CFI_FIELD_TYPE 5
|
|
#define CFI_FIELD_DIM 6
|
|
|
|
#define CFI_DIM_FIELD_LOWER_BOUND 0
|
|
#define CFI_DIM_FIELD_EXTENT 1
|
|
#define CFI_DIM_FIELD_SM 2
|
|
|
|
static tree
|
|
gfc_get_cfi_descriptor_field (tree desc, unsigned field_idx)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (TREE_CODE (type) == RECORD_TYPE
|
|
&& TYPE_FIELDS (type)
|
|
&& (strcmp ("base_addr",
|
|
IDENTIFIER_POINTER (DECL_NAME (TYPE_FIELDS (type))))
|
|
== 0));
|
|
tree field = gfc_advance_chain (TYPE_FIELDS (type), field_idx);
|
|
gcc_assert (field != NULL_TREE);
|
|
|
|
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
|
|
desc, field, NULL_TREE);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_base_addr (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_BASE_ADDR);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_elem_len (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ELEM_LEN);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_version (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_VERSION);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_rank (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_RANK);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_type (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_TYPE);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_desc_attribute (tree desc)
|
|
{
|
|
return gfc_get_cfi_descriptor_field (desc, CFI_FIELD_ATTRIBUTE);
|
|
}
|
|
|
|
static tree
|
|
gfc_get_cfi_dim_item (tree desc, tree idx, unsigned field_idx)
|
|
{
|
|
tree tmp = gfc_get_cfi_descriptor_field (desc, CFI_FIELD_DIM);
|
|
tmp = gfc_build_array_ref (tmp, idx, true);
|
|
tree field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), field_idx);
|
|
gcc_assert (field != NULL_TREE);
|
|
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
|
|
tmp, field, NULL_TREE);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_dim_lbound (tree desc, tree idx)
|
|
{
|
|
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_LOWER_BOUND);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_dim_extent (tree desc, tree idx)
|
|
{
|
|
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_EXTENT);
|
|
}
|
|
|
|
tree
|
|
gfc_get_cfi_dim_sm (tree desc, tree idx)
|
|
{
|
|
return gfc_get_cfi_dim_item (desc, idx, CFI_DIM_FIELD_SM);
|
|
}
|
|
|
|
#undef CFI_FIELD_BASE_ADDR
|
|
#undef CFI_FIELD_ELEM_LEN
|
|
#undef CFI_FIELD_VERSION
|
|
#undef CFI_FIELD_RANK
|
|
#undef CFI_FIELD_ATTRIBUTE
|
|
#undef CFI_FIELD_TYPE
|
|
#undef CFI_FIELD_DIM
|
|
|
|
#undef CFI_DIM_FIELD_LOWER_BOUND
|
|
#undef CFI_DIM_FIELD_EXTENT
|
|
#undef CFI_DIM_FIELD_SM
|
|
|
|
|
|
/******************************************************************************/
|
|
/* Array descriptor low level access routines. */
|
|
/******************************************************************************/
|
|
|
|
/* Build expressions to access the members of an array descriptor.
|
|
It's surprisingly easy to mess up here, so never access
|
|
an array descriptor by "brute force", always use these
|
|
functions. This also avoids problems if we change the format
|
|
of an array descriptor.
|
|
|
|
To understand these magic numbers, look at the comments
|
|
before gfc_build_array_type() in trans-types.cc.
|
|
|
|
The code within these defines should be the only code which knows the format
|
|
of an array descriptor.
|
|
|
|
Any code just needing to read obtain the bounds of an array should use
|
|
gfc_conv_array_* rather than the following functions as these will return
|
|
know constant values, and work with arrays which do not have descriptors.
|
|
|
|
Don't forget to #undef these! */
|
|
|
|
enum descriptor_field
|
|
{
|
|
DATA_FIELD = 0,
|
|
OFFSET_FIELD,
|
|
DTYPE_FIELD,
|
|
SPAN_FIELD,
|
|
DIMENSION_FIELD,
|
|
CAF_TOKEN_FIELD,
|
|
};
|
|
|
|
enum dim_subfield
|
|
{
|
|
STRIDE_SUBFIELD = 0,
|
|
LBOUND_SUBFIELD,
|
|
UBOUND_SUBFIELD,
|
|
};
|
|
|
|
enum dtype_subfield
|
|
{
|
|
GFC_DTYPE_ELEM_LEN = 0,
|
|
GFC_DTYPE_VERSION,
|
|
GFC_DTYPE_RANK,
|
|
GFC_DTYPE_TYPE,
|
|
GFC_DTYPE_ATTR
|
|
};
|
|
|
|
enum attr_subfield
|
|
{
|
|
GFC_ATTR_ATTRIBUTE,
|
|
GFC_ATTR_BYTES_COUNTED_STRIDES
|
|
};
|
|
|
|
static tree
|
|
get_type_field (tree type, unsigned field_idx, tree field_type = NULL_TREE)
|
|
{
|
|
tree field = gfc_advance_chain (TYPE_FIELDS (type), field_idx);
|
|
gcc_assert (field != NULL_TREE
|
|
&& (field_type == NULL_TREE
|
|
|| TREE_TYPE (field) == field_type));
|
|
|
|
return field;
|
|
}
|
|
|
|
static tree
|
|
get_ref_comp (tree ref, unsigned field_idx, tree type = NULL_TREE)
|
|
{
|
|
tree field = get_type_field (TREE_TYPE (ref), field_idx, type);
|
|
return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
|
|
ref, field, NULL_TREE);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descr_comp (tree desc, descriptor_field field, tree type = NULL_TREE)
|
|
{
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)));
|
|
|
|
return get_ref_comp (desc, field, type);
|
|
}
|
|
|
|
|
|
static void
|
|
set_value (stmtblock_t *block, tree ref, tree value)
|
|
{
|
|
location_t loc = input_location;
|
|
gfc_add_modify_loc (loc, block, ref,
|
|
fold_convert_loc (loc, TREE_TYPE (ref), value));
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_data (tree desc)
|
|
{
|
|
return get_descr_comp (desc, DATA_FIELD);
|
|
}
|
|
|
|
/* This provides READ-ONLY access to the data field. The field itself
|
|
doesn't have the proper type. */
|
|
|
|
tree
|
|
gfc_conv_descriptor_data_get (tree desc)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
|
|
|
|
location_t loc = input_location;
|
|
tree field = get_descriptor_data (desc);
|
|
tree target_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc));
|
|
return non_lvalue_loc (loc, fold_convert_loc (loc, target_type, field));
|
|
}
|
|
|
|
/* This provides WRITE access to the data field.
|
|
|
|
TUPLES_P is true if we are generating tuples.
|
|
|
|
This function gets called through the following macros:
|
|
gfc_conv_descriptor_data_set
|
|
gfc_conv_descriptor_data_set. */
|
|
|
|
void
|
|
gfc_conv_descriptor_data_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_data (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_offset (tree desc)
|
|
{
|
|
return get_descr_comp (desc, OFFSET_FIELD, gfc_array_index_type);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_offset_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_offset (desc));
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_offset_units_get (tree desc)
|
|
{
|
|
gcc_assert (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)));
|
|
return gfc_conv_descriptor_offset_get (desc);
|
|
}
|
|
|
|
static tree get_descriptor_elem_len (tree desc);
|
|
|
|
tree
|
|
gfc_conv_descriptor_offset_bytes_get (tree desc)
|
|
{
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
|
return gfc_conv_descriptor_offset_get (desc);
|
|
else
|
|
{
|
|
tree offset_units = gfc_conv_descriptor_offset_get (desc);
|
|
tree elem_len = get_descriptor_elem_len (desc);
|
|
return fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
offset_units, elem_len);
|
|
}
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_offset_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_offset (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_dtype (tree desc)
|
|
{
|
|
return get_descr_comp (desc, DTYPE_FIELD, get_dtype_type_node ());
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_dtype_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_dtype (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_dtype_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_dtype (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
gfc_conv_descriptor_span (tree desc)
|
|
{
|
|
return get_descr_comp (desc, SPAN_FIELD, gfc_array_index_type);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_span_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, gfc_conv_descriptor_span (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_span_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, gfc_conv_descriptor_span (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_dtype_comp (tree desc, dtype_subfield field, tree type = NULL_TREE)
|
|
{
|
|
tree dtype_ref = get_descriptor_dtype (desc);
|
|
return get_ref_comp (dtype_ref, field, type);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_rank (tree desc)
|
|
{
|
|
return get_dtype_comp (desc, GFC_DTYPE_RANK, signed_char_type_node);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_rank_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_rank (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_rank_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_rank (desc), value);
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_rank_set (stmtblock_t *block, tree desc, int value)
|
|
{
|
|
gfc_conv_descriptor_rank_set (block, desc, gfc_rank_cst[value]);
|
|
}
|
|
|
|
static tree
|
|
get_descriptor_version (tree desc)
|
|
{
|
|
return get_dtype_comp (desc, GFC_DTYPE_VERSION, integer_type_node);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_version_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_version (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_version_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_version (desc), value);
|
|
}
|
|
|
|
|
|
/* Return the element length from the descriptor dtype field. */
|
|
|
|
static tree
|
|
get_descriptor_elem_len (tree desc)
|
|
{
|
|
return get_dtype_comp (desc, GFC_DTYPE_ELEM_LEN, size_type_node);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_elem_len_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_elem_len (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_elem_len_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_elem_len (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_type (tree desc)
|
|
{
|
|
return get_dtype_comp (desc, GFC_DTYPE_TYPE, signed_char_type_node);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_type_get (tree desc)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_type (desc));
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_type_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_type (desc), value);
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_type_set (stmtblock_t *block, tree desc, int value)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
|
|
|
|
tree dtype = get_type_field (type, DTYPE_FIELD);
|
|
|
|
tree field = get_type_field (TREE_TYPE (dtype), GFC_DTYPE_TYPE);
|
|
|
|
tree type_value = build_int_cst (TREE_TYPE (field), value);
|
|
gfc_conv_descriptor_type_set (block, desc, type_value);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_type_set (tree desc, tree value)
|
|
{
|
|
stmtblock_t block;
|
|
|
|
gfc_init_block (&block);
|
|
gfc_conv_descriptor_type_set (&block, desc, value);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_type_set (tree desc, int value)
|
|
{
|
|
stmtblock_t block;
|
|
|
|
gfc_init_block (&block);
|
|
gfc_conv_descriptor_type_set (&block, desc, value);
|
|
return gfc_finish_block (&block);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_attr_comp (tree desc)
|
|
{
|
|
return get_dtype_comp (desc, GFC_DTYPE_ATTR, gfc_get_attr_type_node ());
|
|
}
|
|
|
|
|
|
static tree
|
|
get_attr_comp (tree desc, attr_subfield field, tree type = NULL_TREE)
|
|
{
|
|
tree attr_ref = get_attr_comp (desc);
|
|
return get_ref_comp (attr_ref, field, type);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_bytes_counted_strides (tree desc)
|
|
{
|
|
return get_attr_comp (desc, GFC_ATTR_BYTES_COUNTED_STRIDES, short_unsigned_type_node);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_bytes_counted_strides_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, get_descriptor_bytes_counted_strides (desc), value);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_bytes_counted_strides_set (stmtblock_t *block, tree desc, int value)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
|
|
gcc_assert (value == 0 || value == 1);
|
|
|
|
tree dtype = get_type_field (type, DTYPE_FIELD);
|
|
tree attr = get_type_field (TREE_TYPE (dtype), GFC_DTYPE_ATTR);
|
|
tree field = get_type_field (TREE_TYPE (attr), GFC_ATTR_BYTES_COUNTED_STRIDES);
|
|
|
|
tree type_value = build_int_cst (TREE_TYPE (field), value);
|
|
gfc_conv_descriptor_bytes_counted_strides_set (block, desc, type_value);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_bytes_counted_strides_set (stmtblock_t *block, tree desc)
|
|
{
|
|
int value = GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc));
|
|
gfc_conv_descriptor_bytes_counted_strides_set (block, desc, value);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_get_descriptor_dimension (tree desc)
|
|
{
|
|
tree field = get_descr_comp (desc, DIMENSION_FIELD);
|
|
gcc_assert (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
|
|
&& TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == RECORD_TYPE);
|
|
return field;
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_dimension (tree desc, tree dim)
|
|
{
|
|
tree tmp;
|
|
|
|
tmp = gfc_get_descriptor_dimension (desc);
|
|
|
|
return gfc_build_array_ref (tmp, dim, true);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_dimension_get (tree desc, tree dim)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_dimension (desc, dim));
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_dimension_get (tree desc, int dim)
|
|
{
|
|
return gfc_conv_descriptor_dimension_get (desc, gfc_rank_cst[dim]);
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_dimension_set (stmtblock_t *block, tree desc, tree dim,
|
|
tree value)
|
|
{
|
|
set_value (block, get_descriptor_dimension (desc, dim), value);
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_dimension_set (stmtblock_t *block, tree desc, int dim,
|
|
tree value)
|
|
{
|
|
gfc_conv_descriptor_dimension_set (block, desc, gfc_rank_cst[dim], value);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_conv_descriptor_token (tree desc)
|
|
{
|
|
gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
|
|
tree field = get_descr_comp (desc, CAF_TOKEN_FIELD);
|
|
/* Should be a restricted pointer - except in the finalization wrapper. */
|
|
gcc_assert (TREE_TYPE (field) == prvoid_type_node
|
|
|| TREE_TYPE (field) == pvoid_type_node);
|
|
return field;
|
|
}
|
|
|
|
void
|
|
gfc_conv_descriptor_token_set (stmtblock_t *block, tree desc, tree value)
|
|
{
|
|
set_value (block, gfc_conv_descriptor_token (desc), value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descr_dim_comp (tree desc, tree dim, dim_subfield field,
|
|
tree type = NULL_TREE)
|
|
{
|
|
tree tmp = get_descriptor_dimension (desc, dim);
|
|
return get_ref_comp (tmp, field, type);
|
|
}
|
|
|
|
static tree
|
|
get_descriptor_stride (tree desc, tree dim)
|
|
{
|
|
return get_descr_dim_comp (desc, dim, STRIDE_SUBFIELD, gfc_array_index_type);
|
|
}
|
|
|
|
static bool
|
|
is_class_type (tree desc)
|
|
{
|
|
STRIP_NOPS (desc);
|
|
|
|
if (TREE_CODE (desc) == COMPONENT_REF
|
|
&& GFC_CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (desc, 0))))
|
|
return true;
|
|
|
|
if (DECL_P (desc)
|
|
&& DECL_LANG_SPECIFIC (desc))
|
|
if (tree saved_desc = GFC_DECL_SAVED_DESCRIPTOR (desc))
|
|
{
|
|
if (GFC_CLASS_TYPE_P (TREE_TYPE (saved_desc)))
|
|
saved_desc = gfc_class_data_get (saved_desc);
|
|
|
|
return is_class_type (saved_desc);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_stride_get (tree desc, tree dim)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
|
|
if (integer_zerop (dim)
|
|
&& (GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE
|
|
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_SHAPE_CONT
|
|
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK_CONT
|
|
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK_ALLOCATABLE
|
|
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK_POINTER_CONT
|
|
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT)
|
|
&& !(is_class_type (desc)))
|
|
return gfc_index_one_node;
|
|
|
|
return non_lvalue_loc (input_location, get_descriptor_stride (desc, dim));
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_stride_get (tree desc, int dim)
|
|
{
|
|
return gfc_conv_descriptor_stride_get (desc, gfc_rank_cst[dim]);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_conv_descriptor_stride_units_get (tree desc, tree dim)
|
|
{
|
|
gcc_assert (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)));
|
|
return gfc_conv_descriptor_stride_get (desc, dim);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_conv_descriptor_stride_bytes_get (tree desc, tree dim)
|
|
{
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
|
return gfc_conv_descriptor_stride_get (desc, dim);
|
|
else
|
|
{
|
|
tree stride_units = gfc_conv_descriptor_stride_get (desc, dim);
|
|
tree element_len = gfc_conv_descriptor_elem_len_get (desc);
|
|
element_len = fold_convert_loc (input_location, gfc_array_index_type,
|
|
element_len);
|
|
return fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
stride_units, element_len);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_conv_descriptor_stride_set (stmtblock_t *block, tree desc,
|
|
tree dim, tree value)
|
|
{
|
|
set_value (block, get_descriptor_stride (desc, dim), value);
|
|
}
|
|
|
|
static tree
|
|
get_descriptor_lbound (tree desc, tree dim)
|
|
{
|
|
return get_descr_dim_comp (desc, dim, LBOUND_SUBFIELD, gfc_array_index_type);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_lbound_get (tree desc, tree dim)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_lbound (desc, dim));
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_lbound_get (tree desc, int dim)
|
|
{
|
|
return gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[dim]);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_lbound_set (stmtblock_t *block, tree desc,
|
|
tree dim, tree value)
|
|
{
|
|
set_value (block, get_descriptor_lbound (desc, dim), value);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_lbound_set (stmtblock_t *block, tree desc,
|
|
int dim, tree value)
|
|
{
|
|
gfc_conv_descriptor_lbound_set (block, desc, gfc_rank_cst[dim], value);
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_ubound (tree desc, tree dim)
|
|
{
|
|
return get_descr_dim_comp (desc, dim, UBOUND_SUBFIELD, gfc_array_index_type);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_ubound_get (tree desc, tree dim)
|
|
{
|
|
return non_lvalue_loc (input_location, get_descriptor_ubound (desc, dim));
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_ubound_get (tree desc, int dim)
|
|
{
|
|
return gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[dim]);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_ubound_set (stmtblock_t *block, tree desc,
|
|
tree dim, tree value)
|
|
{
|
|
set_value (block, get_descriptor_ubound (desc, dim), value);
|
|
}
|
|
|
|
static void
|
|
gfc_conv_descriptor_ubound_set (stmtblock_t *block, tree desc,
|
|
int dim, tree value)
|
|
{
|
|
gfc_conv_descriptor_ubound_set (block, desc, gfc_rank_cst[dim], value);
|
|
}
|
|
|
|
tree
|
|
gfc_conv_descriptor_sm_get (tree desc, tree dim)
|
|
{
|
|
return gfc_conv_descriptor_stride_bytes_get (desc, dim);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_conv_descriptor_extent_get (tree desc, tree dim)
|
|
{
|
|
tree lbound = gfc_conv_descriptor_lbound_get (desc, dim);
|
|
tree ubound = gfc_conv_descriptor_ubound_get (desc, dim);
|
|
|
|
tree tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
lbound, gfc_index_one_node);
|
|
return fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
ubound, tmp);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Array descriptor higher level routines. *
|
|
******************************************************************************/
|
|
|
|
static tree
|
|
get_attr_constructor (bool bytes_counted_strides)
|
|
{
|
|
tree attr;
|
|
tree field;
|
|
vec<constructor_elt, va_gc> *v = NULL;
|
|
|
|
tree attr_type_node = gfc_get_attr_type_node ();
|
|
field = gfc_advance_chain (TYPE_FIELDS (attr_type_node),
|
|
GFC_ATTR_BYTES_COUNTED_STRIDES);
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
build_int_cst (TREE_TYPE (field),
|
|
bytes_counted_strides));
|
|
|
|
attr = build_constructor (attr_type_node, v);
|
|
|
|
return attr;
|
|
}
|
|
|
|
|
|
/* Return the DTYPE for an array. This describes the type and type parameters
|
|
of the array. */
|
|
/* TODO: Only call this when the value is actually used, and make all the
|
|
unknown cases abort. */
|
|
|
|
tree
|
|
get_dtype_rank_type_size (int rank, bt n, bool bytes_counted_strides,
|
|
tree size)
|
|
{
|
|
tree dtype;
|
|
tree field;
|
|
vec<constructor_elt, va_gc> *v = NULL;
|
|
|
|
tree dtype_type_node = get_dtype_type_node ();
|
|
if (size)
|
|
{
|
|
STRIP_NOPS (size);
|
|
size = fold_convert (size_type_node, size);
|
|
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
|
|
GFC_DTYPE_ELEM_LEN);
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
fold_convert (TREE_TYPE (field), size));
|
|
}
|
|
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
|
|
GFC_DTYPE_VERSION);
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
build_zero_cst (TREE_TYPE (field)));
|
|
|
|
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
|
|
GFC_DTYPE_RANK);
|
|
if (rank >= 0)
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
build_int_cst (TREE_TYPE (field), rank));
|
|
|
|
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
|
|
GFC_DTYPE_TYPE);
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
build_int_cst (TREE_TYPE (field), n));
|
|
|
|
field = gfc_advance_chain (TYPE_FIELDS (dtype_type_node),
|
|
GFC_DTYPE_ATTR);
|
|
CONSTRUCTOR_APPEND_ELT (v, field,
|
|
get_attr_constructor (bytes_counted_strides));
|
|
|
|
dtype = build_constructor (dtype_type_node, v);
|
|
|
|
return dtype;
|
|
}
|
|
|
|
|
|
/* Return the DTYPE for an array. This describes the type and type parameters
|
|
of the array. */
|
|
/* TODO: Only call this when the value is actually used, and make all the
|
|
unknown cases abort. */
|
|
|
|
tree
|
|
gfc_get_dtype_rank_type_slen (int rank, tree etype, bool bytes_counted_strides,
|
|
tree length)
|
|
{
|
|
tree ptype;
|
|
bt n;
|
|
|
|
ptype = etype;
|
|
while (TREE_CODE (etype) == POINTER_TYPE
|
|
|| TREE_CODE (etype) == ARRAY_TYPE)
|
|
{
|
|
ptype = etype;
|
|
etype = TREE_TYPE (etype);
|
|
}
|
|
|
|
gcc_assert (etype);
|
|
|
|
switch (TREE_CODE (etype))
|
|
{
|
|
case INTEGER_TYPE:
|
|
if (TREE_CODE (ptype) == ARRAY_TYPE
|
|
&& TYPE_STRING_FLAG (ptype))
|
|
n = BT_CHARACTER;
|
|
else
|
|
{
|
|
if (TYPE_UNSIGNED (etype))
|
|
n = BT_UNSIGNED;
|
|
else
|
|
n = BT_INTEGER;
|
|
}
|
|
break;
|
|
|
|
case BOOLEAN_TYPE:
|
|
n = BT_LOGICAL;
|
|
break;
|
|
|
|
case REAL_TYPE:
|
|
n = BT_REAL;
|
|
break;
|
|
|
|
case COMPLEX_TYPE:
|
|
n = BT_COMPLEX;
|
|
break;
|
|
|
|
case RECORD_TYPE:
|
|
if (GFC_CLASS_TYPE_P (etype))
|
|
n = BT_CLASS;
|
|
else
|
|
n = BT_DERIVED;
|
|
break;
|
|
|
|
case FUNCTION_TYPE:
|
|
case VOID_TYPE:
|
|
n = BT_VOID;
|
|
break;
|
|
|
|
default:
|
|
/* TODO: Don't do dtype for temporary descriptorless arrays. */
|
|
/* We can encounter strange array types for temporary arrays. */
|
|
gcc_unreachable ();
|
|
}
|
|
|
|
tree size = NULL_TREE;
|
|
switch (n)
|
|
{
|
|
case BT_CHARACTER:
|
|
gcc_assert (TREE_CODE (ptype) == ARRAY_TYPE);
|
|
size = gfc_get_character_len_in_bytes (ptype, length);
|
|
break;
|
|
case BT_VOID:
|
|
if (TREE_CODE (ptype) == POINTER_TYPE)
|
|
size = size_in_bytes (ptype);
|
|
break;
|
|
default:
|
|
size = size_in_bytes (etype);
|
|
break;
|
|
}
|
|
|
|
return get_dtype_rank_type_size (rank, n, bytes_counted_strides, size);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_get_dtype_rank_type (int rank, tree etype, bool bytes_counted_strides)
|
|
{
|
|
return gfc_get_dtype_rank_type_slen (rank, etype, bytes_counted_strides,
|
|
NULL_TREE);
|
|
}
|
|
|
|
|
|
enum descriptor_write_case
|
|
{
|
|
POINTER_NULLIFY,
|
|
RESULT_INIT,
|
|
ABSENT_ARG_INIT,
|
|
STATIC_INIT,
|
|
NONSTATIC_INIT
|
|
};
|
|
|
|
|
|
class constructor_elements
|
|
{
|
|
vec<constructor_elt, va_gc> *values;
|
|
bool constant;
|
|
|
|
public:
|
|
constructor_elements () : values (nullptr), constant (true) {}
|
|
void add_value (tree elt, tree val);
|
|
tree build (tree type);
|
|
};
|
|
|
|
|
|
void
|
|
constructor_elements::add_value (tree elt, tree val)
|
|
{
|
|
CONSTRUCTOR_APPEND_ELT (values, elt, val);
|
|
if (!TREE_CONSTANT (val))
|
|
constant = false;
|
|
}
|
|
|
|
|
|
tree
|
|
constructor_elements::build (tree type)
|
|
{
|
|
tree cstr = build_constructor (type, values);
|
|
if (constant)
|
|
TREE_CONSTANT (cstr) = 1;
|
|
|
|
return cstr;
|
|
}
|
|
|
|
|
|
struct descriptor_write
|
|
{
|
|
const enum write_type
|
|
{
|
|
STATIC_INIT,
|
|
REGULAR_ASSIGN
|
|
}
|
|
type;
|
|
|
|
const tree ref;
|
|
|
|
union u
|
|
{
|
|
struct rw
|
|
{
|
|
stmtblock_t * const block;
|
|
|
|
rw (stmtblock_t *b) : block(b) {}
|
|
}
|
|
regular_assign;
|
|
|
|
constructor_elements static_init;
|
|
|
|
u(stmtblock_t *block) : regular_assign (block) {}
|
|
u() : static_init () {}
|
|
}
|
|
u;
|
|
|
|
descriptor_write (tree r, stmtblock_t *b)
|
|
: type (REGULAR_ASSIGN), ref (r), u (b) {}
|
|
descriptor_write (tree d) : type (STATIC_INIT), ref (d), u () {}
|
|
};
|
|
|
|
|
|
struct value_source
|
|
{
|
|
const descriptor_write_case type;
|
|
|
|
union u
|
|
{
|
|
struct nsi
|
|
{
|
|
gfc_symbol * const sym;
|
|
gfc_expr * const expr;
|
|
tree string_length;
|
|
|
|
nsi (gfc_symbol *s, gfc_expr *e, tree sl)
|
|
: sym (s), expr (e), string_length (sl) {}
|
|
}
|
|
nonstatic_init;
|
|
|
|
struct si
|
|
{
|
|
gfc_symbol * const sym;
|
|
|
|
si (gfc_symbol *s) : sym (s) {}
|
|
}
|
|
static_init;
|
|
|
|
u () {}
|
|
u (gfc_symbol *s) : static_init (s) {}
|
|
u (gfc_symbol *s, gfc_expr *e, tree sl) : nonstatic_init (s, e, sl) {}
|
|
}
|
|
u;
|
|
|
|
value_source (descriptor_write_case t) : type (t), u () {}
|
|
value_source (gfc_symbol *s) : type (STATIC_INIT), u (s) {}
|
|
value_source (gfc_symbol *s, gfc_expr *e, tree sl)
|
|
: type (NONSTATIC_INIT), u (s, e, sl) {}
|
|
};
|
|
|
|
|
|
static void
|
|
set_descriptor_field (descriptor_write &dest, descriptor_field field, tree value)
|
|
{
|
|
if (dest.type == descriptor_write::STATIC_INIT)
|
|
{
|
|
tree field_decl = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (dest.ref)),
|
|
field);
|
|
dest.u.static_init.add_value (field_decl, value);
|
|
}
|
|
else
|
|
{
|
|
tree comp_ref = get_ref_comp (dest.ref, field);
|
|
set_value (dest.u.regular_assign.block, comp_ref, value);
|
|
}
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_data_value (const value_source &src)
|
|
{
|
|
if (src.type == NONSTATIC_INIT)
|
|
{
|
|
gfc_symbol *sym = src.u.nonstatic_init.sym;
|
|
|
|
symbol_attribute attr = gfc_symbol_attr (sym);
|
|
if (!attr.save
|
|
&& (attr.allocatable
|
|
|| (attr.pointer && (gfc_option.rtcheck & GFC_RTCHECK_POINTER))))
|
|
return null_pointer_node;
|
|
else
|
|
return NULL_TREE;
|
|
}
|
|
else
|
|
return null_pointer_node;
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_dtype_value (tree descr, const value_source &src)
|
|
{
|
|
if (src.type == NONSTATIC_INIT)
|
|
{
|
|
gfc_symbol *sym = src.u.nonstatic_init.sym;
|
|
gfc_expr *expr = src.u.nonstatic_init.expr;
|
|
tree string_length = src.u.nonstatic_init.string_length;
|
|
|
|
gfc_array_spec *as;
|
|
if (sym->ts.type == BT_CLASS)
|
|
as = CLASS_DATA (sym)->as;
|
|
else
|
|
as = sym->as;
|
|
|
|
int rank;
|
|
if (as == nullptr)
|
|
rank = 0;
|
|
else if (as->type != AS_ASSUMED_RANK)
|
|
rank = as->rank;
|
|
else if (expr)
|
|
rank = expr->rank;
|
|
else
|
|
rank = -1;
|
|
|
|
tree type = TREE_TYPE (descr);
|
|
tree etype = gfc_get_element_type (type);
|
|
bool bytes_counted_strides = GFC_BYTES_STRIDES_ARRAY_TYPE_P (type);
|
|
return gfc_get_dtype_rank_type_slen (rank, etype, bytes_counted_strides,
|
|
string_length);
|
|
}
|
|
else if (src.type == STATIC_INIT)
|
|
{
|
|
gfc_symbol *sym = src.u.nonstatic_init.sym;
|
|
|
|
gfc_array_spec *as;
|
|
if (sym->ts.type == BT_CLASS)
|
|
as = CLASS_DATA (sym)->as;
|
|
else
|
|
as = sym->as;
|
|
|
|
int rank;
|
|
if (as == nullptr)
|
|
rank = 0;
|
|
else if (as->type != AS_ASSUMED_RANK)
|
|
rank = as->rank;
|
|
else
|
|
rank = -1;
|
|
|
|
return gfc_get_dtype (TREE_TYPE (descr), &rank);
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
|
|
static tree
|
|
get_descriptor_offset_value (const value_source &src)
|
|
{
|
|
if (src.type == NONSTATIC_INIT)
|
|
{
|
|
gfc_symbol *sym = src.u.nonstatic_init.sym;
|
|
|
|
symbol_attribute attr = gfc_symbol_attr (sym);
|
|
if ((attr.allocatable
|
|
|| attr.optional
|
|
|| (attr.pointer && (gfc_option.rtcheck & GFC_RTCHECK_POINTER)))
|
|
&& attr.codimension)
|
|
return null_pointer_node;
|
|
}
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
|
|
static void
|
|
set_descriptor (descriptor_write &dest, const value_source &src)
|
|
{
|
|
tree data_value = get_descriptor_data_value (src);
|
|
if (data_value != NULL_TREE)
|
|
set_descriptor_field (dest, DATA_FIELD, data_value);
|
|
|
|
tree dtype_value = get_descriptor_dtype_value (dest.ref, src);
|
|
if (dtype_value != NULL_TREE)
|
|
set_descriptor_field (dest, DTYPE_FIELD, dtype_value);
|
|
|
|
if (flag_coarray == GFC_FCOARRAY_LIB)
|
|
{
|
|
tree offset_value = get_descriptor_offset_value (src);
|
|
if (offset_value != NULL_TREE)
|
|
set_descriptor_field (dest, OFFSET_FIELD, offset_value);
|
|
}
|
|
|
|
if (dest.type == descriptor_write::STATIC_INIT)
|
|
{
|
|
tree decl = dest.ref;
|
|
tree type = TREE_TYPE (decl);
|
|
tree cstr = dest.u.static_init.build (type);
|
|
DECL_INITIAL (decl) = cstr;
|
|
}
|
|
else if (dtype_value == NULL_TREE)
|
|
gfc_conv_descriptor_bytes_counted_strides_set (dest.u.regular_assign.block,
|
|
dest.ref);
|
|
}
|
|
|
|
|
|
/* Build a null array descriptor constructor. */
|
|
|
|
tree
|
|
gfc_build_null_descriptor (tree type)
|
|
{
|
|
tree field;
|
|
tree tmp;
|
|
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
|
|
gcc_assert (DATA_FIELD == 0);
|
|
field = TYPE_FIELDS (type);
|
|
|
|
/* Set a NULL data pointer. */
|
|
tmp = build_constructor_single (type, field, null_pointer_node);
|
|
TREE_CONSTANT (tmp) = 1;
|
|
/* All other fields are ignored. */
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
/* Obtain offsets for trans-types.cc(gfc_get_array_descr_info). */
|
|
|
|
void
|
|
gfc_get_descriptor_offsets_for_info (const_tree desc_type, tree *data_off,
|
|
tree *dtype_off, tree *rank_suboff,
|
|
tree *span_off, tree *dim_off,
|
|
tree *dim_size, tree *stride_suboff,
|
|
tree *lower_suboff, tree *upper_suboff)
|
|
{
|
|
tree field;
|
|
tree type;
|
|
|
|
type = TYPE_MAIN_VARIANT (desc_type);
|
|
tree fields = TYPE_FIELDS (type);
|
|
field = gfc_advance_chain (fields, DATA_FIELD);
|
|
*data_off = byte_position (field);
|
|
field = gfc_advance_chain (fields, DTYPE_FIELD);
|
|
*dtype_off = byte_position (field);
|
|
type = TREE_TYPE (field);
|
|
field = gfc_advance_chain (TYPE_FIELDS (type), GFC_DTYPE_RANK);
|
|
*rank_suboff = byte_position (field);
|
|
field = gfc_advance_chain (fields, SPAN_FIELD);
|
|
*span_off = byte_position (field);
|
|
field = gfc_advance_chain (fields, DIMENSION_FIELD);
|
|
*dim_off = byte_position (field);
|
|
type = TREE_TYPE (TREE_TYPE (field));
|
|
*dim_size = TYPE_SIZE_UNIT (type);
|
|
field = gfc_advance_chain (TYPE_FIELDS (type), STRIDE_SUBFIELD);
|
|
*stride_suboff = byte_position (field);
|
|
field = gfc_advance_chain (TYPE_FIELDS (type), LBOUND_SUBFIELD);
|
|
*lower_suboff = byte_position (field);
|
|
field = gfc_advance_chain (TYPE_FIELDS (type), UBOUND_SUBFIELD);
|
|
*upper_suboff = byte_position (field);
|
|
}
|
|
|
|
|
|
/* For an array descriptor, get the total number of elements. This is just
|
|
the product of the extents along from_dim to to_dim. */
|
|
|
|
static tree
|
|
gfc_conv_descriptor_size_1 (tree desc, int from_dim, int to_dim)
|
|
{
|
|
tree res;
|
|
int dim;
|
|
|
|
res = gfc_index_one_node;
|
|
|
|
for (dim = from_dim; dim < to_dim; ++dim)
|
|
{
|
|
tree extent = gfc_conv_descriptor_extent_get (desc, gfc_rank_cst[dim]);
|
|
res = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
res, extent);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/* Full size of an array. */
|
|
|
|
tree
|
|
gfc_conv_descriptor_size (tree desc, int rank)
|
|
{
|
|
return gfc_conv_descriptor_size_1 (desc, 0, rank);
|
|
}
|
|
|
|
|
|
/* Size of a coarray for all dimensions but the last. */
|
|
|
|
tree
|
|
gfc_conv_descriptor_cosize (tree desc, int rank, int corank)
|
|
{
|
|
return gfc_conv_descriptor_size_1 (desc, rank, rank + corank - 1);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_nullify_descriptor (stmtblock_t *block, tree descr)
|
|
{
|
|
descriptor_write dest(descr, block);
|
|
set_descriptor (dest, value_source (POINTER_NULLIFY));
|
|
}
|
|
|
|
|
|
void
|
|
gfc_init_descriptor_result (stmtblock_t *block, tree descr)
|
|
{
|
|
descriptor_write dest(descr, block);
|
|
set_descriptor (dest, value_source (RESULT_INIT));
|
|
}
|
|
|
|
|
|
void
|
|
gfc_init_absent_descriptor (stmtblock_t *block, tree descr)
|
|
{
|
|
descriptor_write dest(descr, block);
|
|
set_descriptor (dest, value_source (ABSENT_ARG_INIT));
|
|
}
|
|
|
|
|
|
void
|
|
gfc_init_static_descriptor (gfc_symbol *sym)
|
|
{
|
|
descriptor_write dest (sym->backend_decl);
|
|
set_descriptor (dest, value_source (sym));
|
|
}
|
|
|
|
|
|
static void
|
|
init_descriptor_variable (stmtblock_t *block, gfc_symbol *sym, gfc_expr *expr,
|
|
tree descr, tree string_length)
|
|
{
|
|
descriptor_write dest (descr, block);
|
|
set_descriptor (dest, value_source (sym, expr, string_length));
|
|
}
|
|
|
|
void
|
|
gfc_init_descriptor_variable (stmtblock_t *block, gfc_symbol *sym,
|
|
gfc_expr *expr, tree descr)
|
|
{
|
|
return init_descriptor_variable (block, sym, expr, descr, NULL_TREE);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_init_descriptor_variable (stmtblock_t *block, gfc_symbol *sym, tree descr)
|
|
{
|
|
return gfc_init_descriptor_variable (block, sym, nullptr, descr);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_create_null_actual_descriptor (stmtblock_t *block, gfc_typespec *ts,
|
|
symbol_attribute attr, int rank)
|
|
{
|
|
tree etype = gfc_typenode_for_spec (ts);
|
|
|
|
enum gfc_array_kind akind;
|
|
|
|
if (attr.pointer)
|
|
akind = GFC_ARRAY_POINTER_CONT;
|
|
else if (attr.allocatable)
|
|
akind = GFC_ARRAY_ALLOCATABLE;
|
|
else
|
|
akind = GFC_ARRAY_ASSUMED_SHAPE_CONT;
|
|
|
|
tree lower[GFC_MAX_DIMENSIONS];
|
|
tree upper[GFC_MAX_DIMENSIONS];
|
|
memset (&lower, 0, rank * sizeof (lower[0]));
|
|
memset (&upper, 0, rank * sizeof (upper[0]));
|
|
|
|
tree type = gfc_get_array_type_bounds (etype, rank, 0, lower, upper, 1,
|
|
akind, !(attr.pointer || attr.target));
|
|
tree desc = gfc_create_var (type, "desc");
|
|
DECL_ARTIFICIAL (desc) = 1;
|
|
|
|
bool bytes_strides = GFC_BYTES_STRIDES_ARRAY_TYPE_P (type);
|
|
gfc_conv_descriptor_dtype_set (block, desc,
|
|
gfc_get_dtype_rank_type (rank, etype,
|
|
bytes_strides));
|
|
gfc_conv_descriptor_data_set (block, desc, null_pointer_node);
|
|
gfc_conv_descriptor_span_set (block, desc,
|
|
gfc_conv_descriptor_elem_len_get (desc));
|
|
|
|
return desc;
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor_from_scalar (stmtblock_t *block, tree descr, tree scalar,
|
|
symbol_attribute attr,
|
|
tree cond_presence, tree caf_token)
|
|
{
|
|
if (flag_coarray == GFC_FCOARRAY_LIB && caf_token)
|
|
gfc_conv_descriptor_token_set (block, descr, caf_token);
|
|
|
|
tree type = gfc_get_scalar_to_descriptor_type (TREE_TYPE (scalar), attr);
|
|
if (!POINTER_TYPE_P (TREE_TYPE (scalar)))
|
|
scalar = gfc_build_addr_expr (NULL_TREE, scalar);
|
|
if (cond_presence)
|
|
scalar = build3_loc (input_location, COND_EXPR,
|
|
TREE_TYPE (scalar),
|
|
cond_presence, scalar,
|
|
fold_convert (TREE_TYPE (scalar),
|
|
null_pointer_node));
|
|
|
|
gfc_conv_descriptor_dtype_set (block, descr, gfc_get_dtype (type));
|
|
gfc_conv_descriptor_data_set (block, descr, scalar);
|
|
gfc_conv_descriptor_span_set (block, descr,
|
|
gfc_conv_descriptor_elem_len_get (descr));
|
|
|
|
int corank = GFC_TYPE_ARRAY_CORANK (TREE_TYPE (descr));
|
|
if (corank != 0)
|
|
{
|
|
tree type = TREE_TYPE (scalar);
|
|
if (POINTER_TYPE_P (type))
|
|
type = TREE_TYPE (type);
|
|
gcc_assert (GFC_TYPE_ARRAY_CORANK (type) == corank);
|
|
for (int i = 0; i < corank; i++)
|
|
{
|
|
gfc_conv_descriptor_lbound_set (block, descr, i,
|
|
GFC_TYPE_ARRAY_LBOUND (type, i));
|
|
if (i < corank - 1)
|
|
gfc_conv_descriptor_ubound_set (block, descr, i,
|
|
GFC_TYPE_ARRAY_UBOUND (type, i));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor_from_scalar_class (stmtblock_t *block, tree descr,
|
|
tree scalar, gfc_expr *scalar_expr)
|
|
{
|
|
gfc_set_descriptor_from_scalar (block, descr, gfc_class_data_get (scalar),
|
|
gfc_expr_attr (scalar_expr));
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor_from_scalar (stmtblock_t *block, tree descr,
|
|
tree scalar, gfc_expr *scalar_expr,
|
|
tree cond_presence, tree caf_token)
|
|
{
|
|
gfc_set_descriptor_from_scalar (block, descr, scalar,
|
|
gfc_expr_attr (scalar_expr), cond_presence,
|
|
caf_token);
|
|
}
|
|
|
|
|
|
static void
|
|
set_dimension_bounds (stmtblock_t * block, tree descr, tree dim,
|
|
tree lbound, tree ubound, tree stride, tree *offset)
|
|
{
|
|
lbound = gfc_evaluate_now (lbound, block);
|
|
|
|
gfc_conv_descriptor_ubound_set (block, descr, dim, ubound);
|
|
|
|
tree tmp = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, lbound, stride);
|
|
*offset = fold_build2_loc (input_location, MINUS_EXPR,
|
|
gfc_array_index_type, *offset, tmp);
|
|
|
|
/* Finally set lbound to value we want. */
|
|
gfc_conv_descriptor_lbound_set (block, descr, dim, lbound);
|
|
}
|
|
|
|
|
|
static void
|
|
set_dimension_bounds (stmtblock_t * block, tree descr, tree dim,
|
|
tree lbound, tree ubound, tree stride, tree offset_var)
|
|
{
|
|
tree offset = offset_var;
|
|
set_dimension_bounds (block, descr, dim, lbound, ubound, stride, &offset);
|
|
gfc_add_modify (block, offset_var, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
set_dimension_fields (stmtblock_t * block, tree descr, tree dim,
|
|
tree lbound, tree ubound, tree stride, tree *offset)
|
|
{
|
|
stride = gfc_evaluate_now (stride, block);
|
|
set_dimension_bounds (block, descr, dim, lbound, ubound, stride, offset);
|
|
gfc_conv_descriptor_stride_set (block, descr, dim, stride);
|
|
}
|
|
|
|
|
|
static void
|
|
set_dimension_fields (stmtblock_t * block, tree descr, tree dim,
|
|
tree lbound, tree ubound, tree stride, tree offset_var)
|
|
{
|
|
stride = gfc_evaluate_now (stride, block);
|
|
set_dimension_bounds (block, descr, dim, lbound, ubound, stride, offset_var);
|
|
gfc_conv_descriptor_stride_set (block, descr, dim, stride);
|
|
}
|
|
|
|
static void
|
|
shift_dimension_bounds (stmtblock_t * block, tree descr, tree dim,
|
|
tree new_lbound, tree orig_lbound, tree orig_ubound,
|
|
tree orig_stride, tree *offset_value)
|
|
{
|
|
new_lbound = fold_convert (gfc_array_index_type, new_lbound);
|
|
|
|
orig_stride = gfc_evaluate_now (orig_stride, block);
|
|
|
|
/* Get difference (new - old) by which to shift stuff. */
|
|
tree diff = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
new_lbound, orig_lbound);
|
|
|
|
/* Shift ubound and offset accordingly. This has to be done before
|
|
updating the lbound, as they depend on the lbound expression! */
|
|
tree ubound = fold_build2_loc (input_location, PLUS_EXPR,
|
|
gfc_array_index_type, orig_ubound, diff);
|
|
|
|
set_dimension_bounds (block, descr, dim, new_lbound, ubound, orig_stride,
|
|
offset_value);
|
|
}
|
|
|
|
|
|
static void
|
|
shift_dimension_fields (stmtblock_t * block, tree descr, tree dim,
|
|
tree new_lbound, tree orig_lbound, tree orig_ubound,
|
|
tree orig_stride, tree *offset_value)
|
|
{
|
|
tree stride = gfc_evaluate_now (orig_stride, block);
|
|
shift_dimension_bounds (block, descr, dim, new_lbound, orig_lbound, orig_ubound,
|
|
stride, offset_value);
|
|
gfc_conv_descriptor_stride_set (block, descr, dim, stride);
|
|
}
|
|
|
|
|
|
/* Modify a descriptor such that the lbound of a given dimension is the value
|
|
specified. This also updates ubound and offset accordingly. */
|
|
|
|
static void
|
|
conv_shift_descriptor_lbound (stmtblock_t* block, tree desc,
|
|
int dim, tree new_lbound, tree *offset)
|
|
{
|
|
tree ubound, lbound, stride;
|
|
|
|
new_lbound = fold_convert (gfc_array_index_type, new_lbound);
|
|
|
|
lbound = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[dim]);
|
|
ubound = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[dim]);
|
|
stride = gfc_conv_descriptor_stride_get (desc, gfc_rank_cst[dim]);
|
|
|
|
shift_dimension_bounds (block, desc, gfc_rank_cst[dim], new_lbound, lbound,
|
|
ubound, stride, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_conv_shift_descriptor (stmtblock_t* block, tree desc, int rank)
|
|
{
|
|
/* Apply a shift of the lbound when supplied. */
|
|
tree offset = gfc_index_zero_node;
|
|
for (int dim = 0; dim < rank; ++dim)
|
|
conv_shift_descriptor_lbound (block, desc, dim, gfc_index_one_node,
|
|
&offset);
|
|
gfc_conv_descriptor_offset_set (block, desc, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
conv_shift_descriptor (stmtblock_t *block, tree desc, int rank,
|
|
gfc_expr * const (lbound[GFC_MAX_DIMENSIONS]))
|
|
{
|
|
/* Apply a shift of the lbound when supplied. */
|
|
tree offset = gfc_index_zero_node;
|
|
for (int dim = 0; dim < rank; ++dim)
|
|
{
|
|
gfc_expr *lb_expr = lbound[dim];
|
|
|
|
tree lower_bound;
|
|
if (lb_expr == nullptr)
|
|
lower_bound = gfc_index_one_node;
|
|
else
|
|
{
|
|
gfc_se lb_se;
|
|
|
|
gfc_init_se (&lb_se, nullptr);
|
|
gfc_conv_expr (&lb_se, lb_expr);
|
|
|
|
gfc_add_block_to_block (block, &lb_se.pre);
|
|
tree lb_var = gfc_create_var (TREE_TYPE (lb_se.expr), "lower_bound");
|
|
gfc_add_modify (block, lb_var, lb_se.expr);
|
|
gfc_add_block_to_block (block, &lb_se.post);
|
|
|
|
lower_bound = lb_var;
|
|
}
|
|
|
|
conv_shift_descriptor_lbound (block, desc, dim, lower_bound, &offset);
|
|
}
|
|
gfc_conv_descriptor_offset_set (block, desc, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
conv_shift_descriptor (stmtblock_t *block, tree desc,
|
|
const gfc_array_spec &as)
|
|
{
|
|
conv_shift_descriptor (block, desc, as.rank, as.lower);
|
|
}
|
|
|
|
|
|
static void
|
|
set_type (array_type &type, array_type value)
|
|
{
|
|
gcc_assert (type == AS_UNKNOWN || type == value);
|
|
type = value;
|
|
}
|
|
|
|
|
|
static void
|
|
array_ref_to_array_spec (const gfc_array_ref &ref, gfc_array_spec &spec)
|
|
{
|
|
spec.rank = ref.dimen;
|
|
spec.corank = ref.codimen;
|
|
|
|
spec.type = AS_UNKNOWN;
|
|
spec.cotype = AS_ASSUMED_SIZE;
|
|
|
|
for (int dim = 0; dim < spec.rank + spec.corank; dim++)
|
|
switch (ref.dimen_type[dim])
|
|
{
|
|
case DIMEN_ELEMENT:
|
|
spec.upper[dim] = ref.start[dim];
|
|
set_type (spec.type, AS_EXPLICIT);
|
|
break;
|
|
|
|
case DIMEN_RANGE:
|
|
spec.lower[dim] = ref.start[dim];
|
|
spec.upper[dim] = ref.end[dim];
|
|
if (spec.upper[dim] == nullptr)
|
|
set_type (spec.type, AS_DEFERRED);
|
|
else
|
|
set_type (spec.type, AS_EXPLICIT);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_conv_shift_descriptor (stmtblock_t *block, tree desc,
|
|
const gfc_array_ref &ar)
|
|
{
|
|
gfc_array_spec as;
|
|
|
|
array_ref_to_array_spec (ar, as);
|
|
|
|
conv_shift_descriptor (block, desc, as);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_conv_shift_descriptor (stmtblock_t *block, tree dest, tree src,
|
|
int rank, tree zero_cond)
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
|
|
tree tmp = gfc_conv_descriptor_data_get (src);
|
|
gfc_conv_descriptor_data_set (block, dest, tmp);
|
|
|
|
tree offset = gfc_index_zero_node;
|
|
for (int n = 0 ; n < rank; n++)
|
|
{
|
|
tree lbound = gfc_conv_descriptor_lbound_get (dest, gfc_rank_cst[n]);
|
|
lbound = fold_build3_loc (input_location, COND_EXPR,
|
|
gfc_array_index_type, zero_cond,
|
|
gfc_index_one_node, lbound);
|
|
lbound = gfc_evaluate_now (lbound, block);
|
|
|
|
tree dim = gfc_rank_cst[n];
|
|
tree stride = gfc_conv_descriptor_stride_get (src, dim);
|
|
shift_dimension_fields (block, dest, gfc_rank_cst[n],
|
|
lbound, gfc_index_zero_node,
|
|
gfc_conv_descriptor_ubound_get (src, dim),
|
|
stride, &offset);
|
|
}
|
|
|
|
gfc_conv_descriptor_offset_set (block, dest, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_subarray_descriptor (stmtblock_t *block, tree descr, tree value,
|
|
gfc_expr *value_expr, gfc_expr *conv_arg)
|
|
{
|
|
if (value_expr->expr_type != EXPR_VARIABLE)
|
|
gfc_conv_descriptor_data_set (block, value,
|
|
null_pointer_node);
|
|
|
|
/* Obtain the array spec of full array references. */
|
|
gfc_array_spec *as;
|
|
if (conv_arg)
|
|
as = gfc_get_full_arrayspec_from_expr (conv_arg);
|
|
else
|
|
as = gfc_get_full_arrayspec_from_expr (value_expr);
|
|
|
|
/* Shift the lbound and ubound of temporaries to being unity,
|
|
rather than zero, based. Always calculate the offset. */
|
|
tree offset = gfc_index_zero_node;
|
|
|
|
for (int n = 0; n < value_expr->rank; n++)
|
|
{
|
|
tree lbound;
|
|
|
|
/* Obtain the correct lbound - ISO/IEC TR 15581:2001 page 9.
|
|
TODO It looks as if gfc_conv_expr_descriptor should return
|
|
the correct bounds and that the following should not be
|
|
necessary. This would simplify gfc_conv_intrinsic_bound
|
|
as well. */
|
|
if (as && as->lower[n])
|
|
{
|
|
gfc_se lbse;
|
|
gfc_init_se (&lbse, NULL);
|
|
gfc_conv_expr (&lbse, as->lower[n]);
|
|
gfc_add_block_to_block (block, &lbse.pre);
|
|
lbound = gfc_evaluate_now (lbse.expr, block);
|
|
}
|
|
else if (as && conv_arg)
|
|
{
|
|
tree tmp = gfc_get_symbol_decl (conv_arg->symtree->n.sym);
|
|
lbound = gfc_conv_descriptor_lbound_get (tmp, gfc_rank_cst[n]);
|
|
}
|
|
else if (as)
|
|
lbound = gfc_conv_descriptor_lbound_get (descr, gfc_rank_cst[n]);
|
|
else
|
|
lbound = gfc_index_one_node;
|
|
|
|
lbound = fold_convert (gfc_array_index_type, lbound);
|
|
|
|
/* Shift the bounds and set the offset accordingly. */
|
|
tree dim = gfc_rank_cst[n];
|
|
shift_dimension_bounds (block, descr, dim, lbound,
|
|
gfc_conv_descriptor_lbound_get (descr, dim),
|
|
gfc_conv_descriptor_ubound_get (descr, dim),
|
|
gfc_conv_descriptor_stride_get (descr, dim),
|
|
&offset);
|
|
}
|
|
gfc_conv_descriptor_offset_set (block, descr, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_shift_descriptor (stmtblock_t *block, tree descr, int rank,
|
|
tree lbound[GFC_MAX_DIMENSIONS],
|
|
tree ubound[GFC_MAX_DIMENSIONS])
|
|
{
|
|
tree size = gfc_index_one_node;
|
|
tree offset = gfc_index_zero_node;
|
|
for (int n = 0; n < rank; n++)
|
|
{
|
|
tree dim = gfc_rank_cst[n];
|
|
shift_dimension_bounds (block, descr, dim, gfc_index_one_node,
|
|
lbound[n], ubound[n], size, &offset);
|
|
|
|
tree tmp = fold_build2_loc (input_location, MINUS_EXPR,
|
|
gfc_array_index_type, ubound[n], lbound[n]);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR,
|
|
gfc_array_index_type, tmp, gfc_index_one_node);
|
|
size = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, size, tmp);
|
|
}
|
|
|
|
gfc_conv_descriptor_offset_set (block, descr, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_sequence_descriptor (stmtblock_t *block, tree dest, tree src, int rank)
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
|
|
gfc_conv_descriptor_data_set (block, dest,
|
|
gfc_conv_descriptor_data_get (src));
|
|
gfc_conv_descriptor_lbound_set (block, dest, gfc_index_zero_node,
|
|
gfc_index_zero_node);
|
|
gfc_conv_descriptor_ubound_set (block, dest, gfc_index_zero_node,
|
|
gfc_conv_descriptor_size (src, rank));
|
|
tree stride = gfc_conv_descriptor_stride_get (src, gfc_index_zero_node);
|
|
gfc_conv_descriptor_stride_set (block, dest, gfc_index_zero_node, stride);
|
|
gfc_conv_descriptor_dtype_set (block, dest,
|
|
gfc_conv_descriptor_dtype_get (src));
|
|
gfc_conv_descriptor_rank_set (block, dest, 1);
|
|
gfc_conv_descriptor_span_set (block, dest,
|
|
gfc_conv_descriptor_span_get (src));
|
|
gfc_conv_descriptor_offset_set (block, dest, gfc_index_zero_node);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_descriptor (stmtblock_t *block, tree dest, tree src,
|
|
gfc_expr *src_expr, bool subref)
|
|
{
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
{
|
|
struct lang_type *dest_ls = TYPE_LANG_SPECIFIC (TREE_TYPE (dest));
|
|
struct lang_type *src_ls = TYPE_LANG_SPECIFIC (TREE_TYPE (src));
|
|
|
|
/* When only the array_kind differs, do a view_convert. */
|
|
tree tmp1;
|
|
if (dest_ls
|
|
&& src_ls
|
|
&& dest_ls->rank == src_ls->rank
|
|
&& dest_ls->akind != src_ls->akind)
|
|
tmp1 = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (dest), src);
|
|
else
|
|
tmp1 = src;
|
|
|
|
/* Copy the descriptor for pointer assignments. */
|
|
gfc_add_modify (block, dest, tmp1);
|
|
}
|
|
else
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
&& !GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
gfc_copy_descriptor (block, dest, src, src_expr);
|
|
}
|
|
|
|
/* Add any offsets from subreferences. */
|
|
gfc_get_dataptr_offset (block, dest, src, NULL_TREE, subref, src_expr);
|
|
|
|
/* ....and set the span field. */
|
|
tree tmp2;
|
|
if (src_expr->ts.type == BT_CHARACTER)
|
|
tmp2 = gfc_conv_descriptor_span_get (src);
|
|
else
|
|
tmp2 = gfc_get_array_span (src, src_expr);
|
|
gfc_conv_descriptor_span_set (block, dest, tmp2);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_descriptor (stmtblock_t *block, tree dest, tree src, bool lhs_type)
|
|
{
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
{
|
|
gfc_conv_descriptor_data_set (block, dest,
|
|
gfc_conv_descriptor_data_get (src));
|
|
gfc_conv_descriptor_offset_set (block, dest,
|
|
gfc_conv_descriptor_offset_get (src));
|
|
|
|
gfc_conv_descriptor_dtype_set (block, dest,
|
|
gfc_conv_descriptor_dtype_get (src));
|
|
|
|
gfc_conv_descriptor_span_set (block, dest,
|
|
gfc_conv_descriptor_span_get (src));
|
|
|
|
/* Assign the dimension as range-ref. */
|
|
tree tmp = gfc_get_descriptor_dimension (dest);
|
|
tree tmp2 = gfc_get_descriptor_dimension (src);
|
|
|
|
tree type = lhs_type ? TREE_TYPE (tmp) : TREE_TYPE (tmp2);
|
|
tmp = build4_loc (input_location, ARRAY_RANGE_REF, type, tmp,
|
|
gfc_index_zero_node, NULL_TREE, NULL_TREE);
|
|
tmp2 = build4_loc (input_location, ARRAY_RANGE_REF, type, tmp2,
|
|
gfc_index_zero_node, NULL_TREE, NULL_TREE);
|
|
gfc_add_modify (block, tmp, tmp2);
|
|
}
|
|
else
|
|
gfc_copy_descriptor (block, dest, src);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_descriptor (stmtblock_t *block, tree dst, tree src, int rank)
|
|
{
|
|
int n;
|
|
tree dim;
|
|
tree tmp;
|
|
tree tmp2;
|
|
tree size;
|
|
tree offset;
|
|
|
|
/* Use memcpy to copy the descriptor. The size is the minimum of
|
|
the sizes of 'src' and 'dst'. This avoids a non-trivial conversion. */
|
|
tmp = TYPE_SIZE_UNIT (TREE_TYPE (src));
|
|
tmp2 = TYPE_SIZE_UNIT (TREE_TYPE (dst));
|
|
size = fold_build2_loc (input_location, MIN_EXPR,
|
|
TREE_TYPE (tmp), tmp, tmp2);
|
|
tmp = builtin_decl_explicit (BUILT_IN_MEMCPY);
|
|
tmp = build_call_expr_loc (input_location, tmp, 3,
|
|
gfc_build_addr_expr (NULL_TREE, dst),
|
|
gfc_build_addr_expr (NULL_TREE, src),
|
|
fold_convert (size_type_node, size));
|
|
gfc_add_expr_to_block (block, tmp);
|
|
|
|
offset = gfc_index_zero_node;
|
|
|
|
/* Set the offset correctly. */
|
|
for (n = 0; n < rank; n++)
|
|
{
|
|
dim = gfc_rank_cst[n];
|
|
tree stride_raw = gfc_conv_descriptor_stride_get (src, dim);
|
|
tree stride;
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dst))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
stride = stride_raw;
|
|
else
|
|
{
|
|
tree span = gfc_conv_descriptor_span_get (dst);
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dst))
|
|
&& !GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
stride = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, stride_raw, span);
|
|
else if (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dst))
|
|
&& GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
stride = fold_build2_loc (input_location, EXACT_DIV_EXPR,
|
|
gfc_array_index_type, stride_raw, span);
|
|
else
|
|
gcc_unreachable ();
|
|
}
|
|
tmp = gfc_conv_descriptor_lbound_get (src, dim);
|
|
tmp = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (tmp),
|
|
tmp, stride);
|
|
offset = fold_build2_loc (input_location, MINUS_EXPR,
|
|
TREE_TYPE (offset), offset, tmp);
|
|
offset = gfc_evaluate_now (offset, block);
|
|
}
|
|
|
|
gfc_conv_descriptor_offset_set (block, dst, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_descriptor (stmtblock_t *block, tree dest, tree src, tree ptr,
|
|
int rank, gfc_ss *ss)
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
|
|
gfc_conv_descriptor_dtype_set (block, dest,
|
|
gfc_conv_descriptor_dtype_get (src));
|
|
|
|
gfc_conv_descriptor_offset_set (block, dest,
|
|
gfc_conv_descriptor_offset_get (src));
|
|
|
|
for (int i = 0; i < rank; i++)
|
|
{
|
|
int idx = gfc_get_array_ref_dim_for_loop_dim (ss, i);
|
|
tree old_field = gfc_conv_descriptor_dimension_get (src, idx);
|
|
gfc_conv_descriptor_dimension_set (block, dest, i, old_field);
|
|
}
|
|
|
|
if (flag_coarray == GFC_FCOARRAY_LIB
|
|
&& GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (src))
|
|
&& GFC_TYPE_ARRAY_AKIND (TREE_TYPE (src)) == GFC_ARRAY_ALLOCATABLE)
|
|
gfc_conv_descriptor_token_set (block, dest,
|
|
gfc_conv_descriptor_token (src));
|
|
|
|
gfc_conv_descriptor_data_set (block, dest, ptr);
|
|
}
|
|
|
|
|
|
static tree
|
|
find_parent_coarray_descriptor (tree t)
|
|
{
|
|
do
|
|
{
|
|
switch (TREE_CODE (t))
|
|
{
|
|
case COMPONENT_REF:
|
|
case INDIRECT_REF:
|
|
case NOP_EXPR:
|
|
t = TREE_OPERAND (t, 0);
|
|
break;
|
|
|
|
default:
|
|
gcc_unreachable ();
|
|
}
|
|
|
|
tree type = TREE_TYPE (t);
|
|
if (GFC_DESCRIPTOR_TYPE_P (type)
|
|
&& TYPE_LANG_SPECIFIC (type)
|
|
&& GFC_TYPE_ARRAY_CORANK (type) > 0)
|
|
return t;
|
|
}
|
|
while (!DECL_P (t));
|
|
|
|
return NULL_TREE;
|
|
}
|
|
|
|
|
|
static void
|
|
copy_dimension (stmtblock_t *block, tree dest, tree src, tree dim,
|
|
tree element_len, tree *offset)
|
|
{
|
|
tree lbound = gfc_conv_descriptor_lbound_get (src, dim);
|
|
tree ubound = gfc_conv_descriptor_ubound_get (src, dim);
|
|
tree stride_raw = gfc_conv_descriptor_stride_get (src, dim);
|
|
tree stride;
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
stride = stride_raw;
|
|
else if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest)))
|
|
{
|
|
stride = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, stride_raw,
|
|
element_len);
|
|
}
|
|
else
|
|
{
|
|
tree stride_raw = gfc_conv_descriptor_stride_get (src, dim);
|
|
stride = fold_build2_loc (input_location, EXACT_DIV_EXPR,
|
|
gfc_array_index_type, stride_raw,
|
|
element_len);
|
|
}
|
|
set_dimension_fields (block, dest, dim, lbound, ubound, stride, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
copy_dimension (stmtblock_t *block, tree dest, tree src, tree dim,
|
|
tree element_len, tree offset_var)
|
|
{
|
|
tree offset = offset_var;
|
|
copy_dimension (block, dest, src, dim, element_len, &offset);
|
|
gfc_add_modify (block, offset_var, offset);
|
|
}
|
|
|
|
|
|
static bool
|
|
is_assumed_rank (tree descriptor)
|
|
{
|
|
if (GFC_TYPE_ARRAY_RANK (TREE_TYPE (descriptor)) == -1)
|
|
return true;
|
|
|
|
switch (GFC_TYPE_ARRAY_AKIND (TREE_TYPE (descriptor)))
|
|
{
|
|
case GFC_ARRAY_ASSUMED_RANK:
|
|
case GFC_ARRAY_ASSUMED_RANK_CONT:
|
|
case GFC_ARRAY_ASSUMED_RANK_ALLOCATABLE:
|
|
case GFC_ARRAY_ASSUMED_RANK_POINTER:
|
|
case GFC_ARRAY_ASSUMED_RANK_POINTER_CONT:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_copy_descriptor (stmtblock_t *block, tree dest, tree src)
|
|
{
|
|
tree dest_type = TREE_TYPE (dest);
|
|
tree src_type = TREE_TYPE (src);
|
|
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (dest_type)
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (src_type)
|
|
&& (TYPE_CANONICAL (dest_type)
|
|
== TYPE_CANONICAL (src_type)
|
|
|| TYPE_MAIN_VARIANT (dest_type)
|
|
== TYPE_MAIN_VARIANT (src_type)))
|
|
gfc_add_modify (block, dest, src);
|
|
else
|
|
{
|
|
gfc_conv_descriptor_data_set (block, dest,
|
|
gfc_conv_descriptor_data_get (src));
|
|
gfc_conv_descriptor_dtype_set (block, dest,
|
|
gfc_conv_descriptor_dtype_get (src));
|
|
gfc_conv_descriptor_bytes_counted_strides_set (block, dest);
|
|
gfc_conv_descriptor_span_set (block, dest,
|
|
gfc_conv_descriptor_span_get (src));
|
|
|
|
tree element_len = gfc_conv_descriptor_elem_len_get (src);
|
|
element_len = fold_convert_loc (input_location, gfc_array_index_type,
|
|
element_len);
|
|
|
|
bool dest_assumed_rank = is_assumed_rank (dest);
|
|
bool src_assumed_rank = is_assumed_rank (src);
|
|
|
|
if (dest_assumed_rank && src_assumed_rank)
|
|
{
|
|
tree offset = gfc_create_var (gfc_array_index_type, "offset");
|
|
gfc_add_modify (block, offset, gfc_index_zero_node);
|
|
|
|
tree idx = gfc_create_var (integer_type_node, "idx");
|
|
tree dest_rank = fold_convert (integer_type_node,
|
|
gfc_conv_descriptor_rank_get (src));
|
|
|
|
stmtblock_t body;
|
|
gfc_start_block (&body);
|
|
copy_dimension (&body, dest, src, idx, element_len, offset);
|
|
|
|
gfc_simple_for_loop (block, idx, integer_zero_node, dest_rank,
|
|
LT_EXPR, integer_one_node,
|
|
gfc_finish_block (&body));
|
|
|
|
gfc_conv_descriptor_offset_set (block, dest, offset);
|
|
|
|
gcc_assert (GFC_TYPE_ARRAY_CORANK (TREE_TYPE (dest)) == 0);
|
|
}
|
|
else
|
|
{
|
|
tree offset = gfc_index_zero_node;
|
|
|
|
int rank;
|
|
if (GFC_TYPE_ARRAY_RANK (TREE_TYPE (dest))
|
|
== GFC_TYPE_ARRAY_RANK (TREE_TYPE (src)))
|
|
rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (dest));
|
|
else
|
|
{
|
|
gcc_assert (GFC_TYPE_ARRAY_AKIND (TREE_TYPE (dest))
|
|
== GFC_ARRAY_ASSUMED_RANK);
|
|
rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (src));
|
|
}
|
|
|
|
for (int i = 0; i < rank; i++)
|
|
copy_dimension (block, dest, src, gfc_rank_cst[i], element_len,
|
|
&offset);
|
|
|
|
gfc_conv_descriptor_offset_set (block, dest, offset);
|
|
|
|
int corank = GFC_TYPE_ARRAY_CORANK (TREE_TYPE (dest));
|
|
if (corank > 0)
|
|
{
|
|
tree codims_src_descr;
|
|
if (GFC_TYPE_ARRAY_CORANK (TREE_TYPE (src)) > 0)
|
|
{
|
|
gcc_assert (GFC_TYPE_ARRAY_CORANK (TREE_TYPE (src)) == corank);
|
|
codims_src_descr = src;
|
|
}
|
|
else
|
|
/* We may pointer assign a non-coarray target to a non-coarray
|
|
pointer subobject of a coarray. Get the bounds from the parent
|
|
coarray in that case. */
|
|
codims_src_descr = find_parent_coarray_descriptor (dest);
|
|
|
|
int codims_src_rank = GFC_TYPE_ARRAY_RANK (TREE_TYPE (codims_src_descr));
|
|
gcc_assert (GFC_TYPE_ARRAY_CORANK (TREE_TYPE (codims_src_descr))
|
|
== corank);
|
|
for (int i = 0; i < corank; i++)
|
|
{
|
|
int src_index = codims_src_rank + i;
|
|
tree lbound = gfc_conv_descriptor_lbound_get (codims_src_descr,
|
|
src_index);
|
|
gfc_conv_descriptor_lbound_set (block, dest, rank + i, lbound);
|
|
if (i < corank - 1)
|
|
{
|
|
tree ubound = gfc_conv_descriptor_ubound_get (codims_src_descr,
|
|
src_index);
|
|
gfc_conv_descriptor_ubound_set (block, dest, i, ubound);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag_coarray == GFC_FCOARRAY_LIB)
|
|
gfc_conv_descriptor_token_set (block, dest,
|
|
gfc_conv_descriptor_token (src));
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_conv_remap_descriptor (stmtblock_t *block, tree dest, int dest_rank,
|
|
tree src, bool contiguous_src, gfc_array_ref *ar)
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
|| !GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
|
|
/* Set dtype. */
|
|
gfc_conv_descriptor_dtype_set (block, dest,
|
|
gfc_get_dtype (TREE_TYPE (dest)));
|
|
|
|
/* Copy data pointer. */
|
|
gfc_conv_descriptor_data_set (block, dest,
|
|
gfc_conv_descriptor_data_get (src));
|
|
|
|
/* Copy the span. */
|
|
tree span;
|
|
if (VAR_P (src)
|
|
&& GFC_DECL_PTR_ARRAY_P (src))
|
|
span = gfc_conv_descriptor_span_get (src);
|
|
else
|
|
{
|
|
tree tmp = TREE_TYPE (src);
|
|
tmp = TYPE_SIZE_UNIT (gfc_get_element_type (tmp));
|
|
span = fold_convert (gfc_array_index_type, tmp);
|
|
}
|
|
span = gfc_evaluate_now (span, block);
|
|
gfc_conv_descriptor_span_set (block, dest, span);
|
|
|
|
/* Copy offset but adjust it such that it would correspond
|
|
to a lbound of zero. */
|
|
tree offset = gfc_index_zero_node;
|
|
|
|
/* Set the bounds as declared for the LHS and calculate strides as
|
|
well as another offset update accordingly. */
|
|
tree stride;
|
|
if (!contiguous_src)
|
|
stride = gfc_conv_descriptor_stride_bytes_get (src, gfc_rank_cst[0]);
|
|
else if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest)))
|
|
stride = span;
|
|
else
|
|
stride = gfc_index_one_node;
|
|
|
|
for (int dim = 0; dim < dest_rank; ++dim)
|
|
{
|
|
gfc_se lower_se;
|
|
gfc_se upper_se;
|
|
|
|
gcc_assert (ar->start[dim] && ar->end[dim]);
|
|
|
|
if (ar->start[dim]->expr_type != EXPR_CONSTANT
|
|
|| ar->start[dim]->expr_type != EXPR_VARIABLE)
|
|
gfc_resolve_expr (ar->start[dim]);
|
|
if (ar->end[dim]->expr_type != EXPR_CONSTANT
|
|
|| ar->end[dim]->expr_type != EXPR_VARIABLE)
|
|
gfc_resolve_expr (ar->end[dim]);
|
|
|
|
/* Convert declared bounds. */
|
|
gfc_init_se (&lower_se, NULL);
|
|
gfc_init_se (&upper_se, NULL);
|
|
gfc_conv_expr (&lower_se, ar->start[dim]);
|
|
gfc_conv_expr (&upper_se, ar->end[dim]);
|
|
|
|
gfc_add_block_to_block (block, &lower_se.pre);
|
|
gfc_add_block_to_block (block, &upper_se.pre);
|
|
|
|
tree lbound = fold_convert (gfc_array_index_type, lower_se.expr);
|
|
tree ubound = fold_convert (gfc_array_index_type, upper_se.expr);
|
|
|
|
lbound = gfc_evaluate_now (lbound, block);
|
|
ubound = gfc_evaluate_now (ubound, block);
|
|
|
|
gfc_add_block_to_block (block, &lower_se.post);
|
|
gfc_add_block_to_block (block, &upper_se.post);
|
|
|
|
stride = gfc_evaluate_now (stride, block);
|
|
|
|
set_dimension_fields (block, dest, gfc_rank_cst[dim],
|
|
lbound, ubound, stride, &offset);
|
|
|
|
/* Update stride. */
|
|
tree tmp = gfc_conv_array_extent_dim (lbound, ubound, NULL);
|
|
stride = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, stride, tmp);
|
|
}
|
|
gfc_conv_descriptor_offset_set (block, dest, offset);
|
|
}
|
|
|
|
|
|
static bool
|
|
element_size_known (tree desc)
|
|
{
|
|
tree type = TREE_TYPE (desc);
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type)
|
|
|| GFC_ARRAY_TYPE_P (type));
|
|
|
|
tree elt_type = gfc_get_element_type (TREE_TYPE (desc));
|
|
tree size = TYPE_SIZE_UNIT (elt_type);
|
|
|
|
return size && TREE_CODE (size) == INTEGER_CST;
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor (stmtblock_t *block, tree dest, tree src, gfc_expr *src_expr,
|
|
int rank, int corank, gfc_ss *ss, gfc_array_info *info,
|
|
tree lowers[GFC_MAX_DIMENSIONS],
|
|
tree uppers[GFC_MAX_DIMENSIONS],
|
|
bool unlimited_polymorphic, bool data_needed,
|
|
bool subref)
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
|| !GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)));
|
|
|
|
int ndim = info->ref ? info->ref->u.ar.dimen : rank;
|
|
|
|
/* Set the span field. */
|
|
tree span = NULL_TREE;
|
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (src)))
|
|
span = gfc_conv_descriptor_span_get (src);
|
|
else
|
|
span = gfc_get_array_span (src, src_expr);
|
|
if (span)
|
|
gfc_conv_descriptor_span_set (block, dest, span);
|
|
|
|
/* The following can be somewhat confusing. We have two
|
|
descriptors, a new one and the original array.
|
|
{parm, parmtype, dim} refer to the new one.
|
|
{desc, type, n, loop} refer to the original, which maybe
|
|
a descriptorless array.
|
|
The bounds of the scalarization are the bounds of the section.
|
|
We don't have to worry about numeric overflows when calculating
|
|
the offsets because all elements are within the array data. */
|
|
|
|
/* Set the dtype. */
|
|
tree dtype;
|
|
if (unlimited_polymorphic)
|
|
{
|
|
if (UNLIMITED_POLY (src_expr))
|
|
{
|
|
tree tmp2 = src;
|
|
if (TREE_CODE (tmp2) == INDIRECT_REF
|
|
&& DECL_P (TREE_OPERAND (tmp2, 0)))
|
|
tmp2 = TREE_OPERAND (tmp2, 0);
|
|
if (TREE_CODE (tmp2) == COMPONENT_REF
|
|
&& GFC_CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp2, 0))))
|
|
tmp2 = TREE_OPERAND (tmp2, 0);
|
|
if (DECL_P (tmp2)
|
|
&& DECL_LANG_SPECIFIC (tmp2)
|
|
&& GFC_DECL_SAVED_DESCRIPTOR (tmp2))
|
|
tmp2 = GFC_DECL_SAVED_DESCRIPTOR (tmp2);
|
|
tmp2 = gfc_class_data_get (tmp2);
|
|
if (POINTER_TYPE_P (TREE_TYPE (tmp2)))
|
|
tmp2 = build_fold_indirect_ref_loc (input_location, tmp2);
|
|
dtype = gfc_conv_descriptor_dtype_get (tmp2);
|
|
}
|
|
else
|
|
dtype = gfc_get_dtype (TREE_TYPE (src), &rank);
|
|
}
|
|
else if (src_expr->ts.type == BT_ASSUMED)
|
|
{
|
|
tree tmp2 = src;
|
|
if (DECL_LANG_SPECIFIC (tmp2) && GFC_DECL_SAVED_DESCRIPTOR (tmp2))
|
|
tmp2 = GFC_DECL_SAVED_DESCRIPTOR (tmp2);
|
|
if (POINTER_TYPE_P (TREE_TYPE (tmp2)))
|
|
tmp2 = build_fold_indirect_ref_loc (input_location, tmp2);
|
|
dtype = gfc_conv_descriptor_dtype_get (tmp2);
|
|
}
|
|
else if (src_expr->rank != -1
|
|
&& src_expr->ts.type == BT_CHARACTER
|
|
&& !element_size_known (dest))
|
|
{
|
|
bool bytes_strides = GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest));
|
|
dtype = get_dtype_rank_type_size (src_expr->rank, BT_CHARACTER,
|
|
bytes_strides, ss->info->string_length);
|
|
}
|
|
else
|
|
dtype = gfc_get_dtype (TREE_TYPE (dest));
|
|
gfc_conv_descriptor_dtype_set (block, dest, dtype);
|
|
|
|
if (src_expr->ts.type == BT_CLASS)
|
|
gfc_conv_descriptor_elem_len_set (block, dest, span);
|
|
else if (src_expr->rank != -1
|
|
&& src_expr->ts.type == BT_CHARACTER
|
|
&& ss->info->string_length == NULL_TREE
|
|
&& !element_size_known (dest))
|
|
{
|
|
tree src_desc = src;
|
|
if (TREE_CODE (src_desc) == INDIRECT_REF
|
|
&& DECL_P (TREE_OPERAND (src_desc, 0)))
|
|
src_desc = TREE_OPERAND (src_desc, 0);
|
|
if (DECL_P (src_desc)
|
|
&& DECL_LANG_SPECIFIC (src_desc)
|
|
&& GFC_DECL_SAVED_DESCRIPTOR (src_desc))
|
|
src_desc = GFC_DECL_SAVED_DESCRIPTOR (src_desc);
|
|
if (POINTER_TYPE_P (TREE_TYPE (src_desc)))
|
|
src_desc = build_fold_indirect_ref_loc (input_location, src_desc);
|
|
tree elem_len = gfc_conv_descriptor_elem_len_get (src_desc);
|
|
gfc_conv_descriptor_elem_len_set (block, dest, elem_len);
|
|
}
|
|
|
|
/* The 1st element in the section. */
|
|
tree base = gfc_index_zero_node;
|
|
if (src_expr->ts.type == BT_CHARACTER && src_expr->rank == 0 && corank)
|
|
base = gfc_index_one_node;
|
|
|
|
tree tmp = NULL_TREE;
|
|
|
|
/* The offset from the 1st element in the section. */
|
|
tree offset = gfc_index_zero_node;
|
|
|
|
for (int n = 0; n < ndim; n++)
|
|
{
|
|
tree src_stride = gfc_conv_array_stride (src, n);
|
|
src_stride = gfc_evaluate_now (src_stride, block);
|
|
|
|
tree stride;
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (dest))
|
|
== GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (src)))
|
|
stride = src_stride;
|
|
else
|
|
stride = gfc_conv_array_stride_bytes (src, n);
|
|
|
|
/* Work out the 1st element in the section. */
|
|
tree start;
|
|
if (info->ref
|
|
&& info->ref->u.ar.dimen_type[n] == DIMEN_ELEMENT)
|
|
{
|
|
gcc_assert (info->subscript[n]
|
|
&& info->subscript[n]->info->type == GFC_SS_SCALAR);
|
|
start = info->subscript[n]->info->data.scalar.value;
|
|
}
|
|
else
|
|
{
|
|
/* Evaluate and remember the start of the section. */
|
|
start = info->start[n];
|
|
stride = gfc_evaluate_now (stride, block);
|
|
}
|
|
|
|
tmp = gfc_conv_array_lbound (src, n);
|
|
tmp = fold_build2_loc (input_location, MINUS_EXPR, TREE_TYPE (tmp),
|
|
start, tmp);
|
|
tmp = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (tmp),
|
|
tmp, src_stride);
|
|
base = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (tmp),
|
|
base, tmp);
|
|
|
|
if (info->ref
|
|
&& info->ref->u.ar.dimen_type[n] == DIMEN_ELEMENT)
|
|
{
|
|
/* For elemental dimensions, we only need the 1st
|
|
element in the section. */
|
|
continue;
|
|
}
|
|
|
|
/* Vector subscripts need copying and are handled elsewhere. */
|
|
if (info->ref)
|
|
gcc_assert (info->ref->u.ar.dimen_type[n] == DIMEN_RANGE);
|
|
|
|
/* look for the corresponding scalarizer dimension: dim. */
|
|
int dim;
|
|
for (dim = 0; dim < ndim; dim++)
|
|
if (ss->dim[dim] == n)
|
|
break;
|
|
|
|
/* loop exited early: the DIM being looked for has been found. */
|
|
gcc_assert (dim < ndim);
|
|
|
|
/* Set the new lower bound. */
|
|
tree from = lowers[dim];
|
|
tree to = uppers[dim];
|
|
|
|
/* Multiply the stride by the section stride to get the
|
|
total stride. */
|
|
stride = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type,
|
|
stride, info->stride[n]);
|
|
|
|
set_dimension_fields (block, dest, gfc_rank_cst[dim], from, to, stride,
|
|
&offset);
|
|
}
|
|
|
|
for (int n = rank; n < rank + corank; n++)
|
|
{
|
|
tree from = lowers[n];
|
|
tree to = uppers[n];
|
|
gfc_conv_descriptor_lbound_set (block, dest,
|
|
gfc_rank_cst[n], from);
|
|
if (n < rank + corank - 1)
|
|
gfc_conv_descriptor_ubound_set (block, dest,
|
|
gfc_rank_cst[n], to);
|
|
}
|
|
|
|
if (data_needed)
|
|
/* Point the data pointer at the 1st element in the section. */
|
|
gfc_get_dataptr_offset (block, dest, src, base,
|
|
subref, src_expr);
|
|
else
|
|
gfc_conv_descriptor_data_set (block, dest,
|
|
gfc_index_zero_node);
|
|
|
|
gfc_conv_descriptor_offset_set (block, dest, offset);
|
|
|
|
if (flag_coarray == GFC_FCOARRAY_LIB && src_expr->corank)
|
|
{
|
|
tmp = INDIRECT_REF_P (src) ? TREE_OPERAND (src, 0) : src;
|
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
|
|
tmp = gfc_conv_descriptor_token (tmp);
|
|
else if (DECL_P (tmp) && DECL_LANG_SPECIFIC (tmp)
|
|
&& GFC_DECL_TOKEN (tmp) != NULL_TREE)
|
|
tmp = GFC_DECL_TOKEN (tmp);
|
|
else if (TYPE_LANG_SPECIFIC (TREE_TYPE (tmp)))
|
|
tmp = GFC_TYPE_ARRAY_CAF_TOKEN (TREE_TYPE (tmp));
|
|
else
|
|
tmp = NULL_TREE;
|
|
|
|
if (tmp != NULL_TREE)
|
|
gfc_conv_descriptor_token_set (block, dest, tmp);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_contiguous_descriptor (stmtblock_t *block, tree desc, tree size,
|
|
tree data_ptr)
|
|
{
|
|
gcc_assert (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)));
|
|
gfc_conv_descriptor_dtype_set (block, desc,
|
|
gfc_get_dtype_rank_type (1, TREE_TYPE (desc),
|
|
false));
|
|
gfc_conv_descriptor_lbound_set (block, desc,
|
|
gfc_index_zero_node,
|
|
gfc_index_one_node);
|
|
gfc_conv_descriptor_stride_set (block, desc,
|
|
gfc_index_zero_node,
|
|
gfc_index_one_node);
|
|
gfc_conv_descriptor_ubound_set (block, desc,
|
|
gfc_index_zero_node, size);
|
|
gfc_conv_descriptor_data_set (block, desc, data_ptr);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor_with_shape (stmtblock_t *block, tree desc, tree ptr,
|
|
gfc_expr *shape, gfc_expr *lower, locus *where)
|
|
{
|
|
/* Set the span field. */
|
|
tree tmp = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (desc)));
|
|
tree elem_len = fold_convert (gfc_array_index_type, tmp);
|
|
gfc_conv_descriptor_span_set (block, desc, elem_len);
|
|
|
|
/* Set data value, dtype, and offset. */
|
|
tmp = GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc));
|
|
gfc_conv_descriptor_data_set (block, desc, fold_convert (tmp, ptr));
|
|
gfc_conv_descriptor_dtype_set (block, desc,
|
|
gfc_get_dtype (TREE_TYPE (desc)));
|
|
|
|
/* Start scalarization of the bounds, using the shape argument. */
|
|
|
|
gfc_ss *shape_ss = gfc_walk_expr (shape);
|
|
gcc_assert (shape_ss != gfc_ss_terminator);
|
|
gfc_se shapese, lowerse;
|
|
gfc_init_se (&shapese, nullptr);
|
|
gfc_ss *lower_ss = nullptr;
|
|
if (lower)
|
|
{
|
|
lower_ss = gfc_walk_expr (lower);
|
|
gcc_assert (lower_ss != gfc_ss_terminator);
|
|
gfc_init_se (&lowerse, nullptr);
|
|
}
|
|
|
|
gfc_loopinfo loop;
|
|
gfc_init_loopinfo (&loop);
|
|
gfc_add_ss_to_loop (&loop, shape_ss);
|
|
if (lower)
|
|
gfc_add_ss_to_loop (&loop, lower_ss);
|
|
gfc_conv_ss_startstride (&loop);
|
|
gfc_conv_loop_setup (&loop, where);
|
|
gfc_mark_ss_chain_used (shape_ss, 1);
|
|
if (lower)
|
|
gfc_mark_ss_chain_used (lower_ss, 1);
|
|
|
|
gfc_copy_loopinfo_to_se (&shapese, &loop);
|
|
shapese.ss = shape_ss;
|
|
if (lower)
|
|
{
|
|
gfc_copy_loopinfo_to_se (&lowerse, &loop);
|
|
lowerse.ss = lower_ss;
|
|
}
|
|
|
|
tree stride = gfc_create_var (gfc_array_index_type, "stride");
|
|
tree offset = gfc_create_var (gfc_array_index_type, "offset");
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
|
gfc_add_modify (block, stride, elem_len);
|
|
else
|
|
gfc_add_modify (block, stride, gfc_index_one_node);
|
|
gfc_add_modify (block, offset, gfc_index_zero_node);
|
|
|
|
/* Loop body. */
|
|
stmtblock_t body;
|
|
gfc_start_scalarized_body (&loop, &body);
|
|
|
|
tree dim = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
loop.loopvar[0], loop.from[0]);
|
|
|
|
tree lbound;
|
|
if (lower)
|
|
{
|
|
gfc_conv_expr (&lowerse, lower);
|
|
gfc_add_block_to_block (&body, &lowerse.pre);
|
|
lbound = fold_convert (gfc_array_index_type, lowerse.expr);
|
|
lbound = gfc_evaluate_now (lbound, &body);
|
|
gfc_add_block_to_block (&body, &lowerse.post);
|
|
}
|
|
else
|
|
lbound = gfc_index_one_node;
|
|
|
|
gfc_conv_expr (&shapese, shape);
|
|
gfc_add_block_to_block (&body, &shapese.pre);
|
|
tree shapeval = fold_convert (gfc_array_index_type, shapese.expr);
|
|
shapeval = gfc_evaluate_now (shapeval, &body);
|
|
tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
lbound, gfc_index_one_node);
|
|
tree ubound = fold_build2_loc (input_location, PLUS_EXPR,
|
|
gfc_array_index_type, tmp, shapeval);
|
|
ubound = gfc_evaluate_now (ubound, &body);
|
|
gfc_add_block_to_block (&body, &shapese.post);
|
|
|
|
set_dimension_fields (&body, desc, dim, lbound, ubound, stride, offset);
|
|
|
|
/* Update stride. */
|
|
gfc_add_modify (&body, stride,
|
|
fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, stride, shapeval));
|
|
|
|
/* Finish scalarization loop. */
|
|
gfc_trans_scalarizing_loops (&loop, &body);
|
|
gfc_add_block_to_block (block, &loop.pre);
|
|
gfc_add_block_to_block (block, &loop.post);
|
|
gfc_cleanup_loop (&loop);
|
|
|
|
gfc_conv_descriptor_offset_set (block, desc, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
set_gfc_dimension_from_cfi (stmtblock_t *block, tree gfc, tree cfi, tree idx,
|
|
tree lbound, tree offset_var, tree cont_stride_var,
|
|
bool contiguous)
|
|
{
|
|
/* gfc->dim[i].lbound = ... */
|
|
lbound = fold_convert (gfc_array_index_type, lbound);
|
|
|
|
/* gfc->dim[i].ubound = gfc->dim[i].lbound + cfi->dim[i].extent - 1. */
|
|
tree tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
|
|
lbound, gfc_index_one_node);
|
|
tree ubound = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
gfc_get_cfi_dim_extent (cfi, idx), tmp);
|
|
|
|
tree stride;
|
|
if (contiguous)
|
|
{
|
|
gcc_assert (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (gfc)));
|
|
|
|
/* gfc->dim[i].stride
|
|
= idx == 0 ? 1 : gfc->dim[i-1].stride * cfi->dim[i-1].extent */
|
|
tree cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
|
|
idx, build_zero_cst (TREE_TYPE (idx)));
|
|
tmp = fold_build2_loc (input_location, MINUS_EXPR, TREE_TYPE (idx),
|
|
idx, build_int_cst (TREE_TYPE (idx), 1));
|
|
tmp = gfc_get_cfi_dim_extent (cfi, tmp);
|
|
tmp = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (tmp),
|
|
tmp, cont_stride_var);
|
|
tmp = build3_loc (input_location, COND_EXPR, gfc_array_index_type, cond,
|
|
gfc_index_one_node, tmp);
|
|
stride = gfc_evaluate_now (tmp, block);
|
|
gfc_add_modify (block, cont_stride_var, stride);
|
|
}
|
|
else
|
|
{
|
|
gcc_assert (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (gfc)));
|
|
|
|
/* gfc->dim[i].stride = cfi->dim[i].sm / cfi>elem_len */
|
|
stride = gfc_get_cfi_dim_sm (cfi, idx);
|
|
}
|
|
|
|
set_dimension_fields (block, gfc, idx, lbound, ubound, stride, offset_var);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_gfc_from_cfi (stmtblock_t *block, tree gfc, gfc_expr *e, tree rank,
|
|
tree gfc_strlen, tree cfi, gfc_symbol *fsym)
|
|
{
|
|
stmtblock_t block2;
|
|
gfc_init_block (&block2);
|
|
if (e->rank == 0)
|
|
{
|
|
tree tmp = gfc_get_cfi_desc_base_addr (cfi);
|
|
gfc_add_modify (block, gfc, fold_convert (TREE_TYPE (gfc), tmp));
|
|
}
|
|
else
|
|
{
|
|
tree tmp = gfc_get_cfi_desc_base_addr (cfi);
|
|
gfc_conv_descriptor_data_set (block, gfc, tmp);
|
|
|
|
if (fsym->attr.allocatable)
|
|
{
|
|
/* gfc->span = cfi->elem_len. */
|
|
tmp = fold_convert (gfc_array_index_type,
|
|
gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]));
|
|
}
|
|
else
|
|
{
|
|
/* gfc->span = ((cfi->dim[0].sm % cfi->elem_len)
|
|
? cfi->dim[0].sm : cfi->elem_len). */
|
|
tmp = gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]);
|
|
tree tmp2 = fold_convert (gfc_array_index_type,
|
|
gfc_get_cfi_desc_elem_len (cfi));
|
|
tmp = fold_build2_loc (input_location, TRUNC_MOD_EXPR,
|
|
gfc_array_index_type, tmp, tmp2);
|
|
tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
|
|
tmp, gfc_index_zero_node);
|
|
tmp = build3_loc (input_location, COND_EXPR, gfc_array_index_type, tmp,
|
|
gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]), tmp2);
|
|
}
|
|
gfc_conv_descriptor_span_set (&block2, gfc, tmp);
|
|
|
|
/* Calculate offset + set lbound, ubound and stride. */
|
|
tree offset = gfc_create_var (gfc_array_index_type, "offset");
|
|
gfc_add_modify (&block2, offset, gfc_index_zero_node);
|
|
bool contiguous = fsym->attr.allocatable;
|
|
tree stride;
|
|
if (contiguous)
|
|
stride = gfc_create_var (gfc_array_index_type, "stride");
|
|
else
|
|
stride = NULL_TREE;
|
|
/* Loop: for (i = 0; i < rank; ++i). */
|
|
tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
|
|
/* Loop body. */
|
|
stmtblock_t loop_body;
|
|
gfc_init_block (&loop_body);
|
|
set_gfc_dimension_from_cfi (&loop_body, gfc, cfi, idx,
|
|
gfc_get_cfi_dim_lbound (cfi, idx), offset,
|
|
stride, contiguous);
|
|
/* Generate loop. */
|
|
gfc_simple_for_loop (&block2, idx, build_int_cst (TREE_TYPE (idx), 0),
|
|
rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
|
|
gfc_finish_block (&loop_body));
|
|
gfc_conv_descriptor_offset_set (&block2, gfc, offset);
|
|
}
|
|
|
|
if (e->ts.type == BT_CHARACTER && !e->ts.u.cl->length)
|
|
{
|
|
tree tmp = fold_convert (gfc_charlen_type_node,
|
|
gfc_get_cfi_desc_elem_len (cfi));
|
|
if (e->ts.kind != 1)
|
|
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
|
|
gfc_charlen_type_node, tmp,
|
|
build_int_cst (gfc_charlen_type_node,
|
|
e->ts.kind));
|
|
gfc_add_modify (&block2, gfc_strlen, tmp);
|
|
}
|
|
|
|
tree tmp = gfc_get_cfi_desc_base_addr (cfi);
|
|
tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
|
|
tmp, null_pointer_node);
|
|
tmp = build3_v (COND_EXPR, tmp, gfc_finish_block (&block2),
|
|
build_empty_stmt (input_location));
|
|
gfc_add_expr_to_block (block, tmp);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_gfc_from_cfi (stmtblock_t *block, stmtblock_t *block2, tree gfc_desc,
|
|
tree rank, tree cfi, gfc_symbol *sym, bool do_copy_inout)
|
|
{
|
|
/* gfc->dtype = ... (from declaration, not from cfi). */
|
|
gfc_conv_descriptor_dtype_set (block, gfc_desc,
|
|
gfc_get_dtype (TREE_TYPE (gfc_desc),
|
|
&sym->as->rank));
|
|
/* gfc->data = cfi->base_addr. */
|
|
gfc_conv_descriptor_data_set (block, gfc_desc,
|
|
gfc_get_cfi_desc_base_addr (cfi));
|
|
|
|
if (sym->ts.type == BT_ASSUMED)
|
|
{
|
|
/* For type(*), take elem_len + dtype.type from the actual argument. */
|
|
gfc_conv_descriptor_elem_len_set (block, gfc_desc,
|
|
gfc_get_cfi_desc_elem_len (cfi));
|
|
tree ctype = gfc_get_cfi_desc_type (cfi);
|
|
ctype = fold_build2_loc (input_location, BIT_AND_EXPR, TREE_TYPE (ctype),
|
|
ctype, build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_mask));
|
|
|
|
/* if (CFI_type_cptr) BT_VOID else BT_UNKNOWN */
|
|
/* Note: BT_VOID is could also be CFI_type_funcptr, but assume c_ptr. */
|
|
tree cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
|
|
ctype, build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_cptr));
|
|
tree tmp = gfc_conv_descriptor_type_set (gfc_desc, BT_VOID);
|
|
tree tmp2 = gfc_conv_descriptor_type_set (gfc_desc, BT_UNKNOWN);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
/* if (CFI_type_struct) BT_DERIVED else < tmp2 > */
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_struct));
|
|
tmp = gfc_conv_descriptor_type_set (gfc_desc, BT_DERIVED);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
/* if (CFI_type_Character) BT_CHARACTER else < tmp2 > */
|
|
/* Note: this is kind=1, CFI_type_ucs4_char is handled in the 'else if'
|
|
before (see below, as generated bottom up). */
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_Character));
|
|
tmp = gfc_conv_descriptor_type_set (gfc_desc, BT_CHARACTER);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
/* if (CFI_type_ucs4_char) BT_CHARACTER else < tmp2 > */
|
|
/* Note: gfc->elem_len = cfi->elem_len/4. */
|
|
/* However, assuming that CFI_type_ucs4_char cannot be recovered, leave
|
|
gfc->elem_len == cfi->elem_len, which helps with operations which use
|
|
sizeof() in Fortran and cfi->elem_len in C. */
|
|
tmp = gfc_get_cfi_desc_type (cfi);
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, tmp,
|
|
build_int_cst (TREE_TYPE (tmp),
|
|
CFI_type_ucs4_char));
|
|
tmp = gfc_conv_descriptor_type_set (gfc_desc, BT_CHARACTER);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
/* if (CFI_type_Complex) BT_COMPLEX + cfi->elem_len/2 else < tmp2 > */
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_Complex));
|
|
tmp = gfc_conv_descriptor_type_set (gfc_desc, BT_COMPLEX);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
/* if (CFI_type_Integer || CFI_type_Logical || CFI_type_Real)
|
|
ctype else <tmp2> */
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_Integer));
|
|
tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_Logical));
|
|
cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
|
|
cond, tmp);
|
|
tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, ctype,
|
|
build_int_cst (TREE_TYPE (ctype),
|
|
CFI_type_Real));
|
|
cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
|
|
cond, tmp);
|
|
tmp = gfc_conv_descriptor_type_set (gfc_desc, ctype);
|
|
tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
|
|
tmp, tmp2);
|
|
gfc_add_expr_to_block (block, tmp2);
|
|
}
|
|
|
|
if (sym->as->rank < 0)
|
|
/* Set gfc->dtype.rank, if assumed-rank. */
|
|
gfc_conv_descriptor_rank_set (block, gfc_desc, rank);
|
|
|
|
/* if do_copy_inout: gfc->dspan = gfc->dtype.elem_len
|
|
We use gfc instead of cfi on the RHS as this might be a constant. */
|
|
tree tmp = fold_convert (gfc_array_index_type,
|
|
gfc_conv_descriptor_elem_len_get (gfc_desc));
|
|
if (!do_copy_inout)
|
|
{
|
|
/* gfc->dspan = ((cfi->dim[0].sm % gfc->elem_len)
|
|
? cfi->dim[0].sm : gfc->elem_len). */
|
|
tree cond;
|
|
tree tmp2 = gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]);
|
|
cond = fold_build2_loc (input_location, TRUNC_MOD_EXPR,
|
|
gfc_array_index_type, tmp2, tmp);
|
|
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
|
|
cond, gfc_index_zero_node);
|
|
tmp = build3_loc (input_location, COND_EXPR, gfc_array_index_type, cond,
|
|
tmp2, tmp);
|
|
}
|
|
gfc_conv_descriptor_span_set (block2, gfc_desc, tmp);
|
|
|
|
/* Calculate offset + set lbound, ubound and stride. */
|
|
tree offset = gfc_create_var (gfc_array_index_type, "offset");
|
|
gfc_add_modify (block2, offset, gfc_index_zero_node);
|
|
|
|
/* Stride */
|
|
bool contiguous = do_copy_inout || sym->attr.allocatable;
|
|
tree stride;
|
|
if (contiguous)
|
|
stride = gfc_create_var (gfc_array_index_type, "stride");
|
|
else
|
|
stride = NULL_TREE;
|
|
|
|
if (sym->as->rank > 0 && !sym->attr.pointer && !sym->attr.allocatable)
|
|
{
|
|
for (int i = 0; i < sym->as->rank; ++i)
|
|
{
|
|
gfc_se se;
|
|
gfc_init_se (&se, NULL );
|
|
if (sym->as->lower[i])
|
|
{
|
|
gfc_conv_expr (&se, sym->as->lower[i]);
|
|
tmp = se.expr;
|
|
}
|
|
else
|
|
tmp = gfc_index_one_node;
|
|
gfc_add_block_to_block (block2, &se.pre);
|
|
tree lbound = gfc_evaluate_now (tmp, block2);
|
|
gfc_add_block_to_block (block2, &se.post);
|
|
set_gfc_dimension_from_cfi (block2, gfc_desc, cfi, gfc_rank_cst[i],
|
|
lbound, offset, stride, contiguous);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Loop: for (i = 0; i < rank; ++i). */
|
|
tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
|
|
|
|
/* Loop body. */
|
|
stmtblock_t loop_body;
|
|
gfc_init_block (&loop_body);
|
|
/* gfc->dim[i].lbound = ... */
|
|
tree lbound;
|
|
if (sym->attr.pointer || sym->attr.allocatable)
|
|
lbound = gfc_get_cfi_dim_lbound (cfi, idx);
|
|
else if (sym->as->rank < 0)
|
|
lbound = gfc_index_one_node;
|
|
else
|
|
gcc_unreachable ();
|
|
|
|
set_gfc_dimension_from_cfi (&loop_body, gfc_desc, cfi, idx, lbound,
|
|
offset, stride, contiguous);
|
|
|
|
/* Generate loop. */
|
|
gfc_simple_for_loop (block2, idx, build_zero_cst (TREE_TYPE (idx)),
|
|
rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
|
|
gfc_finish_block (&loop_body));
|
|
}
|
|
|
|
gfc_conv_descriptor_offset_set (block2, gfc_desc, offset);
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_temporary_descriptor (stmtblock_t *block, tree descr, tree class_src,
|
|
tree elemsize, tree data_ptr,
|
|
tree lbound[GFC_MAX_DIMENSIONS],
|
|
tree ubound[GFC_MAX_DIMENSIONS],
|
|
tree stride[GFC_MAX_DIMENSIONS], int rank,
|
|
bool callee_allocated, bool rank_changer,
|
|
bool shift_bounds)
|
|
{
|
|
if (!class_src)
|
|
{
|
|
/* Fill in the array dtype. */
|
|
gfc_conv_descriptor_dtype_set (block, descr,
|
|
gfc_get_dtype (TREE_TYPE (descr)));
|
|
}
|
|
else if (rank_changer)
|
|
{
|
|
/* For classes, we copy the whole original class descriptor to the
|
|
temporary one, so we don't need to set the individual dtype fields.
|
|
Except for the case of rank altering intrinsics for which we
|
|
generate descriptors of different rank. */
|
|
|
|
/* Take the dtype from the class expression. */
|
|
tree class_descr = gfc_class_data_get (class_src);
|
|
tree dtype = gfc_conv_descriptor_dtype_get (class_descr);
|
|
gfc_conv_descriptor_dtype_set (block, descr, dtype);
|
|
|
|
/* These transformational functions change the rank. */
|
|
gfc_conv_descriptor_rank_set (block, descr, rank);
|
|
}
|
|
|
|
tree offset = gfc_index_zero_node;
|
|
if (!callee_allocated)
|
|
for (int n = 0; n < rank; n++)
|
|
{
|
|
if (shift_bounds)
|
|
shift_dimension_fields (block, descr, gfc_rank_cst[n],
|
|
gfc_index_zero_node, lbound[n], ubound[n],
|
|
stride[n], &offset);
|
|
else
|
|
set_dimension_fields (block, descr, gfc_rank_cst[n], lbound[n],
|
|
ubound[n], stride[n], &offset);
|
|
}
|
|
|
|
if (elemsize != NULL_TREE)
|
|
gfc_conv_descriptor_span_set (block, descr, elemsize);
|
|
|
|
gfc_conv_descriptor_offset_set (block, descr, offset);
|
|
|
|
gfc_conv_descriptor_data_set (block, descr, data_ptr);
|
|
}
|
|
|
|
|
|
/* Returns the value of LBOUND for an expression. This could be broken out
|
|
from gfc_conv_intrinsic_bound but this seemed to be simpler. This is
|
|
called by gfc_alloc_allocatable_for_assignment. */
|
|
static tree
|
|
get_std_lbound (gfc_expr *expr, tree desc, int dim, bool assumed_size)
|
|
{
|
|
tree lbound;
|
|
tree ubound;
|
|
tree stride;
|
|
tree cond, cond1, cond3, cond4;
|
|
tree tmp;
|
|
gfc_ref *ref;
|
|
|
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
|
|
{
|
|
tmp = gfc_rank_cst[dim];
|
|
lbound = gfc_conv_descriptor_lbound_get (desc, tmp);
|
|
ubound = gfc_conv_descriptor_ubound_get (desc, tmp);
|
|
stride = gfc_conv_descriptor_stride_get (desc, tmp);
|
|
cond1 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
|
|
ubound, lbound);
|
|
cond3 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
|
|
stride, gfc_index_zero_node);
|
|
cond3 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
|
|
logical_type_node, cond3, cond1);
|
|
cond4 = fold_build2_loc (input_location, LT_EXPR, logical_type_node,
|
|
stride, gfc_index_zero_node);
|
|
if (assumed_size)
|
|
cond = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
|
|
tmp, build_int_cst (gfc_array_index_type,
|
|
expr->rank - 1));
|
|
else
|
|
cond = logical_false_node;
|
|
|
|
cond1 = fold_build2_loc (input_location, TRUTH_OR_EXPR,
|
|
logical_type_node, cond3, cond4);
|
|
cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
|
|
logical_type_node, cond, cond1);
|
|
|
|
return fold_build3_loc (input_location, COND_EXPR,
|
|
gfc_array_index_type, cond,
|
|
lbound, gfc_index_one_node);
|
|
}
|
|
|
|
if (expr->expr_type == EXPR_FUNCTION)
|
|
{
|
|
/* A conversion function, so use the argument. */
|
|
gcc_assert (expr->value.function.isym
|
|
&& expr->value.function.isym->conversion);
|
|
expr = expr->value.function.actual->expr;
|
|
}
|
|
|
|
if (expr->expr_type == EXPR_VARIABLE)
|
|
{
|
|
tmp = TREE_TYPE (expr->symtree->n.sym->backend_decl);
|
|
for (ref = expr->ref; ref; ref = ref->next)
|
|
{
|
|
if (ref->type == REF_COMPONENT
|
|
&& ref->u.c.component->as
|
|
&& ref->next
|
|
&& ref->next->u.ar.type == AR_FULL)
|
|
tmp = TREE_TYPE (ref->u.c.component->backend_decl);
|
|
}
|
|
return GFC_TYPE_ARRAY_LBOUND(tmp, dim);
|
|
}
|
|
|
|
return gfc_index_one_node;
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_descriptor_for_assign_realloc (stmtblock_t *block, gfc_loopinfo *loop,
|
|
gfc_expr *expr1, gfc_expr *expr2,
|
|
tree desc, tree desc2, tree elemsize2,
|
|
tree class_expr2, bool coarray)
|
|
{
|
|
gfc_array_spec *as;
|
|
/* Get arrayspec if expr is a full array. */
|
|
if (expr2 && expr2->expr_type == EXPR_FUNCTION
|
|
&& expr2->value.function.isym
|
|
&& expr2->value.function.isym->conversion)
|
|
{
|
|
/* For conversion functions, take the arg. */
|
|
gfc_expr *arg = expr2->value.function.actual->expr;
|
|
as = gfc_get_full_arrayspec_from_expr (arg);
|
|
}
|
|
else if (expr2)
|
|
as = gfc_get_full_arrayspec_from_expr (expr2);
|
|
else
|
|
as = NULL;
|
|
|
|
/* Now modify the lhs descriptor and the associated scalarizer
|
|
variables. F2003 7.4.1.3: "If variable is or becomes an
|
|
unallocated allocatable variable, then it is allocated with each
|
|
deferred type parameter equal to the corresponding type parameters
|
|
of expr , with the shape of expr , and with each lower bound equal
|
|
to the corresponding element of LBOUND(expr)."
|
|
Reuse size1 to keep a dimension-by-dimension track of the
|
|
stride of the new array. */
|
|
tree size1;
|
|
if (GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
|
size1 = elemsize2;
|
|
else
|
|
size1 = gfc_index_one_node;
|
|
|
|
tree offset = gfc_index_zero_node;
|
|
|
|
for (int n = 0; n < expr2->rank; n++)
|
|
{
|
|
tree tmp = fold_build2_loc (input_location, MINUS_EXPR,
|
|
gfc_array_index_type,
|
|
loop->to[n], loop->from[n]);
|
|
tree ubound = fold_build2_loc (input_location, PLUS_EXPR,
|
|
gfc_array_index_type,
|
|
tmp, gfc_index_one_node);
|
|
|
|
if (as)
|
|
shift_dimension_fields (block, desc, gfc_rank_cst[n],
|
|
get_std_lbound (expr2, desc2, n,
|
|
as->type == AS_ASSUMED_SIZE),
|
|
gfc_index_one_node, ubound, size1, &offset);
|
|
else
|
|
set_dimension_fields (block, desc, gfc_rank_cst[n], gfc_index_one_node,
|
|
ubound, size1, &offset);
|
|
|
|
size1 = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
|
|
ubound, size1);
|
|
}
|
|
|
|
/* Set the lhs descriptor and scalarizer offsets. For rank > 1,
|
|
the array offset is saved and the info.offset is used for a
|
|
running offset. Use the saved_offset instead. */
|
|
gfc_conv_descriptor_offset_set (block, desc, offset);
|
|
|
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
|
|
gfc_conv_descriptor_span_set (block, desc, elemsize2);
|
|
|
|
bool bytes_counted_strides;
|
|
bytes_counted_strides = GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (desc));
|
|
|
|
/* For deferred character length, the 'size' field of the dtype might
|
|
have changed so set the dtype. */
|
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
|
|
&& expr1->ts.type == BT_CHARACTER && expr1->ts.deferred)
|
|
{
|
|
tree type;
|
|
if (expr2->ts.u.cl->backend_decl)
|
|
type = gfc_typenode_for_spec (&expr2->ts);
|
|
else
|
|
type = gfc_typenode_for_spec (&expr1->ts);
|
|
|
|
tree tmp = gfc_get_dtype_rank_type (expr1->rank, type,
|
|
bytes_counted_strides);
|
|
gfc_conv_descriptor_dtype_set (block, desc, tmp);
|
|
gfc_conv_descriptor_elem_len_set (block, desc, elemsize2);
|
|
}
|
|
else if (expr1->ts.type == BT_CLASS)
|
|
{
|
|
tree type;
|
|
|
|
if (expr2->ts.type != BT_CLASS)
|
|
type = gfc_typenode_for_spec (&expr2->ts);
|
|
else
|
|
type = gfc_get_character_type_len (1, elemsize2);
|
|
|
|
tree tmp = gfc_get_dtype_rank_type (expr2->rank, type,
|
|
bytes_counted_strides);
|
|
gfc_conv_descriptor_dtype_set (block, desc, tmp);
|
|
|
|
/* Set the _len field as well... */
|
|
if (UNLIMITED_POLY (expr1))
|
|
{
|
|
tmp = gfc_class_len_get (TREE_OPERAND (desc, 0));
|
|
if (expr2->ts.type == BT_CHARACTER)
|
|
gfc_add_modify (block, tmp,
|
|
fold_convert (TREE_TYPE (tmp),
|
|
TYPE_SIZE_UNIT (type)));
|
|
else if (UNLIMITED_POLY (expr2))
|
|
gfc_add_modify (block, tmp,
|
|
gfc_class_len_get (TREE_OPERAND (desc2, 0)));
|
|
else
|
|
gfc_add_modify (block, tmp,
|
|
build_int_cst (TREE_TYPE (tmp), 0));
|
|
}
|
|
/* ...and the vptr. */
|
|
tmp = gfc_class_vptr_get (TREE_OPERAND (desc, 0));
|
|
tree tmp2;
|
|
if (expr2->ts.type == BT_CLASS && !VAR_P (desc2)
|
|
&& TREE_CODE (desc2) == COMPONENT_REF)
|
|
{
|
|
tmp2 = gfc_get_class_from_expr (desc2);
|
|
tmp2 = gfc_class_vptr_get (tmp2);
|
|
}
|
|
else if (expr2->ts.type == BT_CLASS && class_expr2 != NULL_TREE)
|
|
tmp2 = gfc_class_vptr_get (class_expr2);
|
|
else
|
|
{
|
|
tmp2 = gfc_get_symbol_decl (gfc_find_vtab (&expr2->ts));
|
|
tmp2 = gfc_build_addr_expr (TREE_TYPE (tmp), tmp2);
|
|
}
|
|
|
|
gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
|
|
}
|
|
else if (coarray && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
|
|
gfc_conv_descriptor_dtype_set (block, desc,
|
|
gfc_get_dtype (TREE_TYPE (desc)));
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_set_pdt_array_descriptor (stmtblock_t *block, tree descr,
|
|
gfc_array_spec *as,
|
|
gfc_actual_arglist *pdt_param_list, tree elt_size)
|
|
{
|
|
gfc_se tse;
|
|
tree size = gfc_index_one_node;
|
|
tree offset = gfc_index_zero_node;
|
|
gfc_expr *e;
|
|
|
|
gcc_assert (!GFC_BYTES_STRIDES_ARRAY_TYPE_P (TREE_TYPE (descr)));
|
|
|
|
/* This chunk takes the expressions for 'lower' and 'upper'
|
|
in the arrayspec and substitutes in the expressions for
|
|
the parameters from 'pdt_param_list'. The descriptor
|
|
fields can then be filled from the values so obtained. */
|
|
gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (descr)));
|
|
for (int i = 0; i < as->rank; i++)
|
|
{
|
|
gfc_init_se (&tse, NULL);
|
|
e = gfc_copy_expr (as->lower[i]);
|
|
gfc_insert_parameter_exprs (e, pdt_param_list);
|
|
gfc_conv_expr_type (&tse, e, gfc_array_index_type);
|
|
gfc_free_expr (e);
|
|
tree lower = tse.expr;
|
|
gfc_add_block_to_block (block, &tse.pre);
|
|
|
|
e = gfc_copy_expr (as->upper[i]);
|
|
gfc_insert_parameter_exprs (e, pdt_param_list);
|
|
gfc_conv_expr_type (&tse, e, gfc_array_index_type);
|
|
gfc_free_expr (e);
|
|
tree upper = tse.expr;
|
|
gfc_add_block_to_block (block, &tse.pre);
|
|
|
|
set_dimension_fields (block, descr, gfc_rank_cst[i], lower, upper, size,
|
|
&offset);
|
|
|
|
tree tmp = fold_build2_loc (input_location, MINUS_EXPR,
|
|
gfc_array_index_type, upper, lower);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
tmp, gfc_index_one_node);
|
|
size = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, size, tmp);
|
|
}
|
|
gfc_conv_descriptor_offset_set (block, descr, offset);
|
|
gfc_conv_descriptor_dtype_set (block, descr,
|
|
gfc_get_dtype (TREE_TYPE (descr)));
|
|
|
|
gfc_conv_descriptor_span_set (block, descr, elt_size);
|
|
|
|
size = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, size, elt_size);
|
|
size = gfc_evaluate_now (size, block);
|
|
gfc_conv_descriptor_data_set (block, descr,
|
|
gfc_call_malloc (block, NULL, size));
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
/* Extend the data in array DESC by EXTRA elements. */
|
|
|
|
void
|
|
gfc_grow_array (stmtblock_t * pblock, tree desc, tree extra)
|
|
{
|
|
tree arg0, arg1;
|
|
tree tmp;
|
|
tree size;
|
|
tree ubound;
|
|
|
|
if (integer_zerop (extra))
|
|
return;
|
|
|
|
ubound = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[0]);
|
|
|
|
/* Add EXTRA to the upper bound. */
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
ubound, extra);
|
|
gfc_conv_descriptor_ubound_set (pblock, desc, gfc_rank_cst[0], tmp);
|
|
|
|
/* Get the value of the current data pointer. */
|
|
arg0 = gfc_conv_descriptor_data_get (desc);
|
|
|
|
/* Calculate the new array size. */
|
|
size = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (desc)));
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
|
|
ubound, gfc_index_one_node);
|
|
arg1 = fold_build2_loc (input_location, MULT_EXPR, size_type_node,
|
|
fold_convert (size_type_node, tmp),
|
|
fold_convert (size_type_node, size));
|
|
|
|
/* Call the realloc() function. */
|
|
tmp = gfc_call_realloc (pblock, arg0, arg1);
|
|
gfc_conv_descriptor_data_set (pblock, desc, tmp);
|
|
}
|
|
|
|
|
|
/* Fills in an array descriptor, and returns the size of the array.
|
|
The size will be a simple_val, ie a variable or a constant. Also
|
|
calculates the offset of the base. The pointer argument overflow,
|
|
which should be of integer type, will increase in value if overflow
|
|
occurs during the size calculation. Returns the size of the array.
|
|
{
|
|
stride = 1;
|
|
offset = 0;
|
|
for (n = 0; n < rank; n++)
|
|
{
|
|
a.lbound[n] = specified_lower_bound;
|
|
offset = offset + a.lbond[n] * stride;
|
|
size = 1 - lbound;
|
|
a.ubound[n] = specified_upper_bound;
|
|
a.stride[n] = stride;
|
|
size = size >= 0 ? ubound + size : 0; //size = ubound + 1 - lbound
|
|
overflow += size == 0 ? 0: (MAX/size < stride ? 1: 0);
|
|
stride = stride * size;
|
|
}
|
|
for (n = rank; n < rank+corank; n++)
|
|
(Set lcobound/ucobound as above.)
|
|
element_size = sizeof (array element);
|
|
if (!rank)
|
|
return element_size
|
|
stride = (size_t) stride;
|
|
overflow += element_size == 0 ? 0: (MAX/element_size < stride ? 1: 0);
|
|
stride = stride * element_size;
|
|
return (stride);
|
|
} */
|
|
/*GCC ARRAYS*/
|
|
|
|
tree
|
|
gfc_descriptor_init_count (tree descriptor, int rank, int corank,
|
|
gfc_expr ** lower, gfc_expr ** upper,
|
|
stmtblock_t * pblock, stmtblock_t * descriptor_block,
|
|
tree * overflow, tree expr3_elem_size,
|
|
gfc_expr *expr3, tree expr3_desc,
|
|
bool e3_has_nodescriptor, gfc_expr *expr,
|
|
tree element_size, gfc_typespec * explicit_ts,
|
|
tree *empty_array_cond)
|
|
{
|
|
tree type;
|
|
tree tmp;
|
|
tree size;
|
|
tree offset;
|
|
tree stride;
|
|
tree cond;
|
|
gfc_expr *ubound;
|
|
gfc_se se;
|
|
int n;
|
|
|
|
type = TREE_TYPE (descriptor);
|
|
|
|
bool bytes_counted_strides = GFC_BYTES_STRIDES_ARRAY_TYPE_P (type);
|
|
|
|
if (bytes_counted_strides)
|
|
stride = fold_convert_loc (input_location, gfc_array_index_type,
|
|
element_size);
|
|
else
|
|
stride = gfc_index_one_node;
|
|
|
|
offset = gfc_index_zero_node;
|
|
|
|
/* Set the dtype before the alloc, because registration of coarrays needs
|
|
it initialized. */
|
|
if (expr->ts.type == BT_CHARACTER
|
|
&& expr->ts.deferred
|
|
&& expr->ts.u.cl->backend_decl
|
|
&& VAR_P (expr->ts.u.cl->backend_decl))
|
|
{
|
|
tree dtype;
|
|
if (expr3_elem_size
|
|
&& TREE_CODE (expr3_elem_size) == INTEGER_CST)
|
|
dtype = get_dtype_rank_type_size (rank, BT_CHARACTER,
|
|
bytes_counted_strides,
|
|
expr3_elem_size);
|
|
else
|
|
{
|
|
type = gfc_typenode_for_spec (&expr->ts);
|
|
dtype = gfc_get_dtype_rank_type (rank, type, bytes_counted_strides);
|
|
}
|
|
gfc_conv_descriptor_dtype_set (pblock, descriptor, dtype);
|
|
if (expr3_elem_size
|
|
&& TREE_CODE (expr3_elem_size) != INTEGER_CST)
|
|
gfc_conv_descriptor_elem_len_set (pblock, descriptor, expr3_elem_size);
|
|
}
|
|
else if (expr->ts.type == BT_CHARACTER
|
|
&& expr->ts.deferred
|
|
&& TREE_CODE (descriptor) == COMPONENT_REF)
|
|
{
|
|
/* Deferred character components have their string length tucked away
|
|
in a hidden field of the derived type. Obtain that and use it to
|
|
set the dtype. The charlen backend decl is zero because the field
|
|
type is zero length. */
|
|
gfc_ref *ref;
|
|
tmp = NULL_TREE;
|
|
for (ref = expr->ref; ref; ref = ref->next)
|
|
if (ref->type == REF_COMPONENT
|
|
&& gfc_deferred_strlen (ref->u.c.component, &tmp))
|
|
break;
|
|
gcc_assert (tmp != NULL_TREE);
|
|
tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (tmp),
|
|
TREE_OPERAND (descriptor, 0), tmp, NULL_TREE);
|
|
tmp = fold_convert (gfc_charlen_type_node, tmp);
|
|
type = gfc_get_character_type_len (expr->ts.kind, tmp);
|
|
tree dtype = gfc_get_dtype_rank_type (rank, type, bytes_counted_strides);
|
|
gfc_conv_descriptor_dtype_set (pblock, descriptor, dtype);
|
|
}
|
|
else if (expr3_desc && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (expr3_desc)))
|
|
gfc_conv_descriptor_dtype_set (pblock, descriptor,
|
|
gfc_conv_descriptor_dtype_get (expr3_desc));
|
|
else if (expr->ts.type == BT_CLASS && explicit_ts->type == BT_UNKNOWN
|
|
&& expr3 && expr3->ts.type != BT_CLASS
|
|
&& expr3_elem_size != NULL_TREE && expr3_desc == NULL_TREE)
|
|
gfc_conv_descriptor_elem_len_set (pblock, descriptor, expr3_elem_size);
|
|
else if (explicit_ts->type != BT_UNKNOWN)
|
|
{
|
|
tree elt_type = gfc_typenode_for_spec (explicit_ts);
|
|
tree dtype = gfc_get_dtype_rank_type (rank, elt_type,
|
|
bytes_counted_strides);
|
|
gfc_conv_descriptor_dtype_set (pblock, descriptor, dtype);
|
|
}
|
|
else
|
|
gfc_conv_descriptor_dtype_set (pblock, descriptor, gfc_get_dtype (type));
|
|
|
|
tree empty_cond = logical_false_node;
|
|
|
|
for (n = 0; n < rank; n++)
|
|
{
|
|
tree conv_lbound;
|
|
tree conv_ubound;
|
|
|
|
/* We have 3 possibilities for determining the size of the array:
|
|
lower == NULL => lbound = 1, ubound = upper[n]
|
|
upper[n] = NULL => lbound = 1, ubound = lower[n]
|
|
upper[n] != NULL => lbound = lower[n], ubound = upper[n] */
|
|
ubound = upper[n];
|
|
|
|
/* Set lower bound. */
|
|
gfc_init_se (&se, NULL);
|
|
if (expr3_desc != NULL_TREE)
|
|
{
|
|
if (e3_has_nodescriptor)
|
|
/* The lbound of nondescriptor arrays like array constructors,
|
|
nonallocatable/nonpointer function results/variables,
|
|
start at zero, but when allocating it, the standard expects
|
|
the array to start at one. */
|
|
se.expr = gfc_index_one_node;
|
|
else
|
|
se.expr = gfc_conv_descriptor_lbound_get (expr3_desc,
|
|
gfc_rank_cst[n]);
|
|
}
|
|
else if (lower == NULL)
|
|
se.expr = gfc_index_one_node;
|
|
else
|
|
{
|
|
gcc_assert (lower[n]);
|
|
if (ubound)
|
|
{
|
|
gfc_conv_expr_type (&se, lower[n], gfc_array_index_type);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
}
|
|
else
|
|
{
|
|
se.expr = gfc_index_one_node;
|
|
ubound = lower[n];
|
|
}
|
|
}
|
|
conv_lbound = se.expr;
|
|
conv_lbound = gfc_evaluate_now (conv_lbound, pblock);
|
|
|
|
/* Set upper bound. */
|
|
gfc_init_se (&se, NULL);
|
|
if (expr3_desc != NULL_TREE)
|
|
{
|
|
if (e3_has_nodescriptor)
|
|
{
|
|
/* The lbound of nondescriptor arrays like array constructors,
|
|
nonallocatable/nonpointer function results/variables,
|
|
start at zero, but when allocating it, the standard expects
|
|
the array to start at one. Therefore fix the upper bound to be
|
|
(desc.ubound - desc.lbound) + 1. */
|
|
tmp = gfc_conv_descriptor_extent_get (expr3_desc,
|
|
gfc_rank_cst[n]);
|
|
se.expr = gfc_evaluate_now (tmp, pblock);
|
|
}
|
|
else
|
|
se.expr = gfc_conv_descriptor_ubound_get (expr3_desc,
|
|
gfc_rank_cst[n]);
|
|
}
|
|
else
|
|
{
|
|
gcc_assert (ubound);
|
|
gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
if (ubound->expr_type == EXPR_FUNCTION)
|
|
se.expr = gfc_evaluate_now (se.expr, pblock);
|
|
}
|
|
conv_ubound = se.expr;
|
|
conv_ubound = gfc_evaluate_now (conv_ubound, pblock);
|
|
|
|
set_dimension_fields (descriptor_block, descriptor, gfc_rank_cst[n],
|
|
conv_lbound, conv_ubound, stride, &offset);
|
|
|
|
/* Calculate size and check whether extent is negative. */
|
|
size = gfc_conv_array_extent_dim (conv_lbound, conv_ubound, &empty_cond);
|
|
size = gfc_evaluate_now (size, pblock);
|
|
|
|
/* Check whether multiplying the stride by the number of
|
|
elements in this dimension would overflow. We must also check
|
|
whether the current dimension has zero size in order to avoid
|
|
division by zero.
|
|
*/
|
|
tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
|
|
gfc_array_index_type,
|
|
fold_convert (gfc_array_index_type,
|
|
TYPE_MAX_VALUE (gfc_array_index_type)),
|
|
size);
|
|
cond = gfc_unlikely (fold_build2_loc (input_location, LT_EXPR,
|
|
logical_type_node, tmp, stride),
|
|
PRED_FORTRAN_OVERFLOW);
|
|
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
|
|
integer_one_node, integer_zero_node);
|
|
cond = gfc_unlikely (fold_build2_loc (input_location, EQ_EXPR,
|
|
logical_type_node, size,
|
|
gfc_index_zero_node),
|
|
PRED_FORTRAN_SIZE_ZERO);
|
|
tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
|
|
integer_zero_node, tmp);
|
|
tmp = fold_build2_loc (input_location, PLUS_EXPR, integer_type_node,
|
|
*overflow, tmp);
|
|
*overflow = gfc_evaluate_now (tmp, pblock);
|
|
|
|
/* Multiply the stride by the number of elements in this dimension. */
|
|
stride = fold_build2_loc (input_location, MULT_EXPR,
|
|
gfc_array_index_type, stride, size);
|
|
stride = gfc_evaluate_now (stride, pblock);
|
|
}
|
|
|
|
*empty_array_cond = empty_cond;
|
|
|
|
for (n = rank; n < rank + corank; n++)
|
|
{
|
|
ubound = upper[n];
|
|
|
|
/* Set lower bound. */
|
|
gfc_init_se (&se, NULL);
|
|
if (lower == NULL || lower[n] == NULL)
|
|
{
|
|
gcc_assert (n == rank + corank - 1);
|
|
se.expr = gfc_index_one_node;
|
|
}
|
|
else
|
|
{
|
|
if (ubound || n == rank + corank - 1)
|
|
{
|
|
gfc_conv_expr_type (&se, lower[n], gfc_array_index_type);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
}
|
|
else
|
|
{
|
|
se.expr = gfc_index_one_node;
|
|
ubound = lower[n];
|
|
}
|
|
}
|
|
gfc_conv_descriptor_lbound_set (descriptor_block, descriptor,
|
|
gfc_rank_cst[n], se.expr);
|
|
|
|
if (n < rank + corank - 1)
|
|
{
|
|
gfc_init_se (&se, NULL);
|
|
gcc_assert (ubound);
|
|
gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
|
|
gfc_add_block_to_block (pblock, &se.pre);
|
|
gfc_conv_descriptor_ubound_set (descriptor_block, descriptor,
|
|
gfc_rank_cst[n], se.expr);
|
|
}
|
|
}
|
|
|
|
if (rank == 0)
|
|
return gfc_index_one_node;
|
|
|
|
/* Update the array descriptor with the offset and the span. */
|
|
gfc_conv_descriptor_offset_set (descriptor_block, descriptor, offset);
|
|
tmp = fold_convert (gfc_array_index_type, element_size);
|
|
gfc_conv_descriptor_span_set (descriptor_block, descriptor, tmp);
|
|
|
|
return stride;
|
|
}
|
|
|
|
|
|
void
|
|
gfc_set_empty_descriptor_bounds (stmtblock_t *block, tree descr, int rank)
|
|
{
|
|
tree offset = gfc_index_zero_node;
|
|
for (int n = 0; n < rank; n++)
|
|
set_dimension_fields (block, descr, gfc_rank_cst[n], gfc_index_one_node,
|
|
gfc_index_zero_node, gfc_index_zero_node, &offset);
|
|
|
|
gfc_conv_descriptor_offset_set (block, descr, gfc_index_zero_node);
|
|
}
|
|
|
|
|
|
tree
|
|
gfc_create_unallocated_library_result_descriptor (stmtblock_t *block, tree source_descr, tree dtype)
|
|
{
|
|
if (dtype == NULL_TREE)
|
|
dtype = gfc_get_dtype (TREE_TYPE (source_descr));
|
|
|
|
gfc_conv_descriptor_dtype_set (block, source_descr, dtype);
|
|
gfc_conv_descriptor_span_set (block, source_descr,
|
|
gfc_conv_descriptor_elem_len_get (source_descr));
|
|
|
|
tree res_desc = gfc_evaluate_now (source_descr, block);
|
|
gfc_conv_descriptor_data_set (block, res_desc, null_pointer_node);
|
|
|
|
return res_desc;
|
|
}
|