blob: b473d660e736f5a7bba3ca9d4745f74d4a4900e9 [file] [log] [blame]
/* Backend function setup
Copyright (C) 2002-2013 Free Software Foundation, Inc.
Contributed by Paul Brook
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/>. */
/* trans-decl.c -- Handling of backend function and variable decls, etc */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "tree-dump.h"
#include "gimple.h" /* For create_tmp_var_raw. */
#include "ggc.h"
#include "diagnostic-core.h" /* For internal_error. */
#include "toplev.h" /* For announce_function. */
#include "target.h"
#include "function.h"
#include "flags.h"
#include "cgraph.h"
#include "debug.h"
#include "gfortran.h"
#include "pointer-set.h"
#include "constructor.h"
#include "trans.h"
#include "trans-types.h"
#include "trans-array.h"
#include "trans-const.h"
/* Only for gfc_trans_code. Shouldn't need to include this. */
#include "trans-stmt.h"
#define MAX_LABEL_VALUE 99999
/* Holds the result of the function if no result variable specified. */
static GTY(()) tree current_fake_result_decl;
static GTY(()) tree parent_fake_result_decl;
/* Holds the variable DECLs for the current function. */
static GTY(()) tree saved_function_decls;
static GTY(()) tree saved_parent_function_decls;
static struct pointer_set_t *nonlocal_dummy_decl_pset;
static GTY(()) tree nonlocal_dummy_decls;
/* Holds the variable DECLs that are locals. */
static GTY(()) tree saved_local_decls;
/* The namespace of the module we're currently generating. Only used while
outputting decls for module variables. Do not rely on this being set. */
static gfc_namespace *module_namespace;
/* The currently processed procedure symbol. */
static gfc_symbol* current_procedure_symbol = NULL;
/* With -fcoarray=lib: For generating the registering call
of static coarrays. */
static bool has_coarray_vars;
static stmtblock_t caf_init_block;
/* List of static constructor functions. */
tree gfc_static_ctors;
/* Function declarations for builtin library functions. */
tree gfor_fndecl_pause_numeric;
tree gfor_fndecl_pause_string;
tree gfor_fndecl_stop_numeric;
tree gfor_fndecl_stop_numeric_f08;
tree gfor_fndecl_stop_string;
tree gfor_fndecl_error_stop_numeric;
tree gfor_fndecl_error_stop_string;
tree gfor_fndecl_runtime_error;
tree gfor_fndecl_runtime_error_at;
tree gfor_fndecl_runtime_warning_at;
tree gfor_fndecl_os_error;
tree gfor_fndecl_generate_error;
tree gfor_fndecl_set_args;
tree gfor_fndecl_set_fpe;
tree gfor_fndecl_set_options;
tree gfor_fndecl_set_convert;
tree gfor_fndecl_set_record_marker;
tree gfor_fndecl_set_max_subrecord_length;
tree gfor_fndecl_ctime;
tree gfor_fndecl_fdate;
tree gfor_fndecl_ttynam;
tree gfor_fndecl_in_pack;
tree gfor_fndecl_in_unpack;
tree gfor_fndecl_associated;
/* Coarray run-time library function decls. */
tree gfor_fndecl_caf_init;
tree gfor_fndecl_caf_finalize;
tree gfor_fndecl_caf_register;
tree gfor_fndecl_caf_deregister;
tree gfor_fndecl_caf_critical;
tree gfor_fndecl_caf_end_critical;
tree gfor_fndecl_caf_sync_all;
tree gfor_fndecl_caf_sync_images;
tree gfor_fndecl_caf_error_stop;
tree gfor_fndecl_caf_error_stop_str;
/* Coarray global variables for num_images/this_image. */
tree gfort_gvar_caf_num_images;
tree gfort_gvar_caf_this_image;
/* Math functions. Many other math functions are handled in
trans-intrinsic.c. */
gfc_powdecl_list gfor_fndecl_math_powi[4][3];
tree gfor_fndecl_math_ishftc4;
tree gfor_fndecl_math_ishftc8;
tree gfor_fndecl_math_ishftc16;
/* String functions. */
tree gfor_fndecl_compare_string;
tree gfor_fndecl_concat_string;
tree gfor_fndecl_string_len_trim;
tree gfor_fndecl_string_index;
tree gfor_fndecl_string_scan;
tree gfor_fndecl_string_verify;
tree gfor_fndecl_string_trim;
tree gfor_fndecl_string_minmax;
tree gfor_fndecl_adjustl;
tree gfor_fndecl_adjustr;
tree gfor_fndecl_select_string;
tree gfor_fndecl_compare_string_char4;
tree gfor_fndecl_concat_string_char4;
tree gfor_fndecl_string_len_trim_char4;
tree gfor_fndecl_string_index_char4;
tree gfor_fndecl_string_scan_char4;
tree gfor_fndecl_string_verify_char4;
tree gfor_fndecl_string_trim_char4;
tree gfor_fndecl_string_minmax_char4;
tree gfor_fndecl_adjustl_char4;
tree gfor_fndecl_adjustr_char4;
tree gfor_fndecl_select_string_char4;
/* Conversion between character kinds. */
tree gfor_fndecl_convert_char1_to_char4;
tree gfor_fndecl_convert_char4_to_char1;
/* Other misc. runtime library functions. */
tree gfor_fndecl_size0;
tree gfor_fndecl_size1;
tree gfor_fndecl_iargc;
/* Intrinsic functions implemented in Fortran. */
tree gfor_fndecl_sc_kind;
tree gfor_fndecl_si_kind;
tree gfor_fndecl_sr_kind;
/* BLAS gemm functions. */
tree gfor_fndecl_sgemm;
tree gfor_fndecl_dgemm;
tree gfor_fndecl_cgemm;
tree gfor_fndecl_zgemm;
static void
gfc_add_decl_to_parent_function (tree decl)
{
gcc_assert (decl);
DECL_CONTEXT (decl) = DECL_CONTEXT (current_function_decl);
DECL_NONLOCAL (decl) = 1;
DECL_CHAIN (decl) = saved_parent_function_decls;
saved_parent_function_decls = decl;
}
void
gfc_add_decl_to_function (tree decl)
{
gcc_assert (decl);
TREE_USED (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
DECL_CHAIN (decl) = saved_function_decls;
saved_function_decls = decl;
}
static void
add_decl_as_local (tree decl)
{
gcc_assert (decl);
TREE_USED (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
DECL_CHAIN (decl) = saved_local_decls;
saved_local_decls = decl;
}
/* Build a backend label declaration. Set TREE_USED for named labels.
The context of the label is always the current_function_decl. All
labels are marked artificial. */
tree
gfc_build_label_decl (tree label_id)
{
/* 2^32 temporaries should be enough. */
static unsigned int tmp_num = 1;
tree label_decl;
char *label_name;
if (label_id == NULL_TREE)
{
/* Build an internal label name. */
ASM_FORMAT_PRIVATE_NAME (label_name, "L", tmp_num++);
label_id = get_identifier (label_name);
}
else
label_name = NULL;
/* Build the LABEL_DECL node. Labels have no type. */
label_decl = build_decl (input_location,
LABEL_DECL, label_id, void_type_node);
DECL_CONTEXT (label_decl) = current_function_decl;
DECL_MODE (label_decl) = VOIDmode;
/* We always define the label as used, even if the original source
file never references the label. We don't want all kinds of
spurious warnings for old-style Fortran code with too many
labels. */
TREE_USED (label_decl) = 1;
DECL_ARTIFICIAL (label_decl) = 1;
return label_decl;
}
/* Set the backend source location of a decl. */
void
gfc_set_decl_location (tree decl, locus * loc)
{
DECL_SOURCE_LOCATION (decl) = loc->lb->location;
}
/* Return the backend label declaration for a given label structure,
or create it if it doesn't exist yet. */
tree
gfc_get_label_decl (gfc_st_label * lp)
{
if (lp->backend_decl)
return lp->backend_decl;
else
{
char label_name[GFC_MAX_SYMBOL_LEN + 1];
tree label_decl;
/* Validate the label declaration from the front end. */
gcc_assert (lp != NULL && lp->value <= MAX_LABEL_VALUE);
/* Build a mangled name for the label. */
sprintf (label_name, "__label_%.6d", lp->value);
/* Build the LABEL_DECL node. */
label_decl = gfc_build_label_decl (get_identifier (label_name));
/* Tell the debugger where the label came from. */
if (lp->value <= MAX_LABEL_VALUE) /* An internal label. */
gfc_set_decl_location (label_decl, &lp->where);
else
DECL_ARTIFICIAL (label_decl) = 1;
/* Store the label in the label list and return the LABEL_DECL. */
lp->backend_decl = label_decl;
return label_decl;
}
}
/* Convert a gfc_symbol to an identifier of the same name. */
static tree
gfc_sym_identifier (gfc_symbol * sym)
{
if (sym->attr.is_main_program && strcmp (sym->name, "main") == 0)
return (get_identifier ("MAIN__"));
else
return (get_identifier (sym->name));
}
/* Construct mangled name from symbol name. */
static tree
gfc_sym_mangled_identifier (gfc_symbol * sym)
{
char name[GFC_MAX_MANGLED_SYMBOL_LEN + 1];
/* Prevent the mangling of identifiers that have an assigned
binding label (mainly those that are bind(c)). */
if (sym->attr.is_bind_c == 1 && sym->binding_label)
return get_identifier (sym->binding_label);
if (sym->module == NULL)
return gfc_sym_identifier (sym);
else
{
snprintf (name, sizeof name, "__%s_MOD_%s", sym->module, sym->name);
return get_identifier (name);
}
}
/* Construct mangled function name from symbol name. */
static tree
gfc_sym_mangled_function_id (gfc_symbol * sym)
{
int has_underscore;
char name[GFC_MAX_MANGLED_SYMBOL_LEN + 1];
/* It may be possible to simply use the binding label if it's
provided, and remove the other checks. Then we could use it
for other things if we wished. */
if ((sym->attr.is_bind_c == 1 || sym->attr.is_iso_c == 1) &&
sym->binding_label)
/* use the binding label rather than the mangled name */
return get_identifier (sym->binding_label);
if (sym->module == NULL || sym->attr.proc == PROC_EXTERNAL
|| (sym->module != NULL && (sym->attr.external
|| sym->attr.if_source == IFSRC_IFBODY)))
{
/* Main program is mangled into MAIN__. */
if (sym->attr.is_main_program)
return get_identifier ("MAIN__");
/* Intrinsic procedures are never mangled. */
if (sym->attr.proc == PROC_INTRINSIC)
return get_identifier (sym->name);
if (gfc_option.flag_underscoring)
{
has_underscore = strchr (sym->name, '_') != 0;
if (gfc_option.flag_second_underscore && has_underscore)
snprintf (name, sizeof name, "%s__", sym->name);
else
snprintf (name, sizeof name, "%s_", sym->name);
return get_identifier (name);
}
else
return get_identifier (sym->name);
}
else
{
snprintf (name, sizeof name, "__%s_MOD_%s", sym->module, sym->name);
return get_identifier (name);
}
}
void
gfc_set_decl_assembler_name (tree decl, tree name)
{
tree target_mangled = targetm.mangle_decl_assembler_name (decl, name);
SET_DECL_ASSEMBLER_NAME (decl, target_mangled);
}
/* Returns true if a variable of specified size should go on the stack. */
int
gfc_can_put_var_on_stack (tree size)
{
unsigned HOST_WIDE_INT low;
if (!INTEGER_CST_P (size))
return 0;
if (gfc_option.flag_max_stack_var_size < 0)
return 1;
if (TREE_INT_CST_HIGH (size) != 0)
return 0;
low = TREE_INT_CST_LOW (size);
if (low > (unsigned HOST_WIDE_INT) gfc_option.flag_max_stack_var_size)
return 0;
/* TODO: Set a per-function stack size limit. */
return 1;
}
/* gfc_finish_cray_pointee sets DECL_VALUE_EXPR for a Cray pointee to
an expression involving its corresponding pointer. There are
2 cases; one for variable size arrays, and one for everything else,
because variable-sized arrays require one fewer level of
indirection. */
static void
gfc_finish_cray_pointee (tree decl, gfc_symbol *sym)
{
tree ptr_decl = gfc_get_symbol_decl (sym->cp_pointer);
tree value;
/* Parameters need to be dereferenced. */
if (sym->cp_pointer->attr.dummy)
ptr_decl = build_fold_indirect_ref_loc (input_location,
ptr_decl);
/* Check to see if we're dealing with a variable-sized array. */
if (sym->attr.dimension
&& TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
{
/* These decls will be dereferenced later, so we don't dereference
them here. */
value = convert (TREE_TYPE (decl), ptr_decl);
}
else
{
ptr_decl = convert (build_pointer_type (TREE_TYPE (decl)),
ptr_decl);
value = build_fold_indirect_ref_loc (input_location,
ptr_decl);
}
SET_DECL_VALUE_EXPR (decl, value);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
GFC_DECL_CRAY_POINTEE (decl) = 1;
}
/* Finish processing of a declaration without an initial value. */
static void
gfc_finish_decl (tree decl)
{
gcc_assert (TREE_CODE (decl) == PARM_DECL
|| DECL_INITIAL (decl) == NULL_TREE);
if (TREE_CODE (decl) != VAR_DECL)
return;
if (DECL_SIZE (decl) == NULL_TREE
&& TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE)
layout_decl (decl, 0);
/* A few consistency checks. */
/* A static variable with an incomplete type is an error if it is
initialized. Also if it is not file scope. Otherwise, let it
through, but if it is not `extern' then it may cause an error
message later. */
/* An automatic variable with an incomplete type is an error. */
/* We should know the storage size. */
gcc_assert (DECL_SIZE (decl) != NULL_TREE
|| (TREE_STATIC (decl)
? (!DECL_INITIAL (decl) || !DECL_CONTEXT (decl))
: DECL_EXTERNAL (decl)));
/* The storage size should be constant. */
gcc_assert ((!DECL_EXTERNAL (decl) && !TREE_STATIC (decl))
|| !DECL_SIZE (decl)
|| TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST);
}
/* Apply symbol attributes to a variable, and add it to the function scope. */
static void
gfc_finish_var_decl (tree decl, gfc_symbol * sym)
{
tree new_type;
/* TREE_ADDRESSABLE means the address of this variable is actually needed.
This is the equivalent of the TARGET variables.
We also need to set this if the variable is passed by reference in a
CALL statement. */
/* Set DECL_VALUE_EXPR for Cray Pointees. */
if (sym->attr.cray_pointee)
gfc_finish_cray_pointee (decl, sym);
if (sym->attr.target)
TREE_ADDRESSABLE (decl) = 1;
/* If it wasn't used we wouldn't be getting it. */
TREE_USED (decl) = 1;
if (sym->attr.flavor == FL_PARAMETER
&& (sym->attr.dimension || sym->ts.type == BT_DERIVED))
TREE_READONLY (decl) = 1;
/* Chain this decl to the pending declarations. Don't do pushdecl()
because this would add them to the current scope rather than the
function scope. */
if (current_function_decl != NULL_TREE)
{
if (sym->ns->proc_name->backend_decl == current_function_decl
|| sym->result == sym)
gfc_add_decl_to_function (decl);
else if (sym->ns->proc_name->attr.flavor == FL_LABEL)
/* This is a BLOCK construct. */
add_decl_as_local (decl);
else
gfc_add_decl_to_parent_function (decl);
}
if (sym->attr.cray_pointee)
return;
if(sym->attr.is_bind_c == 1 && sym->binding_label)
{
/* We need to put variables that are bind(c) into the common
segment of the object file, because this is what C would do.
gfortran would typically put them in either the BSS or
initialized data segments, and only mark them as common if
they were part of common blocks. However, if they are not put
into common space, then C cannot initialize global Fortran
variables that it interoperates with and the draft says that
either Fortran or C should be able to initialize it (but not
both, of course.) (J3/04-007, section 15.3). */
TREE_PUBLIC(decl) = 1;
DECL_COMMON(decl) = 1;
}
/* If a variable is USE associated, it's always external. */
if (sym->attr.use_assoc)
{
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
}
else if (sym->module && !sym->attr.result && !sym->attr.dummy)
{
/* TODO: Don't set sym->module for result or dummy variables. */
gcc_assert (current_function_decl == NULL_TREE || sym->result == sym);
/* This is the declaration of a module variable. */
if (sym->attr.access == ACCESS_UNKNOWN
&& (sym->ns->default_access == ACCESS_PRIVATE
|| (sym->ns->default_access == ACCESS_UNKNOWN
&& gfc_option.flag_module_private)))
sym->attr.access = ACCESS_PRIVATE;
if (sym->attr.access != ACCESS_PRIVATE || sym->attr.public_used)
TREE_PUBLIC (decl) = 1;
TREE_STATIC (decl) = 1;
}
/* Derived types are a bit peculiar because of the possibility of
a default initializer; this must be applied each time the variable
comes into scope it therefore need not be static. These variables
are SAVE_NONE but have an initializer. Otherwise explicitly
initialized variables are SAVE_IMPLICIT and explicitly saved are
SAVE_EXPLICIT. */
if (!sym->attr.use_assoc
&& (sym->attr.save != SAVE_NONE || sym->attr.data
|| (sym->value && sym->ns->proc_name->attr.is_main_program)
|| (gfc_option.coarray == GFC_FCOARRAY_LIB
&& sym->attr.codimension && !sym->attr.allocatable)))
TREE_STATIC (decl) = 1;
if (sym->attr.volatile_)
{
TREE_THIS_VOLATILE (decl) = 1;
TREE_SIDE_EFFECTS (decl) = 1;
new_type = build_qualified_type (TREE_TYPE (decl), TYPE_QUAL_VOLATILE);
TREE_TYPE (decl) = new_type;
}
/* Keep variables larger than max-stack-var-size off stack. */
if (!sym->ns->proc_name->attr.recursive
&& INTEGER_CST_P (DECL_SIZE_UNIT (decl))
&& !gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))
/* Put variable length auto array pointers always into stack. */
&& (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
|| sym->attr.dimension == 0
|| sym->as->type != AS_EXPLICIT
|| sym->attr.pointer
|| sym->attr.allocatable)
&& !DECL_ARTIFICIAL (decl))
TREE_STATIC (decl) = 1;
/* Handle threadprivate variables. */
if (sym->attr.threadprivate
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
}
/* Allocate the lang-specific part of a decl. */
void
gfc_allocate_lang_decl (tree decl)
{
DECL_LANG_SPECIFIC (decl) = ggc_alloc_cleared_lang_decl(sizeof
(struct lang_decl));
}
/* Remember a symbol to generate initialization/cleanup code at function
entry/exit. */
static void
gfc_defer_symbol_init (gfc_symbol * sym)
{
gfc_symbol *p;
gfc_symbol *last;
gfc_symbol *head;
/* Don't add a symbol twice. */
if (sym->tlink)
return;
last = head = sym->ns->proc_name;
p = last->tlink;
/* Make sure that setup code for dummy variables which are used in the
setup of other variables is generated first. */
if (sym->attr.dummy)
{
/* Find the first dummy arg seen after us, or the first non-dummy arg.
This is a circular list, so don't go past the head. */
while (p != head
&& (!p->attr.dummy || p->dummy_order > sym->dummy_order))
{
last = p;
p = p->tlink;
}
}
/* Insert in between last and p. */
last->tlink = sym;
sym->tlink = p;
}
/* Used in gfc_get_symbol_decl and gfc_get_derived_type to obtain the
backend_decl for a module symbol, if it all ready exists. If the
module gsymbol does not exist, it is created. If the symbol does
not exist, it is added to the gsymbol namespace. Returns true if
an existing backend_decl is found. */
bool
gfc_get_module_backend_decl (gfc_symbol *sym)
{
gfc_gsymbol *gsym;
gfc_symbol *s;
gfc_symtree *st;
gsym = gfc_find_gsymbol (gfc_gsym_root, sym->module);
if (!gsym || (gsym->ns && gsym->type == GSYM_MODULE))
{
st = NULL;
s = NULL;
if (gsym)
gfc_find_symbol (sym->name, gsym->ns, 0, &s);
if (!s)
{
if (!gsym)
{
gsym = gfc_get_gsymbol (sym->module);
gsym->type = GSYM_MODULE;
gsym->ns = gfc_get_namespace (NULL, 0);
}
st = gfc_new_symtree (&gsym->ns->sym_root, sym->name);
st->n.sym = sym;
sym->refs++;
}
else if (sym->attr.flavor == FL_DERIVED)
{
if (s && s->attr.flavor == FL_PROCEDURE)
{
gfc_interface *intr;
gcc_assert (s->attr.generic);
for (intr = s->generic; intr; intr = intr->next)
if (intr->sym->attr.flavor == FL_DERIVED)
{
s = intr->sym;
break;
}
}
if (!s->backend_decl)
s->backend_decl = gfc_get_derived_type (s);
gfc_copy_dt_decls_ifequal (s, sym, true);
return true;
}
else if (s->backend_decl)
{
if (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS)
gfc_copy_dt_decls_ifequal (s->ts.u.derived, sym->ts.u.derived,
true);
else if (sym->ts.type == BT_CHARACTER)
sym->ts.u.cl->backend_decl = s->ts.u.cl->backend_decl;
sym->backend_decl = s->backend_decl;
return true;
}
}
return false;
}
/* Create an array index type variable with function scope. */
static tree
create_index_var (const char * pfx, int nest)
{
tree decl;
decl = gfc_create_var_np (gfc_array_index_type, pfx);
if (nest)
gfc_add_decl_to_parent_function (decl);
else
gfc_add_decl_to_function (decl);
return decl;
}
/* Create variables to hold all the non-constant bits of info for a
descriptorless array. Remember these in the lang-specific part of the
type. */
static void
gfc_build_qualified_array (tree decl, gfc_symbol * sym)
{
tree type;
int dim;
int nest;
gfc_namespace* procns;
type = TREE_TYPE (decl);
/* We just use the descriptor, if there is one. */
if (GFC_DESCRIPTOR_TYPE_P (type))
return;
gcc_assert (GFC_ARRAY_TYPE_P (type));
procns = gfc_find_proc_namespace (sym->ns);
nest = (procns->proc_name->backend_decl != current_function_decl)
&& !sym->attr.contained;
if (sym->attr.codimension && gfc_option.coarray == GFC_FCOARRAY_LIB
&& sym->as->type != AS_ASSUMED_SHAPE
&& GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE)
{
tree token;
token = gfc_create_var_np (build_qualified_type (pvoid_type_node,
TYPE_QUAL_RESTRICT),
"caf_token");
GFC_TYPE_ARRAY_CAF_TOKEN (type) = token;
DECL_ARTIFICIAL (token) = 1;
TREE_STATIC (token) = 1;
gfc_add_decl_to_function (token);
}
for (dim = 0; dim < GFC_TYPE_ARRAY_RANK (type); dim++)
{
if (GFC_TYPE_ARRAY_LBOUND (type, dim) == NULL_TREE)
{
GFC_TYPE_ARRAY_LBOUND (type, dim) = create_index_var ("lbound", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_LBOUND (type, dim)) = 1;
}
/* Don't try to use the unknown bound for assumed shape arrays. */
if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE
&& (sym->as->type != AS_ASSUMED_SIZE
|| dim < GFC_TYPE_ARRAY_RANK (type) - 1))
{
GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1;
}
if (GFC_TYPE_ARRAY_STRIDE (type, dim) == NULL_TREE)
{
GFC_TYPE_ARRAY_STRIDE (type, dim) = create_index_var ("stride", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_STRIDE (type, dim)) = 1;
}
}
for (dim = GFC_TYPE_ARRAY_RANK (type);
dim < GFC_TYPE_ARRAY_RANK (type) + GFC_TYPE_ARRAY_CORANK (type); dim++)
{
if (GFC_TYPE_ARRAY_LBOUND (type, dim) == NULL_TREE)
{
GFC_TYPE_ARRAY_LBOUND (type, dim) = create_index_var ("lbound", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_LBOUND (type, dim)) = 1;
}
/* Don't try to use the unknown ubound for the last coarray dimension. */
if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE
&& dim < GFC_TYPE_ARRAY_RANK (type) + GFC_TYPE_ARRAY_CORANK (type) - 1)
{
GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1;
}
}
if (GFC_TYPE_ARRAY_OFFSET (type) == NULL_TREE)
{
GFC_TYPE_ARRAY_OFFSET (type) = gfc_create_var_np (gfc_array_index_type,
"offset");
TREE_NO_WARNING (GFC_TYPE_ARRAY_OFFSET (type)) = 1;
if (nest)
gfc_add_decl_to_parent_function (GFC_TYPE_ARRAY_OFFSET (type));
else
gfc_add_decl_to_function (GFC_TYPE_ARRAY_OFFSET (type));
}
if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE
&& sym->as->type != AS_ASSUMED_SIZE)
{
GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest);
TREE_NO_WARNING (GFC_TYPE_ARRAY_SIZE (type)) = 1;
}
if (POINTER_TYPE_P (type))
{
gcc_assert (GFC_ARRAY_TYPE_P (TREE_TYPE (type)));
gcc_assert (TYPE_LANG_SPECIFIC (type)
== TYPE_LANG_SPECIFIC (TREE_TYPE (type)));
type = TREE_TYPE (type);
}
if (! COMPLETE_TYPE_P (type) && GFC_TYPE_ARRAY_SIZE (type))
{
tree size, range;
size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
GFC_TYPE_ARRAY_SIZE (type), gfc_index_one_node);
range = build_range_type (gfc_array_index_type, gfc_index_zero_node,
size);
TYPE_DOMAIN (type) = range;
layout_type (type);
}
if (TYPE_NAME (type) != NULL_TREE
&& GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE
&& TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL)
{
tree gtype = DECL_ORIGINAL_TYPE (TYPE_NAME (type));
for (dim = 0; dim < sym->as->rank - 1; dim++)
{
gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE);
gtype = TREE_TYPE (gtype);
}
gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE);
if (TYPE_MAX_VALUE (TYPE_DOMAIN (gtype)) == NULL)
TYPE_NAME (type) = NULL_TREE;
}
if (TYPE_NAME (type) == NULL_TREE)
{
tree gtype = TREE_TYPE (type), rtype, type_decl;
for (dim = sym->as->rank - 1; dim >= 0; dim--)
{
tree lbound, ubound;
lbound = GFC_TYPE_ARRAY_LBOUND (type, dim);
ubound = GFC_TYPE_ARRAY_UBOUND (type, dim);
rtype = build_range_type (gfc_array_index_type, lbound, ubound);
gtype = build_array_type (gtype, rtype);
/* Ensure the bound variables aren't optimized out at -O0.
For -O1 and above they often will be optimized out, but
can be tracked by VTA. Also set DECL_NAMELESS, so that
the artificial lbound.N or ubound.N DECL_NAME doesn't
end up in debug info. */
if (lbound && TREE_CODE (lbound) == VAR_DECL
&& DECL_ARTIFICIAL (lbound) && DECL_IGNORED_P (lbound))
{
if (DECL_NAME (lbound)
&& strstr (IDENTIFIER_POINTER (DECL_NAME (lbound)),
"lbound") != 0)
DECL_NAMELESS (lbound) = 1;
DECL_IGNORED_P (lbound) = 0;
}
if (ubound && TREE_CODE (ubound) == VAR_DECL
&& DECL_ARTIFICIAL (ubound) && DECL_IGNORED_P (ubound))
{
if (DECL_NAME (ubound)
&& strstr (IDENTIFIER_POINTER (DECL_NAME (ubound)),
"ubound") != 0)
DECL_NAMELESS (ubound) = 1;
DECL_IGNORED_P (ubound) = 0;
}
}
TYPE_NAME (type) = type_decl = build_decl (input_location,
TYPE_DECL, NULL, gtype);
DECL_ORIGINAL_TYPE (type_decl) = gtype;
}
}
/* For some dummy arguments we don't use the actual argument directly.
Instead we create a local decl and use that. This allows us to perform
initialization, and construct full type information. */
static tree
gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy)
{
tree decl;
tree type;
gfc_array_spec *as;
char *name;
gfc_packed packed;
int n;
bool known_size;
if (sym->attr.pointer || sym->attr.allocatable
|| (sym->as && sym->as->type == AS_ASSUMED_RANK))
return dummy;
/* Add to list of variables if not a fake result variable. */
if (sym->attr.result || sym->attr.dummy)
gfc_defer_symbol_init (sym);
type = TREE_TYPE (dummy);
gcc_assert (TREE_CODE (dummy) == PARM_DECL
&& POINTER_TYPE_P (type));
/* Do we know the element size? */
known_size = sym->ts.type != BT_CHARACTER
|| INTEGER_CST_P (sym->ts.u.cl->backend_decl);
if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type)))
{
/* For descriptorless arrays with known element size the actual
argument is sufficient. */
gcc_assert (GFC_ARRAY_TYPE_P (type));
gfc_build_qualified_array (dummy, sym);
return dummy;
}
type = TREE_TYPE (type);
if (GFC_DESCRIPTOR_TYPE_P (type))
{
/* Create a descriptorless array pointer. */
as = sym->as;
packed = PACKED_NO;
/* Even when -frepack-arrays is used, symbols with TARGET attribute
are not repacked. */
if (!gfc_option.flag_repack_arrays || sym->attr.target)
{
if (as->type == AS_ASSUMED_SIZE)
packed = PACKED_FULL;
}
else
{
if (as->type == AS_EXPLICIT)
{
packed = PACKED_FULL;
for (n = 0; n < as->rank; n++)
{
if (!(as->upper[n]
&& as->lower[n]
&& as->upper[n]->expr_type == EXPR_CONSTANT
&& as->lower[n]->expr_type == EXPR_CONSTANT))
packed = PACKED_PARTIAL;
}
}
else
packed = PACKED_PARTIAL;
}
type = gfc_typenode_for_spec (&sym->ts);
type = gfc_get_nodesc_array_type (type, sym->as, packed,
!sym->attr.target);
}
else
{
/* We now have an expression for the element size, so create a fully
qualified type. Reset sym->backend decl or this will just return the
old type. */
DECL_ARTIFICIAL (sym->backend_decl) = 1;
sym->backend_decl = NULL_TREE;
type = gfc_sym_type (sym);
packed = PACKED_FULL;
}
ASM_FORMAT_PRIVATE_NAME (name, IDENTIFIER_POINTER (DECL_NAME (dummy)), 0);
decl = build_decl (input_location,
VAR_DECL, get_identifier (name), type);
DECL_ARTIFICIAL (decl) = 1;
DECL_NAMELESS (decl) = 1;
TREE_PUBLIC (decl) = 0;
TREE_STATIC (decl) = 0;
DECL_EXTERNAL (decl) = 0;
/* Avoid uninitialized warnings for optional dummy arguments. */
if (sym->attr.optional)
TREE_NO_WARNING (decl) = 1;
/* We should never get deferred shape arrays here. We used to because of
frontend bugs. */
gcc_assert (sym->as->type != AS_DEFERRED);
if (packed == PACKED_PARTIAL)
GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1;
else if (packed == PACKED_FULL)
GFC_DECL_PACKED_ARRAY (decl) = 1;
gfc_build_qualified_array (decl, sym);
if (DECL_LANG_SPECIFIC (dummy))
DECL_LANG_SPECIFIC (decl) = DECL_LANG_SPECIFIC (dummy);
else
gfc_allocate_lang_decl (decl);
GFC_DECL_SAVED_DESCRIPTOR (decl) = dummy;
if (sym->ns->proc_name->backend_decl == current_function_decl
|| sym->attr.contained)
gfc_add_decl_to_function (decl);
else
gfc_add_decl_to_parent_function (decl);
return decl;
}
/* For symbol SYM with GFC_DECL_SAVED_DESCRIPTOR used in contained
function add a VAR_DECL to the current function with DECL_VALUE_EXPR
pointing to the artificial variable for debug info purposes. */
static void
gfc_nonlocal_dummy_array_decl (gfc_symbol *sym)
{
tree decl, dummy;
if (! nonlocal_dummy_decl_pset)
nonlocal_dummy_decl_pset = pointer_set_create ();
if (pointer_set_insert (nonlocal_dummy_decl_pset, sym->backend_decl))
return;
dummy = GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl);
decl = build_decl (input_location, VAR_DECL, DECL_NAME (dummy),
TREE_TYPE (sym->backend_decl));
DECL_ARTIFICIAL (decl) = 0;
TREE_USED (decl) = 1;
TREE_PUBLIC (decl) = 0;
TREE_STATIC (decl) = 0;
DECL_EXTERNAL (decl) = 0;
if (DECL_BY_REFERENCE (dummy))
DECL_BY_REFERENCE (decl) = 1;
DECL_LANG_SPECIFIC (decl) = DECL_LANG_SPECIFIC (sym->backend_decl);
SET_DECL_VALUE_EXPR (decl, sym->backend_decl);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
DECL_CONTEXT (decl) = DECL_CONTEXT (sym->backend_decl);
DECL_CHAIN (decl) = nonlocal_dummy_decls;
nonlocal_dummy_decls = decl;
}
/* Return a constant or a variable to use as a string length. Does not
add the decl to the current scope. */
static tree
gfc_create_string_length (gfc_symbol * sym)
{
gcc_assert (sym->ts.u.cl);
gfc_conv_const_charlen (sym->ts.u.cl);
if (sym->ts.u.cl->backend_decl == NULL_TREE)
{
tree length;
const char *name;
/* The string length variable shall be in static memory if it is either
explicitly SAVED, a module variable or with -fno-automatic. Only
relevant is "len=:" - otherwise, it is either a constant length or
it is an automatic variable. */
bool static_length = sym->attr.save
|| sym->ns->proc_name->attr.flavor == FL_MODULE
|| (gfc_option.flag_max_stack_var_size == 0
&& sym->ts.deferred && !sym->attr.dummy
&& !sym->attr.result && !sym->attr.function);
/* Also prefix the mangled name. We need to call GFC_PREFIX for static
variables as some systems do not support the "." in the assembler name.
For nonstatic variables, the "." does not appear in assembler. */
if (static_length)
{
if (sym->module)
name = gfc_get_string (GFC_PREFIX ("%s_MOD_%s"), sym->module,
sym->name);
else
name = gfc_get_string (GFC_PREFIX ("%s"), sym->name);
}
else if (sym->module)
name = gfc_get_string (".__%s_MOD_%s", sym->module, sym->name);
else
name = gfc_get_string (".%s", sym->name);
length = build_decl (input_location,
VAR_DECL, get_identifier (name),
gfc_charlen_type_node);
DECL_ARTIFICIAL (length) = 1;
TREE_USED (length) = 1;
if (sym->ns->proc_name->tlink != NULL)
gfc_defer_symbol_init (sym);
sym->ts.u.cl->backend_decl = length;
if (static_length)
TREE_STATIC (length) = 1;
if (sym->ns->proc_name->attr.flavor == FL_MODULE
&& (sym->attr.access != ACCESS_PRIVATE || sym->attr.public_used))
TREE_PUBLIC (length) = 1;
}
gcc_assert (sym->ts.u.cl->backend_decl != NULL_TREE);
return sym->ts.u.cl->backend_decl;
}
/* If a variable is assigned a label, we add another two auxiliary
variables. */
static void
gfc_add_assign_aux_vars (gfc_symbol * sym)
{
tree addr;
tree length;
tree decl;
gcc_assert (sym->backend_decl);
decl = sym->backend_decl;
gfc_allocate_lang_decl (decl);
GFC_DECL_ASSIGN (decl) = 1;
length = build_decl (input_location,
VAR_DECL, create_tmp_var_name (sym->name),
gfc_charlen_type_node);
addr = build_decl (input_location,
VAR_DECL, create_tmp_var_name (sym->name),
pvoid_type_node);
gfc_finish_var_decl (length, sym);
gfc_finish_var_decl (addr, sym);
/* STRING_LENGTH is also used as flag. Less than -1 means that
ASSIGN_ADDR can not be used. Equal -1 means that ASSIGN_ADDR is the
target label's address. Otherwise, value is the length of a format string
and ASSIGN_ADDR is its address. */
if (TREE_STATIC (length))
DECL_INITIAL (length) = build_int_cst (gfc_charlen_type_node, -2);
else
gfc_defer_symbol_init (sym);
GFC_DECL_STRING_LEN (decl) = length;
GFC_DECL_ASSIGN_ADDR (decl) = addr;
}
static tree
add_attributes_to_decl (symbol_attribute sym_attr, tree list)
{
unsigned id;
tree attr;
for (id = 0; id < EXT_ATTR_NUM; id++)
if (sym_attr.ext_attr & (1 << id))
{
attr = build_tree_list (
get_identifier (ext_attr_list[id].middle_end_name),
NULL_TREE);
list = chainon (list, attr);
}
return list;
}
static void build_function_decl (gfc_symbol * sym, bool global);
/* Return the decl for a gfc_symbol, create it if it doesn't already
exist. */
tree
gfc_get_symbol_decl (gfc_symbol * sym)
{
tree decl;
tree length = NULL_TREE;
tree attributes;
int byref;
bool intrinsic_array_parameter = false;
bool fun_or_res;
gcc_assert (sym->attr.referenced
|| sym->attr.flavor == FL_PROCEDURE
|| sym->attr.use_assoc
|| sym->ns->proc_name->attr.if_source == IFSRC_IFBODY
|| (sym->module && sym->attr.if_source != IFSRC_DECL
&& sym->backend_decl));
if (sym->ns && sym->ns->proc_name && sym->ns->proc_name->attr.function)
byref = gfc_return_by_reference (sym->ns->proc_name);
else
byref = 0;
/* Make sure that the vtab for the declared type is completed. */
if (sym->ts.type == BT_CLASS)
{
gfc_component *c = CLASS_DATA (sym);
if (!c->ts.u.derived->backend_decl)
{
gfc_find_derived_vtab (c->ts.u.derived);
gfc_get_derived_type (sym->ts.u.derived);
}
}
/* All deferred character length procedures need to retain the backend
decl, which is a pointer to the character length in the caller's
namespace and to declare a local character length. */
if (!byref && sym->attr.function
&& sym->ts.type == BT_CHARACTER
&& sym->ts.deferred
&& sym->ts.u.cl->passed_length == NULL
&& sym->ts.u.cl->backend_decl
&& TREE_CODE (sym->ts.u.cl->backend_decl) == PARM_DECL)
{
sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl;
sym->ts.u.cl->backend_decl = NULL_TREE;
length = gfc_create_string_length (sym);
}
fun_or_res = byref && (sym->attr.result
|| (sym->attr.function && sym->ts.deferred));
if ((sym->attr.dummy && ! sym->attr.function) || fun_or_res)
{
/* Return via extra parameter. */
if (sym->attr.result && byref
&& !sym->backend_decl)
{
sym->backend_decl =
DECL_ARGUMENTS (sym->ns->proc_name->backend_decl);
/* For entry master function skip over the __entry
argument. */
if (sym->ns->proc_name->attr.entry_master)
sym->backend_decl = DECL_CHAIN (sym->backend_decl);
}
/* Dummy variables should already have been created. */
gcc_assert (sym->backend_decl);
/* Create a character length variable. */
if (sym->ts.type == BT_CHARACTER)
{
/* For a deferred dummy, make a new string length variable. */
if (sym->ts.deferred
&&
(sym->ts.u.cl->passed_length == sym->ts.u.cl->backend_decl))
sym->ts.u.cl->backend_decl = NULL_TREE;
if (sym->ts.deferred && fun_or_res
&& sym->ts.u.cl->passed_length == NULL
&& sym->ts.u.cl->backend_decl)
{
sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl;
sym->ts.u.cl->backend_decl = NULL_TREE;
}
if (sym->ts.u.cl->backend_decl == NULL_TREE)
length = gfc_create_string_length (sym);
else
length = sym->ts.u.cl->backend_decl;
if (TREE_CODE (length) == VAR_DECL
&& DECL_FILE_SCOPE_P (length))
{
/* Add the string length to the same context as the symbol. */
if (DECL_CONTEXT (sym->backend_decl) == current_function_decl)
gfc_add_decl_to_function (length);
else
gfc_add_decl_to_parent_function (length);
gcc_assert (DECL_CONTEXT (sym->backend_decl) ==
DECL_CONTEXT (length));
gfc_defer_symbol_init (sym);
}
}
/* Use a copy of the descriptor for dummy arrays. */
if ((sym->attr.dimension || sym->attr.codimension)
&& !TREE_USED (sym->backend_decl))
{
decl = gfc_build_dummy_array_decl (sym, sym->backend_decl);
/* Prevent the dummy from being detected as unused if it is copied. */
if (sym->backend_decl != NULL && decl != sym->backend_decl)
DECL_ARTIFICIAL (sym->backend_decl) = 1;
sym->backend_decl = decl;
}
TREE_USED (sym->backend_decl) = 1;
if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0)
{
gfc_add_assign_aux_vars (sym);
}
if (sym->attr.dimension
&& DECL_LANG_SPECIFIC (sym->backend_decl)
&& GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl)
&& DECL_CONTEXT (sym->backend_decl) != current_function_decl)
gfc_nonlocal_dummy_array_decl (sym);
if (sym->ts.type == BT_CLASS && sym->backend_decl)
GFC_DECL_CLASS(sym->backend_decl) = 1;
if (sym->ts.type == BT_CLASS && sym->backend_decl)
GFC_DECL_CLASS(sym->backend_decl) = 1;
return sym->backend_decl;
}
if (sym->backend_decl)
return sym->backend_decl;
/* Special case for array-valued named constants from intrinsic
procedures; those are inlined. */
if (sym->attr.use_assoc && sym->from_intmod
&& sym->attr.flavor == FL_PARAMETER)
intrinsic_array_parameter = true;
/* If use associated and whole file compilation, use the module
declaration. */
if (gfc_option.flag_whole_file
&& (sym->attr.flavor == FL_VARIABLE
|| sym->attr.flavor == FL_PARAMETER)
&& sym->attr.use_assoc
&& !intrinsic_array_parameter
&& sym->module
&& gfc_get_module_backend_decl (sym))
{
if (sym->ts.type == BT_CLASS && sym->backend_decl)
GFC_DECL_CLASS(sym->backend_decl) = 1;
return sym->backend_decl;
}
if (sym->attr.flavor == FL_PROCEDURE)
{
/* Catch functions. Only used for actual parameters,
procedure pointers and procptr initialization targets. */
if (sym->attr.external || sym->attr.use_assoc || sym->attr.intrinsic
|| sym->attr.if_source != IFSRC_DECL)
{
decl = gfc_get_extern_function_decl (sym);
gfc_set_decl_location (decl, &sym->declared_at);
}
else
{
if (!sym->backend_decl)
build_function_decl (sym, false);
decl = sym->backend_decl;
}
return decl;
}
if (sym->attr.intrinsic)
internal_error ("intrinsic variable which isn't a procedure");
/* Create string length decl first so that they can be used in the
type declaration. */
if (sym->ts.type == BT_CHARACTER)
length = gfc_create_string_length (sym);
/* Create the decl for the variable. */
decl = build_decl (sym->declared_at.lb->location,
VAR_DECL, gfc_sym_identifier (sym), gfc_sym_type (sym));
/* Add attributes to variables. Functions are handled elsewhere. */
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&decl, attributes, 0);
/* Symbols from modules should have their assembler names mangled.
This is done here rather than in gfc_finish_var_decl because it
is different for string length variables. */
if (sym->module)
{
gfc_set_decl_assembler_name (decl, gfc_sym_mangled_identifier (sym));
if (sym->attr.use_assoc && !intrinsic_array_parameter)
DECL_IGNORED_P (decl) = 1;
}
if (sym->attr.select_type_temporary)
{
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
}
if (sym->attr.dimension || sym->attr.codimension)
{
/* Create variables to hold the non-constant bits of array info. */
gfc_build_qualified_array (decl, sym);
if (sym->attr.contiguous
|| ((sym->attr.allocatable || !sym->attr.dummy) && !sym->attr.pointer))
GFC_DECL_PACKED_ARRAY (decl) = 1;
}
/* Remember this variable for allocation/cleanup. */
if (sym->attr.dimension || sym->attr.allocatable || sym->attr.codimension
|| (sym->ts.type == BT_CLASS &&
(CLASS_DATA (sym)->attr.dimension
|| CLASS_DATA (sym)->attr.allocatable))
|| (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.alloc_comp)
/* This applies a derived type default initializer. */
|| (sym->ts.type == BT_DERIVED
&& sym->attr.save == SAVE_NONE
&& !sym->attr.data
&& !sym->attr.allocatable
&& (sym->value && !sym->ns->proc_name->attr.is_main_program)
&& !(sym->attr.use_assoc && !intrinsic_array_parameter)))
gfc_defer_symbol_init (sym);
gfc_finish_var_decl (decl, sym);
if (sym->ts.type == BT_CHARACTER)
{
/* Character variables need special handling. */
gfc_allocate_lang_decl (decl);
if (TREE_CODE (length) != INTEGER_CST)
{
gfc_finish_var_decl (length, sym);
gcc_assert (!sym->value);
}
}
else if (sym->attr.subref_array_pointer)
{
/* We need the span for these beasts. */
gfc_allocate_lang_decl (decl);
}
if (sym->attr.subref_array_pointer)
{
tree span;
GFC_DECL_SUBREF_ARRAY_P (decl) = 1;
span = build_decl (input_location,
VAR_DECL, create_tmp_var_name ("span"),
gfc_array_index_type);
gfc_finish_var_decl (span, sym);
TREE_STATIC (span) = TREE_STATIC (decl);
DECL_ARTIFICIAL (span) = 1;
GFC_DECL_SPAN (decl) = span;
GFC_TYPE_ARRAY_SPAN (TREE_TYPE (decl)) = span;
}
if (sym->ts.type == BT_CLASS)
GFC_DECL_CLASS(decl) = 1;
sym->backend_decl = decl;
if (sym->attr.assign)
gfc_add_assign_aux_vars (sym);
if (intrinsic_array_parameter)
{
TREE_STATIC (decl) = 1;
DECL_EXTERNAL (decl) = 0;
}
if (TREE_STATIC (decl)
&& !(sym->attr.use_assoc && !intrinsic_array_parameter)
&& (sym->attr.save || sym->ns->proc_name->attr.is_main_program
|| gfc_option.flag_max_stack_var_size == 0
|| sym->attr.data || sym->ns->proc_name->attr.flavor == FL_MODULE)
&& (gfc_option.coarray != GFC_FCOARRAY_LIB
|| !sym->attr.codimension || sym->attr.allocatable))
{
/* Add static initializer. For procedures, it is only needed if
SAVE is specified otherwise they need to be reinitialized
every time the procedure is entered. The TREE_STATIC is
in this case due to -fmax-stack-var-size=. */
DECL_INITIAL (decl) = gfc_conv_initializer (sym->value, &sym->ts,
TREE_TYPE (decl),
sym->attr.dimension
|| (sym->attr.codimension
&& sym->attr.allocatable),
sym->attr.pointer
|| sym->attr.allocatable,
sym->attr.proc_pointer);
}
if (!TREE_STATIC (decl)
&& POINTER_TYPE_P (TREE_TYPE (decl))
&& !sym->attr.pointer
&& !sym->attr.allocatable
&& !sym->attr.proc_pointer
&& !sym->attr.select_type_temporary)
DECL_BY_REFERENCE (decl) = 1;
if (sym->attr.vtab
|| (sym->name[0] == '_' && strncmp ("__def_init", sym->name, 10) == 0))
TREE_READONLY (decl) = 1;
return decl;
}
/* Substitute a temporary variable in place of the real one. */
void
gfc_shadow_sym (gfc_symbol * sym, tree decl, gfc_saved_var * save)
{
save->attr = sym->attr;
save->decl = sym->backend_decl;
gfc_clear_attr (&sym->attr);
sym->attr.referenced = 1;
sym->attr.flavor = FL_VARIABLE;
sym->backend_decl = decl;
}
/* Restore the original variable. */
void
gfc_restore_sym (gfc_symbol * sym, gfc_saved_var * save)
{
sym->attr = save->attr;
sym->backend_decl = save->decl;
}
/* Declare a procedure pointer. */
static tree
get_proc_pointer_decl (gfc_symbol *sym)
{
tree decl;
tree attributes;
decl = sym->backend_decl;
if (decl)
return decl;
decl = build_decl (input_location,
VAR_DECL, get_identifier (sym->name),
build_pointer_type (gfc_get_function_type (sym)));
if (sym->module)
{
/* Apply name mangling. */
gfc_set_decl_assembler_name (decl, gfc_sym_mangled_identifier (sym));
if (sym->attr.use_assoc)
DECL_IGNORED_P (decl) = 1;
}
if ((sym->ns->proc_name
&& sym->ns->proc_name->backend_decl == current_function_decl)
|| sym->attr.contained)
gfc_add_decl_to_function (decl);
else if (sym->ns->proc_name->attr.flavor != FL_MODULE)
gfc_add_decl_to_parent_function (decl);
sym->backend_decl = decl;
/* If a variable is USE associated, it's always external. */
if (sym->attr.use_assoc)
{
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
}
else if (sym->module && sym->ns->proc_name->attr.flavor == FL_MODULE)
{
/* This is the declaration of a module variable. */
TREE_PUBLIC (decl) = 1;
TREE_STATIC (decl) = 1;
}
if (!sym->attr.use_assoc
&& (sym->attr.save != SAVE_NONE || sym->attr.data
|| (sym->value && sym->ns->proc_name->attr.is_main_program)))
TREE_STATIC (decl) = 1;
if (TREE_STATIC (decl) && sym->value)
{
/* Add static initializer. */
DECL_INITIAL (decl) = gfc_conv_initializer (sym->value, &sym->ts,
TREE_TYPE (decl),
sym->attr.dimension,
false, true);
}
/* Handle threadprivate procedure pointers. */
if (sym->attr.threadprivate
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&decl, attributes, 0);
return decl;
}
/* Get a basic decl for an external function. */
tree
gfc_get_extern_function_decl (gfc_symbol * sym)
{
tree type;
tree fndecl;
tree attributes;
gfc_expr e;
gfc_intrinsic_sym *isym;
gfc_expr argexpr;
char s[GFC_MAX_SYMBOL_LEN + 23]; /* "_gfortran_f2c_specific" and '\0'. */
tree name;
tree mangled_name;
gfc_gsymbol *gsym;
if (sym->backend_decl)
return sym->backend_decl;
/* We should never be creating external decls for alternate entry points.
The procedure may be an alternate entry point, but we don't want/need
to know that. */
gcc_assert (!(sym->attr.entry || sym->attr.entry_master));
if (sym->attr.proc_pointer)
return get_proc_pointer_decl (sym);
/* See if this is an external procedure from the same file. If so,
return the backend_decl. */
gsym = gfc_find_gsymbol (gfc_gsym_root, sym->name);
if (gfc_option.flag_whole_file
&& (!sym->attr.use_assoc || sym->attr.if_source != IFSRC_DECL)
&& !sym->backend_decl
&& gsym && gsym->ns
&& ((gsym->type == GSYM_SUBROUTINE) || (gsym->type == GSYM_FUNCTION))
&& (gsym->ns->proc_name->backend_decl || !sym->attr.intrinsic))
{
if (!gsym->ns->proc_name->backend_decl)
{
/* By construction, the external function cannot be
a contained procedure. */
locus old_loc;
gfc_save_backend_locus (&old_loc);
push_cfun (NULL);
gfc_create_function_decl (gsym->ns, true);
pop_cfun ();
gfc_restore_backend_locus (&old_loc);
}
/* If the namespace has entries, the proc_name is the
entry master. Find the entry and use its backend_decl.
otherwise, use the proc_name backend_decl. */
if (gsym->ns->entries)
{
gfc_entry_list *entry = gsym->ns->entries;
for (; entry; entry = entry->next)
{
if (strcmp (gsym->name, entry->sym->name) == 0)
{
sym->backend_decl = entry->sym->backend_decl;
break;
}
}
}
else
sym->backend_decl = gsym->ns->proc_name->backend_decl;
if (sym->backend_decl)
{
/* Avoid problems of double deallocation of the backend declaration
later in gfc_trans_use_stmts; cf. PR 45087. */
if (sym->attr.if_source != IFSRC_DECL && sym->attr.use_assoc)
sym->attr.use_assoc = 0;
return sym->backend_decl;
}
}
/* See if this is a module procedure from the same file. If so,
return the backend_decl. */
if (sym->module)
gsym = gfc_find_gsymbol (gfc_gsym_root, sym->module);
if (gfc_option.flag_whole_file
&& gsym && gsym->ns
&& gsym->type == GSYM_MODULE)
{
gfc_symbol *s;
s = NULL;
gfc_find_symbol (sym->name, gsym->ns, 0, &s);
if (s && s->backend_decl)
{
if (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS)
gfc_copy_dt_decls_ifequal (s->ts.u.derived, sym->ts.u.derived,
true);
else if (sym->ts.type == BT_CHARACTER)
sym->ts.u.cl->backend_decl = s->ts.u.cl->backend_decl;
sym->backend_decl = s->backend_decl;
return sym->backend_decl;
}
}
if (sym->attr.intrinsic)
{
/* Call the resolution function to get the actual name. This is
a nasty hack which relies on the resolution functions only looking
at the first argument. We pass NULL for the second argument
otherwise things like AINT get confused. */
isym = gfc_find_function (sym->name);
gcc_assert (isym->resolve.f0 != NULL);
memset (&e, 0, sizeof (e));
e.expr_type = EXPR_FUNCTION;
memset (&argexpr, 0, sizeof (argexpr));
gcc_assert (isym->formal);
argexpr.ts = isym->formal->ts;
if (isym->formal->next == NULL)
isym->resolve.f1 (&e, &argexpr);
else
{
if (isym->formal->next->next == NULL)
isym->resolve.f2 (&e, &argexpr, NULL);
else
{
if (isym->formal->next->next->next == NULL)
isym->resolve.f3 (&e, &argexpr, NULL, NULL);
else
{
/* All specific intrinsics take less than 5 arguments. */
gcc_assert (isym->formal->next->next->next->next == NULL);
isym->resolve.f4 (&e, &argexpr, NULL, NULL, NULL);
}
}
}
if (gfc_option.flag_f2c
&& ((e.ts.type == BT_REAL && e.ts.kind == gfc_default_real_kind)
|| e.ts.type == BT_COMPLEX))
{
/* Specific which needs a different implementation if f2c
calling conventions are used. */
sprintf (s, "_gfortran_f2c_specific%s", e.value.function.name);
}
else
sprintf (s, "_gfortran_specific%s", e.value.function.name);
name = get_identifier (s);
mangled_name = name;
}
else
{
name = gfc_sym_identifier (sym);
mangled_name = gfc_sym_mangled_function_id (sym);
}
type = gfc_get_function_type (sym);
fndecl = build_decl (input_location,
FUNCTION_DECL, name, type);
/* Initialize DECL_EXTERNAL and TREE_PUBLIC before calling decl_attributes;
TREE_PUBLIC specifies whether a function is globally addressable (i.e.
the opposite of declaring a function as static in C). */
DECL_EXTERNAL (fndecl) = 1;
TREE_PUBLIC (fndecl) = 1;
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&fndecl, attributes, 0);
gfc_set_decl_assembler_name (fndecl, mangled_name);
/* Set the context of this decl. */
if (0 && sym->ns && sym->ns->proc_name)
{
/* TODO: Add external decls to the appropriate scope. */
DECL_CONTEXT (fndecl) = sym->ns->proc_name->backend_decl;
}
else
{
/* Global declaration, e.g. intrinsic subroutine. */
DECL_CONTEXT (fndecl) = NULL_TREE;
}
/* Set attributes for PURE functions. A call to PURE function in the
Fortran 95 sense is both pure and without side effects in the C
sense. */
if (sym->attr.pure || sym->attr.implicit_pure)
{
if (sym->attr.function && !gfc_return_by_reference (sym))
DECL_PURE_P (fndecl) = 1;
/* TODO: check if pure SUBROUTINEs don't have INTENT(OUT)
parameters and don't use alternate returns (is this
allowed?). In that case, calls to them are meaningless, and
can be optimized away. See also in build_function_decl(). */
TREE_SIDE_EFFECTS (fndecl) = 0;
}
/* Mark non-returning functions. */
if (sym->attr.noreturn)
TREE_THIS_VOLATILE(fndecl) = 1;
sym->backend_decl = fndecl;
if (DECL_CONTEXT (fndecl) == NULL_TREE)
pushdecl_top_level (fndecl);
return fndecl;
}
/* Create a declaration for a procedure. For external functions (in the C
sense) use gfc_get_extern_function_decl. HAS_ENTRIES is true if this is
a master function with alternate entry points. */
static void
build_function_decl (gfc_symbol * sym, bool global)
{
tree fndecl, type, attributes;
symbol_attribute attr;
tree result_decl;
gfc_formal_arglist *f;
gcc_assert (!sym->attr.external);
if (sym->backend_decl)
return;
/* Set the line and filename. sym->declared_at seems to point to the
last statement for subroutines, but it'll do for now. */
gfc_set_backend_locus (&sym->declared_at);
/* Allow only one nesting level. Allow public declarations. */
gcc_assert (current_function_decl == NULL_TREE
|| DECL_FILE_SCOPE_P (current_function_decl)
|| (TREE_CODE (DECL_CONTEXT (current_function_decl))
== NAMESPACE_DECL));
type = gfc_get_function_type (sym);
fndecl = build_decl (input_location,
FUNCTION_DECL, gfc_sym_identifier (sym), type);
attr = sym->attr;
/* Initialize DECL_EXTERNAL and TREE_PUBLIC before calling decl_attributes;
TREE_PUBLIC specifies whether a function is globally addressable (i.e.
the opposite of declaring a function as static in C). */
DECL_EXTERNAL (fndecl) = 0;
if (sym->attr.access == ACCESS_UNKNOWN && sym->module
&& (sym->ns->default_access == ACCESS_PRIVATE
|| (sym->ns->default_access == ACCESS_UNKNOWN
&& gfc_option.flag_module_private)))
sym->attr.access = ACCESS_PRIVATE;
if (!current_function_decl
&& !sym->attr.entry_master && !sym->attr.is_main_program
&& (sym->attr.access != ACCESS_PRIVATE || sym->binding_label
|| sym->attr.public_used))
TREE_PUBLIC (fndecl) = 1;
if (sym->attr.referenced || sym->attr.entry_master)
TREE_USED (fndecl) = 1;
attributes = add_attributes_to_decl (attr, NULL_TREE);
decl_attributes (&fndecl, attributes, 0);
/* Figure out the return type of the declared function, and build a
RESULT_DECL for it. If this is a subroutine with alternate
returns, build a RESULT_DECL for it. */
result_decl = NULL_TREE;
/* TODO: Shouldn't this just be TREE_TYPE (TREE_TYPE (fndecl)). */
if (attr.function)
{
if (gfc_return_by_reference (sym))
type = void_type_node;
else
{
if (sym->result != sym)
result_decl = gfc_sym_identifier (sym->result);
type = TREE_TYPE (TREE_TYPE (fndecl));
}
}
else
{
/* Look for alternate return placeholders. */
int has_alternate_returns = 0;
for (f = gfc_sym_get_dummy_args (sym); f; f = f->next)
{
if (f->sym == NULL)
{
has_alternate_returns = 1;
break;
}
}
if (has_alternate_returns)
type = integer_type_node;
else
type = void_type_node;
}
result_decl = build_decl (input_location,
RESULT_DECL, result_decl, type);
DECL_ARTIFICIAL (result_decl) = 1;
DECL_IGNORED_P (result_decl) = 1;
DECL_CONTEXT (result_decl) = fndecl;
DECL_RESULT (fndecl) = result_decl;
/* Don't call layout_decl for a RESULT_DECL.
layout_decl (result_decl, 0); */
/* TREE_STATIC means the function body is defined here. */
TREE_STATIC (fndecl) = 1;
/* Set attributes for PURE functions. A call to a PURE function in the
Fortran 95 sense is both pure and without side effects in the C
sense. */
if (attr.pure || attr.implicit_pure)
{
/* TODO: check if a pure SUBROUTINE has no INTENT(OUT) arguments
including an alternate return. In that case it can also be
marked as PURE. See also in gfc_get_extern_function_decl(). */
if (attr.function && !gfc_return_by_reference (sym))
DECL_PURE_P (fndecl) = 1;
TREE_SIDE_EFFECTS (fndecl) = 0;
}
/* Layout the function declaration and put it in the binding level
of the current function. */
if (global)
pushdecl_top_level (fndecl);
else
pushdecl (fndecl);
/* Perform name mangling if this is a top level or module procedure. */
if (current_function_decl == NULL_TREE)
gfc_set_decl_assembler_name (fndecl, gfc_sym_mangled_function_id (sym));
sym->backend_decl = fndecl;
}
/* Create the DECL_ARGUMENTS for a procedure. */
static void
create_function_arglist (gfc_symbol * sym)
{
tree fndecl;
gfc_formal_arglist *f;
tree typelist, hidden_typelist;
tree arglist, hidden_arglist;
tree type;
tree parm;
fndecl = sym->backend_decl;
/* Build formal argument list. Make sure that their TREE_CONTEXT is
the new FUNCTION_DECL node. */
arglist = NULL_TREE;
hidden_arglist = NULL_TREE;
typelist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (sym->attr.entry_master)
{
type = TREE_VALUE (typelist);
parm = build_decl (input_location,
PARM_DECL, get_identifier ("__entry"), type);
DECL_CONTEXT (parm) = fndecl;
DECL_ARG_TYPE (parm) = type;
TREE_READONLY (parm) = 1;
gfc_finish_decl (parm);
DECL_ARTIFICIAL (parm) = 1;
arglist = chainon (arglist, parm);
typelist = TREE_CHAIN (typelist);
}
if (gfc_return_by_reference (sym))
{
tree type = TREE_VALUE (typelist), length = NULL;
if (sym->ts.type == BT_CHARACTER)
{
/* Length of character result. */
tree len_type = TREE_VALUE (TREE_CHAIN (typelist));
length = build_decl (input_location,
PARM_DECL,
get_identifier (".__result"),
len_type);
if (!sym->ts.u.cl->length)
{
sym->ts.u.cl->backend_decl = length;
TREE_USED (length) = 1;
}
gcc_assert (TREE_CODE (length) == PARM_DECL);
DECL_CONTEXT (length) = fndecl;
DECL_ARG_TYPE (length) = len_type;
TREE_READONLY (length) = 1;
DECL_ARTIFICIAL (length) = 1;
gfc_finish_decl (length);
if (sym->ts.u.cl->backend_decl == NULL
|| sym->ts.u.cl->backend_decl == length)
{
gfc_symbol *arg;
tree backend_decl;
if (sym->ts.u.cl->backend_decl == NULL)
{
tree len = build_decl (input_location,
VAR_DECL,
get_identifier ("..__result"),
gfc_charlen_type_node);
DECL_ARTIFICIAL (len) = 1;
TREE_USED (len) = 1;
sym->ts.u.cl->backend_decl = len;
}
/* Make sure PARM_DECL type doesn't point to incomplete type. */
arg = sym->result ? sym->result : sym;
backend_decl = arg->backend_decl;
/* Temporary clear it, so that gfc_sym_type creates complete
type. */
arg->backend_decl = NULL;
type = gfc_sym_type (arg);
arg->backend_decl = backend_decl;
type = build_reference_type (type);
}
}
parm = build_decl (input_location,
PARM_DECL, get_identifier ("__result"), type);
DECL_CONTEXT (parm) = fndecl;
DECL_ARG_TYPE (parm) = TREE_VALUE (typelist);
TREE_READONLY (parm) = 1;
DECL_ARTIFICIAL (parm) = 1;
gfc_finish_decl (parm);
arglist = chainon (arglist, parm);
typelist = TREE_CHAIN (typelist);
if (sym->ts.type == BT_CHARACTER)
{
gfc_allocate_lang_decl (parm);
arglist = chainon (arglist, length);
typelist = TREE_CHAIN (typelist);
}
}
hidden_typelist = typelist;
for (f = gfc_sym_get_dummy_args (sym); f; f = f->next)
if (f->sym != NULL) /* Ignore alternate returns. */
hidden_typelist = TREE_CHAIN (hidden_typelist);
for (f = gfc_sym_get_dummy_args (sym); f; f = f->next)
{
char name[GFC_MAX_SYMBOL_LEN + 2];
/* Ignore alternate returns. */
if (f->sym == NULL)
continue;
type = TREE_VALUE (typelist);
if (f->sym->ts.type == BT_CHARACTER
&& (!sym->attr.is_bind_c || sym->attr.entry_master))
{
tree len_type = TREE_VALUE (hidden_typelist);
tree length = NULL_TREE;
if (!f->sym->ts.deferred)
gcc_assert (len_type == gfc_charlen_type_node);
else
gcc_assert (POINTER_TYPE_P (len_type));
strcpy (&name[1], f->sym->name);
name[0] = '_';
length = build_decl (input_location,
PARM_DECL, get_identifier (name), len_type);
hidden_arglist = chainon (hidden_arglist, length);
DECL_CONTEXT (length) = fndecl;
DECL_ARTIFICIAL (length) = 1;
DECL_ARG_TYPE (length) = len_type;
TREE_READONLY (length) = 1;
gfc_finish_decl (length);
/* Remember the passed value. */
if (!f->sym->ts.u.cl || f->sym->ts.u.cl->passed_length)
{
/* This can happen if the same type is used for multiple
arguments. We need to copy cl as otherwise
cl->passed_length gets overwritten. */
f->sym->ts.u.cl = gfc_new_charlen (f->sym->ns, f->sym->ts.u.cl);
}
f->sym->ts.u.cl->passed_length = length;
/* Use the passed value for assumed length variables. */
if (!f->sym->ts.u.cl->length)
{
TREE_USED (length) = 1;
gcc_assert (!f->sym->ts.u.cl->backend_decl);
f->sym->ts.u.cl->backend_decl = length;
}
hidden_typelist = TREE_CHAIN (hidden_typelist);
if (f->sym->ts.u.cl->backend_decl == NULL
|| f->sym->ts.u.cl->backend_decl == length)
{
if (f->sym->ts.u.cl->backend_decl == NULL)
gfc_create_string_length (f->sym);
/* Make sure PARM_DECL type doesn't point to incomplete type. */
if (f->sym->attr.flavor == FL_PROCEDURE)
type = build_pointer_type (gfc_get_function_type (f->sym));
else
type = gfc_sym_type (f->sym);
}
}
/* For non-constant length array arguments, make sure they use
a different type node from TYPE_ARG_TYPES type. */
if (f->sym->attr.dimension
&& type == TREE_VALUE (typelist)
&& TREE_CODE (type) == POINTER_TYPE
&& GFC_ARRAY_TYPE_P (type)
&& f->sym->as->type != AS_ASSUMED_SIZE
&& ! COMPLETE_TYPE_P (TREE_TYPE (type)))
{
if (f->sym->attr.flavor == FL_PROCEDURE)
type = build_pointer_type (gfc_get_function_type (f->sym));
else
type = gfc_sym_type (f->sym);
}
if (f->sym->attr.proc_pointer)
type = build_pointer_type (type);
if (f->sym->attr.volatile_)
type = build_qualified_type (type, TYPE_QUAL_VOLATILE);
/* Build the argument declaration. */
parm = build_decl (input_location,
PARM_DECL, gfc_sym_identifier (f->sym), type);
if (f->sym->attr.volatile_)
{
TREE_THIS_VOLATILE (parm) = 1;
TREE_SIDE_EFFECTS (parm) = 1;
}
/* Fill in arg stuff. */
DECL_CONTEXT (parm) = fndecl;
DECL_ARG_TYPE (parm) = TREE_VALUE (typelist);
/* All implementation args except for VALUE are read-only. */
if (!f->sym->attr.value)
TREE_READONLY (parm) = 1;
if (POINTER_TYPE_P (type)
&& (!f->sym->attr.proc_pointer
&& f->sym->attr.flavor != FL_PROCEDURE))
DECL_BY_REFERENCE (parm) = 1;
gfc_finish_decl (parm);
f->sym->backend_decl = parm;
/* Coarrays which are descriptorless or assumed-shape pass with
-fcoarray=lib the token and the offset as hidden arguments. */
if (f->sym->attr.codimension
&& gfc_option.coarray == GFC_FCOARRAY_LIB
&& !f->sym->attr.allocatable)
{
tree caf_type;
tree token;
tree offset;
gcc_assert (f->sym->backend_decl != NULL_TREE
&& !sym->attr.is_bind_c);
caf_type = TREE_TYPE (f->sym->backend_decl);
token = build_decl (input_location, PARM_DECL,
create_tmp_var_name ("caf_token"),
build_qualified_type (pvoid_type_node,
TYPE_QUAL_RESTRICT));
if (f->sym->as->type == AS_ASSUMED_SHAPE)
{
gcc_assert (DECL_LANG_SPECIFIC (f->sym->backend_decl) == NULL
|| GFC_DECL_TOKEN (f->sym->backend_decl) == NULL_TREE);
if (DECL_LANG_SPECIFIC (f->sym->backend_decl) == NULL)
gfc_allocate_lang_decl (f->sym->backend_decl);
GFC_DECL_TOKEN (f->sym->backend_decl) = token;
}
else
{
gcc_assert (GFC_TYPE_ARRAY_CAF_TOKEN (caf_type) == NULL_TREE);
GFC_TYPE_ARRAY_CAF_TOKEN (caf_type) = token;
}
DECL_CONTEXT (token) = fndecl;
DECL_ARTIFICIAL (token) = 1;
DECL_ARG_TYPE (token) = TREE_VALUE (typelist);
TREE_READONLY (token) = 1;
hidden_arglist = chainon (hidden_arglist, token);
gfc_finish_decl (token);
offset = build_decl (input_location, PARM_DECL,
create_tmp_var_name ("caf_offset"),
gfc_array_index_type);
if (f->sym->as->type == AS_ASSUMED_SHAPE)
{
gcc_assert (GFC_DECL_CAF_OFFSET (f->sym->backend_decl)
== NULL_TREE);
GFC_DECL_CAF_OFFSET (f->sym->backend_decl) = offset;
}
else
{
gcc_assert (GFC_TYPE_ARRAY_CAF_OFFSET (caf_type) == NULL_TREE);
GFC_TYPE_ARRAY_CAF_OFFSET (caf_type) = offset;
}
DECL_CONTEXT (offset) = fndecl;
DECL_ARTIFICIAL (offset) = 1;
DECL_ARG_TYPE (offset) = TREE_VALUE (typelist);
TREE_READONLY (offset) = 1;
hidden_arglist = chainon (hidden_arglist, offset);
gfc_finish_decl (offset);
}
arglist = chainon (arglist, parm);
typelist = TREE_CHAIN (typelist);
}
/* Add the hidden string length parameters, unless the procedure
is bind(C). */
if (!sym->attr.is_bind_c)
arglist = chainon (arglist, hidden_arglist);
gcc_assert (hidden_typelist == NULL_TREE
|| TREE_VALUE (hidden_typelist) == void_type_node);
DECL_ARGUMENTS (fndecl) = arglist;
}
/* Do the setup necessary before generating the body of a function. */
static void
trans_function_start (gfc_symbol * sym)
{
tree fndecl;
fndecl = sym->backend_decl;
/* Let GCC know the current scope is this function. */
current_function_decl = fndecl;
/* Let the world know what we're about to do. */
announce_function (fndecl);
if (DECL_FILE_SCOPE_P (fndecl))
{
/* Create RTL for function declaration. */
rest_of_decl_compilation (fndecl, 1, 0);
}
/* Create RTL for function definition. */
make_decl_rtl (fndecl);
allocate_struct_function (fndecl, false);
/* function.c requires a push at the start of the function. */
pushlevel ();
}
/* Create thunks for alternate entry points. */
static void
build_entry_thunks (gfc_namespace * ns, bool global)
{
gfc_formal_arglist *formal;
gfc_formal_arglist *thunk_formal;
gfc_entry_list *el;
gfc_symbol *thunk_sym;
stmtblock_t body;
tree thunk_fndecl;
tree tmp;
locus old_loc;
/* This should always be a toplevel function. */
gcc_assert (current_function_decl == NULL_TREE);
gfc_save_backend_locus (&old_loc);
for (el = ns->entries; el; el = el->next)
{
vec<tree, va_gc> *args = NULL;
vec<tree, va_gc> *string_args = NULL;
thunk_sym = el->sym;
build_function_decl (thunk_sym, global);
create_function_arglist (thunk_sym);
trans_function_start (thunk_sym);
thunk_fndecl = thunk_sym->backend_decl;
gfc_init_block (&body);
/* Pass extra parameter identifying this entry point. */
tmp = build_int_cst (gfc_array_index_type, el->id);
vec_safe_push (args, tmp);
if (thunk_sym->attr.function)
{
if (gfc_return_by_reference (ns->proc_name))
{
tree ref = DECL_ARGUMENTS (current_function_decl);
vec_safe_push (args, ref);
if (ns->proc_name->ts.type == BT_CHARACTER)
vec_safe_push (args, DECL_CHAIN (ref));
}
}
for (formal = gfc_sym_get_dummy_args (ns->proc_name); formal;
formal = formal->next)
{
/* Ignore alternate returns. */
if (formal->sym == NULL)
continue;
/* We don't have a clever way of identifying arguments, so resort to
a brute-force search. */
for (thunk_formal = gfc_sym_get_dummy_args (thunk_sym);
thunk_formal;
thunk_formal = thunk_formal->next)
{
if (thunk_formal->sym == formal->sym)
break;
}
if (thunk_formal)
{
/* Pass the argument. */
DECL_ARTIFICIAL (thunk_formal->sym->backend_decl) = 1;
vec_safe_push (args, thunk_formal->sym->backend_decl);
if (formal->sym->ts.type == BT_CHARACTER)
{
tmp = thunk_formal->sym->ts.u.cl->backend_decl;
vec_safe_push (string_args, tmp);
}
}
else
{
/* Pass NULL for a missing argument. */
vec_safe_push (args, null_pointer_node);
if (formal->sym->ts.type == BT_CHARACTER)
{
tmp = build_int_cst (gfc_charlen_type_node, 0);
vec_safe_push (string_args, tmp);
}
}
}
/* Call the master function. */
vec_safe_splice (args, string_args);
tmp = ns->proc_name->backend_decl;
tmp = build_call_expr_loc_vec (input_location, tmp, args);
if (ns->proc_name->attr.mixed_entry_master)
{
tree union_decl, field;
tree master_type = TREE_TYPE (ns->proc_name->backend_decl);
union_decl = build_decl (input_location,
VAR_DECL, get_identifier ("__result"),
TREE_TYPE (master_type));
DECL_ARTIFICIAL (union_decl) = 1;
DECL_EXTERNAL (union_decl) = 0;
TREE_PUBLIC (union_decl) = 0;
TREE_USED (union_decl) = 1;
layout_decl (union_decl, 0);
pushdecl (union_decl);
DECL_CONTEXT (union_decl) = current_function_decl;
tmp = fold_build2_loc (input_location, MODIFY_EXPR,
TREE_TYPE (union_decl), union_decl, tmp);
gfc_add_expr_to_block (&body, tmp);
for (field = TYPE_FIELDS (TREE_TYPE (union_decl));
field; field = DECL_CHAIN (field))
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)),
thunk_sym->result->name) == 0)
break;
gcc_assert (field != NULL_TREE);
tmp = fold_build3_loc (input_location, COMPONENT_REF,
TREE_TYPE (field), union_decl, field,
NULL_TREE);
tmp = fold_build2_loc (input_location, MODIFY_EXPR,
TREE_TYPE (DECL_RESULT (current_function_decl)),
DECL_RESULT (current_function_decl), tmp);
tmp = build1_v (RETURN_EXPR, tmp);
}
else if (TREE_TYPE (DECL_RESULT (current_function_decl))
!= void_type_node)
{
tmp = fold_build2_loc (input_location, MODIFY_EXPR,
TREE_TYPE (DECL_RESULT (current_function_decl)),
DECL_RESULT (current_function_decl), tmp);
tmp = build1_v (RETURN_EXPR, tmp);
}
gfc_add_expr_to_block (&body, tmp);
/* Finish off this function and send it for code generation. */
DECL_SAVED_TREE (thunk_fndecl) = gfc_finish_block (&body);
tmp = getdecls ();
poplevel (1, 1);
BLOCK_SUPERCONTEXT (DECL_INITIAL (thunk_fndecl)) = thunk_fndecl;
DECL_SAVED_TREE (thunk_fndecl)
= build3_v (BIND_EXPR, tmp, DECL_SAVED_TREE (thunk_fndecl),
DECL_INITIAL (thunk_fndecl));
/* Output the GENERIC tree. */
dump_function (TDI_original, thunk_fndecl);
/* Store the end of the function, so that we get good line number
info for the epilogue. */
cfun->function_end_locus = input_location;
/* We're leaving the context of this function, so zap cfun.
It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
tree_rest_of_compilation. */
set_cfun (NULL);
current_function_decl = NULL_TREE;
cgraph_finalize_function (thunk_fndecl, true);
/* We share the symbols in the formal argument list with other entry
points and the master function. Clear them so that they are
recreated for each function. */
for (formal = gfc_sym_get_dummy_args (thunk_sym); formal;
formal = formal->next)
if (formal->sym != NULL) /* Ignore alternate returns. */
{
formal->sym->backend_decl = NULL_TREE;
if (formal->sym->ts.type == BT_CHARACTER)
formal->sym->ts.u.cl->backend_decl = NULL_TREE;
}
if (thunk_sym->attr.function)
{
if (thunk_sym->ts.type == BT_CHARACTER)
thunk_sym->ts.u.cl->backend_decl = NULL_TREE;
if (thunk_sym->result->ts.type == BT_CHARACTER)
thunk_sym->result->ts.u.cl->backend_decl = NULL_TREE;
}
}
gfc_restore_backend_locus (&old_loc);
}
/* Create a decl for a function, and create any thunks for alternate entry
points. If global is true, generate the function in the global binding
level, otherwise in the current binding level (which can be global). */
void
gfc_create_function_decl (gfc_namespace * ns, bool global)
{
/* Create a declaration for the master function. */
build_function_decl (ns->proc_name, global);
/* Compile the entry thunks. */
if (ns->entries)
build_entry_thunks (ns, global);
/* Now create the read argument list. */
create_function_arglist (ns->proc_name);
}
/* Return the decl used to hold the function return value. If
parent_flag is set, the context is the parent_scope. */
tree
gfc_get_fake_result_decl (gfc_symbol * sym, int parent_flag)
{
tree decl;
tree length;
tree this_fake_result_decl;
tree this_function_decl;
char name[GFC_MAX_SYMBOL_LEN + 10];
if (parent_flag)
{
this_fake_result_decl = parent_fake_result_decl;
this_function_decl = DECL_CONTEXT (current_function_decl);
}
else
{
this_fake_result_decl = current_fake_result_decl;
this_function_decl = current_function_decl;
}
if (sym
&& sym->ns->proc_name->backend_decl == this_function_decl
&& sym->ns->proc_name->attr.entry_master
&& sym != sym->ns->proc_name)
{
tree t = NULL, var;
if (this_fake_result_decl != NULL)
for (t = TREE_CHAIN (this_fake_result_decl); t; t = TREE_CHAIN (t))
if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t)), sym->name) == 0)
break;
if (t)
return TREE_VALUE (t);
decl = gfc_get_fake_result_decl (sym->ns->proc_name, parent_flag);
if (parent_flag)
this_fake_result_decl = parent_fake_result_decl;
else
this_fake_result_decl = current_fake_result_decl;
if (decl && sym->ns->proc_name->attr.mixed_entry_master)
{
tree field;
for (field = TYPE_FIELDS (TREE_TYPE (decl));
field; field = DECL_CHAIN (field))
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)),
sym->name) == 0)
break;
gcc_assert (field != NULL_TREE);
decl = fold_build3_loc (input_location, COMPONENT_REF,
TREE_TYPE (field), decl, field, NULL_TREE);
}
var = create_tmp_var_raw (TREE_TYPE (decl), sym->name);
if (parent_flag)
gfc_add_decl_to_parent_function (var);
else
gfc_add_decl_to_function (var);
SET_DECL_VALUE_EXPR (var, decl);
DECL_HAS_VALUE_EXPR_P (var) = 1;
GFC_DECL_RESULT (var) = 1;
TREE_CHAIN (this_fake_result_decl)
= tree_cons (get_identifier (sym->name), var,
TREE_CHAIN (this_fake_result_decl));
return var;
}
if (this_fake_result_decl != NULL_TREE)
return TREE_VALUE (this_fake_result_decl);
/* Only when gfc_get_fake_result_decl is called by gfc_trans_return,
sym is NULL. */
if (!sym)
return NULL_TREE;
if (sym->ts.type == BT_CHARACTER)
{
if (sym->ts.u.cl->backend_decl == NULL_TREE)
length = gfc_create_string_length (sym);
else
length = sym->ts.u.cl->backend_decl;
if (TREE_CODE (length) == VAR_DECL
&& DECL_CONTEXT (length) == NULL_TREE)
gfc_add_decl_to_function (length);
}
if (gfc_return_by_reference (sym))
{
decl = DECL_ARGUMENTS (this_function_decl);
if (sym->ns->proc_name->backend_decl == this_function_decl
&& sym->ns->proc_name->attr.entry_master)
decl = DECL_CHAIN (decl);
TREE_USED (decl) = 1;
if (sym->as)
decl = gfc_build_dummy_array_decl (sym, decl);
}
else
{
sprintf (name, "__result_%.20s",
IDENTIFIER_POINTER (DECL_NAME (this_function_decl)));
if (!sym->attr.mixed_entry_master && sym->attr.function)
decl = build_decl (DECL_SOURCE_LOCATION (this_function_decl),
VAR_DECL, get_identifier (name),
gfc_sym_type (sym));
else
decl = build_decl (DECL_SOURCE_LOCATION (this_function_decl),
VAR_DECL, get_identifier (name),
TREE_TYPE (TREE_TYPE (this_function_decl)));
DECL_ARTIFICIAL (decl) = 1;
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
TREE_USED (decl) = 1;
GFC_DECL_RESULT (decl) = 1;
TREE_ADDRESSABLE (decl) = 1;
layout_decl (decl, 0);
if (parent_flag)
gfc_add_decl_to_parent_function (decl);
else
gfc_add_decl_to_function (decl);
}
if (parent_flag)
parent_fake_result_decl = build_tree_list (NULL, decl);
else
current_fake_result_decl = build_tree_list (NULL, decl);
return decl;
}
/* Builds a function decl. The remaining parameters are the types of the
function arguments. Negative nargs indicates a varargs function. */
static tree
build_library_function_decl_1 (tree name, const char *spec,
tree rettype, int nargs, va_list p)
{
vec<tree, va_gc> *arglist;
tree fntype;
tree fndecl;
int n;
/* Library functions must be declared with global scope. */
gcc_assert (current_function_decl == NULL_TREE);
/* Create a list of the argument types. */
vec_alloc (arglist, abs (nargs));
for (n = abs (nargs); n > 0; n--)
{
tree argtype = va_arg (p, tree);
arglist->quick_push (argtype);
}
/* Build the function type and decl. */
if (nargs >= 0)
fntype = build_function_type_vec (rettype, arglist);
else
fntype = build_varargs_function_type_vec (rettype, arglist);
if (spec)
{
tree attr_args = build_tree_list (NULL_TREE,
build_string (strlen (spec), spec));
tree attrs = tree_cons (get_identifier ("fn spec"),
attr_args, TYPE_ATTRIBUTES (fntype));
fntype = build_type_attribute_variant (fntype, attrs);
}
fndecl = build_decl (input_location,
FUNCTION_DECL, name, fntype);
/* Mark this decl as external. */
DECL_EXTERNAL (fndecl) = 1;
TREE_PUBLIC (fndecl) = 1;
pushdecl (fndecl);
rest_of_decl_compilation (fndecl, 1, 0);
return fndecl;
}
/* Builds a function decl. The remaining parameters are the types of the
function arguments. Negative nargs indicates a varargs function. */
tree
gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...)
{
tree ret;
va_list args;
va_start (args, nargs);
ret = build_library_function_decl_1 (name, NULL, rettype, nargs, args);
va_end (args);
return ret;
}
/* Builds a function decl. The remaining parameters are the types of the
function arguments. Negative nargs indicates a varargs function.
The SPEC parameter specifies the function argument and return type
specification according to the fnspec function type attribute. */
tree
gfc_build_library_function_decl_with_spec (tree name, const char *spec,
tree rettype, int nargs, ...)
{
tree ret;
va_list args;
va_start (args, nargs);
ret = build_library_function_decl_1 (name, spec, rettype, nargs, args);
va_end (args);
return ret;
}
static void
gfc_build_intrinsic_function_decls (void)
{
tree gfc_int4_type_node = gfc_get_int_type (4);
tree gfc_int8_type_node = gfc_get_int_type (8);
tree gfc_int16_type_node = gfc_get_int_type (16);
tree gfc_logical4_type_node = gfc_get_logical_type (4);
tree pchar1_type_node = gfc_get_pchar_type (1);
tree pchar4_type_node = gfc_get_pchar_type (4);
/* String functions. */
gfor_fndecl_compare_string = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("compare_string")), "..R.R",
integer_type_node, 4, gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node);
DECL_PURE_P (gfor_fndecl_compare_string) = 1;
TREE_NOTHROW (gfor_fndecl_compare_string) = 1;
gfor_fndecl_concat_string = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("concat_string")), "..W.R.R",
void_type_node, 6, gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node);
TREE_NOTHROW (gfor_fndecl_concat_string) = 1;
gfor_fndecl_string_len_trim = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_len_trim")), "..R",
gfc_charlen_type_node, 2, gfc_charlen_type_node, pchar1_type_node);
DECL_PURE_P (gfor_fndecl_string_len_trim) = 1;
TREE_NOTHROW (gfor_fndecl_string_len_trim) = 1;
gfor_fndecl_string_index = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_index")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_index) = 1;
TREE_NOTHROW (gfor_fndecl_string_index) = 1;
gfor_fndecl_string_scan = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_scan")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_scan) = 1;
TREE_NOTHROW (gfor_fndecl_string_scan) = 1;
gfor_fndecl_string_verify = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_verify")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar1_type_node,
gfc_charlen_type_node, pchar1_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_verify) = 1;
TREE_NOTHROW (gfor_fndecl_string_verify) = 1;
gfor_fndecl_string_trim = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_trim")), ".Ww.R",
void_type_node, 4, build_pointer_type (gfc_charlen_type_node),
build_pointer_type (pchar1_type_node), gfc_charlen_type_node,
pchar1_type_node);
gfor_fndecl_string_minmax = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_minmax")), ".Ww.R",
void_type_node, -4, build_pointer_type (gfc_charlen_type_node),
build_pointer_type (pchar1_type_node), integer_type_node,
integer_type_node);
gfor_fndecl_adjustl = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("adjustl")), ".W.R",
void_type_node, 3, pchar1_type_node, gfc_charlen_type_node,
pchar1_type_node);
TREE_NOTHROW (gfor_fndecl_adjustl) = 1;
gfor_fndecl_adjustr = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("adjustr")), ".W.R",
void_type_node, 3, pchar1_type_node, gfc_charlen_type_node,
pchar1_type_node);
TREE_NOTHROW (gfor_fndecl_adjustr) = 1;
gfor_fndecl_select_string = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("select_string")), ".R.R.",
integer_type_node, 4, pvoid_type_node, integer_type_node,
pchar1_type_node, gfc_charlen_type_node);
DECL_PURE_P (gfor_fndecl_select_string) = 1;
TREE_NOTHROW (gfor_fndecl_select_string) = 1;
gfor_fndecl_compare_string_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("compare_string_char4")), "..R.R",
integer_type_node, 4, gfc_charlen_type_node, pchar4_type_node,
gfc_charlen_type_node, pchar4_type_node);
DECL_PURE_P (gfor_fndecl_compare_string_char4) = 1;
TREE_NOTHROW (gfor_fndecl_compare_string_char4) = 1;
gfor_fndecl_concat_string_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("concat_string_char4")), "..W.R.R",
void_type_node, 6, gfc_charlen_type_node, pchar4_type_node,
gfc_charlen_type_node, pchar4_type_node, gfc_charlen_type_node,
pchar4_type_node);
TREE_NOTHROW (gfor_fndecl_concat_string_char4) = 1;
gfor_fndecl_string_len_trim_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_len_trim_char4")), "..R",
gfc_charlen_type_node, 2, gfc_charlen_type_node, pchar4_type_node);
DECL_PURE_P (gfor_fndecl_string_len_trim_char4) = 1;
TREE_NOTHROW (gfor_fndecl_string_len_trim_char4) = 1;
gfor_fndecl_string_index_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_index_char4")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar4_type_node,
gfc_charlen_type_node, pchar4_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_index_char4) = 1;
TREE_NOTHROW (gfor_fndecl_string_index_char4) = 1;
gfor_fndecl_string_scan_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_scan_char4")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar4_type_node,
gfc_charlen_type_node, pchar4_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_scan_char4) = 1;
TREE_NOTHROW (gfor_fndecl_string_scan_char4) = 1;
gfor_fndecl_string_verify_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_verify_char4")), "..R.R.",
gfc_charlen_type_node, 5, gfc_charlen_type_node, pchar4_type_node,
gfc_charlen_type_node, pchar4_type_node, gfc_logical4_type_node);
DECL_PURE_P (gfor_fndecl_string_verify_char4) = 1;
TREE_NOTHROW (gfor_fndecl_string_verify_char4) = 1;
gfor_fndecl_string_trim_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_trim_char4")), ".Ww.R",
void_type_node, 4, build_pointer_type (gfc_charlen_type_node),
build_pointer_type (pchar4_type_node), gfc_charlen_type_node,
pchar4_type_node);
gfor_fndecl_string_minmax_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("string_minmax_char4")), ".Ww.R",
void_type_node, -4, build_pointer_type (gfc_charlen_type_node),
build_pointer_type (pchar4_type_node), integer_type_node,
integer_type_node);
gfor_fndecl_adjustl_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("adjustl_char4")), ".W.R",
void_type_node, 3, pchar4_type_node, gfc_charlen_type_node,
pchar4_type_node);
TREE_NOTHROW (gfor_fndecl_adjustl_char4) = 1;
gfor_fndecl_adjustr_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("adjustr_char4")), ".W.R",
void_type_node, 3, pchar4_type_node, gfc_charlen_type_node,
pchar4_type_node);
TREE_NOTHROW (gfor_fndecl_adjustr_char4) = 1;
gfor_fndecl_select_string_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("select_string_char4")), ".R.R.",
integer_type_node, 4, pvoid_type_node, integer_type_node,
pvoid_type_node, gfc_charlen_type_node);
DECL_PURE_P (gfor_fndecl_select_string_char4) = 1;
TREE_NOTHROW (gfor_fndecl_select_string_char4) = 1;
/* Conversion between character kinds. */
gfor_fndecl_convert_char1_to_char4 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("convert_char1_to_char4")), ".w.R",
void_type_node, 3, build_pointer_type (pchar4_type_node),
gfc_charlen_type_node, pchar1_type_node);
gfor_fndecl_convert_char4_to_char1 = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("convert_char4_to_char1")), ".w.R",
void_type_node, 3, build_pointer_type (pchar1_type_node),
gfc_charlen_type_node, pchar4_type_node);
/* Misc. functions. */
gfor_fndecl_ttynam = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("ttynam")), ".W",
void_type_node, 3, pchar_type_node, gfc_charlen_type_node,
integer_type_node);
gfor_fndecl_fdate = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("fdate")), ".W",
void_type_node, 2, pchar_type_node, gfc_charlen_type_node);
gfor_fndecl_ctime = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("ctime")), ".W",
void_type_node, 3, pchar_type_node, gfc_charlen_type_node,
gfc_int8_type_node);
gfor_fndecl_sc_kind = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("selected_char_kind")), "..R",
gfc_int4_type_node, 2, gfc_charlen_type_node, pchar_type_node);
DECL_PURE_P (gfor_fndecl_sc_kind) = 1;
TREE_NOTHROW (gfor_fndecl_sc_kind) = 1;
gfor_fndecl_si_kind = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("selected_int_kind")), ".R",
gfc_int4_type_node, 1, pvoid_type_node);
DECL_PURE_P (gfor_fndecl_si_kind) = 1;
TREE_NOTHROW (gfor_fndecl_si_kind) = 1;
gfor_fndecl_sr_kind = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("selected_real_kind2008")), ".RR",
gfc_int4_type_node, 3, pvoid_type_node, pvoid_type_node,
pvoid_type_node);
DECL_PURE_P (gfor_fndecl_sr_kind) = 1;
TREE_NOTHROW (gfor_fndecl_sr_kind) = 1;
/* Power functions. */
{
tree ctype, rtype, itype, jtype;
int rkind, ikind, jkind;
#define NIKINDS 3
#define NRKINDS 4
static int ikinds[NIKINDS] = {4, 8, 16};
static int rkinds[NRKINDS] = {4, 8, 10, 16};
char name[PREFIX_LEN + 12]; /* _gfortran_pow_?n_?n */
for (ikind=0; ikind < NIKINDS; ikind++)
{
itype = gfc_get_int_type (ikinds[ikind]);
for (jkind=0; jkind < NIKINDS; jkind++)
{
jtype = gfc_get_int_type (ikinds[jkind]);
if (itype && jtype)
{
sprintf(name, PREFIX("pow_i%d_i%d"), ikinds[ikind],
ikinds[jkind]);
gfor_fndecl_math_powi[jkind][ikind].integer =
gfc_build_library_function_decl (get_identifier (name),
jtype, 2, jtype, itype);
TREE_READONLY (gfor_fndecl_math_powi[jkind][ikind].integer) = 1;
TREE_NOTHROW (gfor_fndecl_math_powi[jkind][ikind].integer) = 1;
}
}
for (rkind = 0; rkind < NRKINDS; rkind ++)
{
rtype = gfc_get_real_type (rkinds[rkind]);
if (rtype && itype)
{
sprintf(name, PREFIX("pow_r%d_i%d"), rkinds[rkind],
ikinds[ikind]);
gfor_fndecl_math_powi[rkind][ikind].real =
gfc_build_library_function_decl (get_identifier (name),
rtype, 2, rtype, itype);
TREE_READONLY (gfor_fndecl_math_powi[rkind][ikind].real) = 1;
TREE_NOTHROW (gfor_fndecl_math_powi[rkind][ikind].real) = 1;
}
ctype = gfc_get_complex_type (rkinds[rkind]);
if (ctype && itype)
{
sprintf(name, PREFIX("pow_c%d_i%d"), rkinds[rkind],
ikinds[ikind]);
gfor_fndecl_math_powi[rkind][ikind].cmplx =
gfc_build_library_function_decl (get_identifier (name),
ctype, 2,ctype, itype);
TREE_READONLY (gfor_fndecl_math_powi[rkind][ikind].cmplx) = 1;
TREE_NOTHROW (gfor_fndecl_math_powi[rkind][ikind].cmplx) = 1;
}
}
}
#undef NIKINDS
#undef NRKINDS
}
gfor_fndecl_math_ishftc4 = gfc_build_library_function_decl (
get_identifier (PREFIX("ishftc4")),
gfc_int4_type_node, 3, gfc_int4_type_node, gfc_int4_type_node,
gfc_int4_type_node);
TREE_READONLY (gfor_fndecl_math_ishftc4) = 1;
TREE_NOTHROW (gfor_fndecl_math_ishftc4) = 1;
gfor_fndecl_math_ishftc8 = gfc_build_library_function_decl (
get_identifier (PREFIX("ishftc8")),
gfc_int8_type_node, 3, gfc_int8_type_node, gfc_int4_type_node,
gfc_int4_type_node);
TREE_READONLY (gfor_fndecl_math_ishftc8) = 1;
TREE_NOTHROW (gfor_fndecl_math_ishftc8) = 1;
if (gfc_int16_type_node)
{
gfor_fndecl_math_ishftc16 = gfc_build_library_function_decl (
get_identifier (PREFIX("ishftc16")),
gfc_int16_type_node, 3, gfc_int16_type_node, gfc_int4_type_node,
gfc_int4_type_node);
TREE_READONLY (gfor_fndecl_math_ishftc16) = 1;
TREE_NOTHROW (gfor_fndecl_math_ishftc16) = 1;
}
/* BLAS functions. */
{
tree pint = build_pointer_type (integer_type_node);
tree ps = build_pointer_type (gfc_get_real_type (gfc_default_real_kind));
tree pd = build_pointer_type (gfc_get_real_type (gfc_default_double_kind));
tree pc = build_pointer_type (gfc_get_complex_type (gfc_default_real_kind));
tree pz = build_pointer_type
(gfc_get_complex_type (gfc_default_double_kind));
gfor_fndecl_sgemm = gfc_build_library_function_decl
(get_identifier
(gfc_option.flag_underscoring ? "sgemm_"
: "sgemm"),
void_type_node, 15, pchar_type_node,
pchar_type_node, pint, pint, pint, ps, ps, pint,
ps, pint, ps, ps, p