diff options
Diffstat (limited to 'gcc-4.8.1/gcc/fortran/trans-io.c')
-rw-r--r-- | gcc-4.8.1/gcc/fortran/trans-io.c | 2338 |
1 files changed, 0 insertions, 2338 deletions
diff --git a/gcc-4.8.1/gcc/fortran/trans-io.c b/gcc-4.8.1/gcc/fortran/trans-io.c deleted file mode 100644 index 9394810f0..000000000 --- a/gcc-4.8.1/gcc/fortran/trans-io.c +++ /dev/null @@ -1,2338 +0,0 @@ -/* IO Code translation/library interface - 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/>. */ - - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tree.h" -#include "ggc.h" -#include "diagnostic-core.h" /* For internal_error. */ -#include "gfortran.h" -#include "trans.h" -#include "trans-stmt.h" -#include "trans-array.h" -#include "trans-types.h" -#include "trans-const.h" - -/* Members of the ioparm structure. */ - -enum ioparam_type -{ - IOPARM_ptype_common, - IOPARM_ptype_open, - IOPARM_ptype_close, - IOPARM_ptype_filepos, - IOPARM_ptype_inquire, - IOPARM_ptype_dt, - IOPARM_ptype_wait, - IOPARM_ptype_num -}; - -enum iofield_type -{ - IOPARM_type_int4, - IOPARM_type_intio, - IOPARM_type_pint4, - IOPARM_type_pintio, - IOPARM_type_pchar, - IOPARM_type_parray, - IOPARM_type_pad, - IOPARM_type_char1, - IOPARM_type_char2, - IOPARM_type_common, - IOPARM_type_num -}; - -typedef struct GTY(()) gfc_st_parameter_field { - const char *name; - unsigned int mask; - enum ioparam_type param_type; - enum iofield_type type; - tree field; - tree field_len; -} -gfc_st_parameter_field; - -typedef struct GTY(()) gfc_st_parameter { - const char *name; - tree type; -} -gfc_st_parameter; - -enum iofield -{ -#define IOPARM(param_type, name, mask, type) IOPARM_##param_type##_##name, -#include "ioparm.def" -#undef IOPARM - IOPARM_field_num -}; - -static GTY(()) gfc_st_parameter st_parameter[] = -{ - { "common", NULL }, - { "open", NULL }, - { "close", NULL }, - { "filepos", NULL }, - { "inquire", NULL }, - { "dt", NULL }, - { "wait", NULL } -}; - -static GTY(()) gfc_st_parameter_field st_parameter_field[] = -{ -#define IOPARM(param_type, name, mask, type) \ - { #name, mask, IOPARM_ptype_##param_type, IOPARM_type_##type, NULL, NULL }, -#include "ioparm.def" -#undef IOPARM - { NULL, 0, (enum ioparam_type) 0, (enum iofield_type) 0, NULL, NULL } -}; - -/* Library I/O subroutines */ - -enum iocall -{ - IOCALL_READ, - IOCALL_READ_DONE, - IOCALL_WRITE, - IOCALL_WRITE_DONE, - IOCALL_X_INTEGER, - IOCALL_X_INTEGER_WRITE, - IOCALL_X_LOGICAL, - IOCALL_X_LOGICAL_WRITE, - IOCALL_X_CHARACTER, - IOCALL_X_CHARACTER_WRITE, - IOCALL_X_CHARACTER_WIDE, - IOCALL_X_CHARACTER_WIDE_WRITE, - IOCALL_X_REAL, - IOCALL_X_REAL_WRITE, - IOCALL_X_COMPLEX, - IOCALL_X_COMPLEX_WRITE, - IOCALL_X_REAL128, - IOCALL_X_REAL128_WRITE, - IOCALL_X_COMPLEX128, - IOCALL_X_COMPLEX128_WRITE, - IOCALL_X_ARRAY, - IOCALL_X_ARRAY_WRITE, - IOCALL_OPEN, - IOCALL_CLOSE, - IOCALL_INQUIRE, - IOCALL_IOLENGTH, - IOCALL_IOLENGTH_DONE, - IOCALL_REWIND, - IOCALL_BACKSPACE, - IOCALL_ENDFILE, - IOCALL_FLUSH, - IOCALL_SET_NML_VAL, - IOCALL_SET_NML_VAL_DIM, - IOCALL_WAIT, - IOCALL_NUM -}; - -static GTY(()) tree iocall[IOCALL_NUM]; - -/* Variable for keeping track of what the last data transfer statement - was. Used for deciding which subroutine to call when the data - transfer is complete. */ -static enum { READ, WRITE, IOLENGTH } last_dt; - -/* The data transfer parameter block that should be shared by all - data transfer calls belonging to the same read/write/iolength. */ -static GTY(()) tree dt_parm; -static stmtblock_t *dt_post_end_block; - -static void -gfc_build_st_parameter (enum ioparam_type ptype, tree *types) -{ - unsigned int type; - gfc_st_parameter_field *p; - char name[64]; - size_t len; - tree t = make_node (RECORD_TYPE); - tree *chain = NULL; - - len = strlen (st_parameter[ptype].name); - gcc_assert (len <= sizeof (name) - sizeof ("__st_parameter_")); - memcpy (name, "__st_parameter_", sizeof ("__st_parameter_")); - memcpy (name + sizeof ("__st_parameter_") - 1, st_parameter[ptype].name, - len + 1); - TYPE_NAME (t) = get_identifier (name); - - for (type = 0, p = st_parameter_field; type < IOPARM_field_num; type++, p++) - if (p->param_type == ptype) - switch (p->type) - { - case IOPARM_type_int4: - case IOPARM_type_intio: - case IOPARM_type_pint4: - case IOPARM_type_pintio: - case IOPARM_type_parray: - case IOPARM_type_pchar: - case IOPARM_type_pad: - p->field = gfc_add_field_to_struct (t, get_identifier (p->name), - types[p->type], &chain); - break; - case IOPARM_type_char1: - p->field = gfc_add_field_to_struct (t, get_identifier (p->name), - pchar_type_node, &chain); - /* FALLTHROUGH */ - case IOPARM_type_char2: - len = strlen (p->name); - gcc_assert (len <= sizeof (name) - sizeof ("_len")); - memcpy (name, p->name, len); - memcpy (name + len, "_len", sizeof ("_len")); - p->field_len = gfc_add_field_to_struct (t, get_identifier (name), - gfc_charlen_type_node, - &chain); - if (p->type == IOPARM_type_char2) - p->field = gfc_add_field_to_struct (t, get_identifier (p->name), - pchar_type_node, &chain); - break; - case IOPARM_type_common: - p->field - = gfc_add_field_to_struct (t, - get_identifier (p->name), - st_parameter[IOPARM_ptype_common].type, - &chain); - break; - case IOPARM_type_num: - gcc_unreachable (); - } - - gfc_finish_type (t); - st_parameter[ptype].type = t; -} - - -/* Build code to test an error condition and call generate_error if needed. - Note: This builds calls to generate_error in the runtime library function. - The function generate_error is dependent on certain parameters in the - st_parameter_common flags to be set. (See libgfortran/runtime/error.c) - Therefore, the code to set these flags must be generated before - this function is used. */ - -void -gfc_trans_io_runtime_check (tree cond, tree var, int error_code, - const char * msgid, stmtblock_t * pblock) -{ - stmtblock_t block; - tree body; - tree tmp; - tree arg1, arg2, arg3; - char *message; - - if (integer_zerop (cond)) - return; - - /* The code to generate the error. */ - gfc_start_block (&block); - - arg1 = gfc_build_addr_expr (NULL_TREE, var); - - arg2 = build_int_cst (integer_type_node, error_code), - - asprintf (&message, "%s", _(msgid)); - arg3 = gfc_build_addr_expr (pchar_type_node, - gfc_build_localized_cstring_const (message)); - free (message); - - tmp = build_call_expr_loc (input_location, - gfor_fndecl_generate_error, 3, arg1, arg2, arg3); - - gfc_add_expr_to_block (&block, tmp); - - body = gfc_finish_block (&block); - - if (integer_onep (cond)) - { - gfc_add_expr_to_block (pblock, body); - } - else - { - cond = gfc_unlikely (cond); - tmp = build3_v (COND_EXPR, cond, body, build_empty_stmt (input_location)); - gfc_add_expr_to_block (pblock, tmp); - } -} - - -/* Create function decls for IO library functions. */ - -void -gfc_build_io_library_fndecls (void) -{ - tree types[IOPARM_type_num], pad_idx, gfc_int4_type_node; - tree gfc_intio_type_node; - tree parm_type, dt_parm_type; - HOST_WIDE_INT pad_size; - unsigned int ptype; - - types[IOPARM_type_int4] = gfc_int4_type_node = gfc_get_int_type (4); - types[IOPARM_type_intio] = gfc_intio_type_node - = gfc_get_int_type (gfc_intio_kind); - types[IOPARM_type_pint4] = build_pointer_type (gfc_int4_type_node); - types[IOPARM_type_pintio] - = build_pointer_type (gfc_intio_type_node); - types[IOPARM_type_parray] = pchar_type_node; - types[IOPARM_type_pchar] = pchar_type_node; - pad_size = 16 * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (pchar_type_node)); - pad_size += 32 * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (integer_type_node)); - pad_idx = build_index_type (size_int (pad_size - 1)); - types[IOPARM_type_pad] = build_array_type (char_type_node, pad_idx); - - /* pad actually contains pointers and integers so it needs to have an - alignment that is at least as large as the needed alignment for those - types. See the st_parameter_dt structure in libgfortran/io/io.h for - what really goes into this space. */ - TYPE_ALIGN (types[IOPARM_type_pad]) = MAX (TYPE_ALIGN (pchar_type_node), - TYPE_ALIGN (gfc_get_int_type (gfc_intio_kind))); - - for (ptype = IOPARM_ptype_common; ptype < IOPARM_ptype_num; ptype++) - gfc_build_st_parameter ((enum ioparam_type) ptype, types); - - /* Define the transfer functions. */ - - dt_parm_type = build_pointer_type (st_parameter[IOPARM_ptype_dt].type); - - iocall[IOCALL_X_INTEGER] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_integer")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_INTEGER_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_integer_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_LOGICAL] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_logical")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_LOGICAL_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_logical_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_CHARACTER] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_character")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_CHARACTER_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_character_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_CHARACTER_WIDE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_character_wide")), ".wW", - void_type_node, 4, dt_parm_type, pvoid_type_node, - gfc_charlen_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_CHARACTER_WIDE_WRITE] = - gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_character_wide_write")), ".wR", - void_type_node, 4, dt_parm_type, pvoid_type_node, - gfc_charlen_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_REAL] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_real")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_REAL_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_real_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_COMPLEX] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_complex")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_COMPLEX_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_complex_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - /* Version for __float128. */ - iocall[IOCALL_X_REAL128] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_real128")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_REAL128_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_real128_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_COMPLEX128] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_complex128")), ".wW", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_COMPLEX128_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_complex128_write")), ".wR", - void_type_node, 3, dt_parm_type, pvoid_type_node, gfc_int4_type_node); - - iocall[IOCALL_X_ARRAY] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_array")), ".ww", - void_type_node, 4, dt_parm_type, pvoid_type_node, - integer_type_node, gfc_charlen_type_node); - - iocall[IOCALL_X_ARRAY_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("transfer_array_write")), ".wr", - void_type_node, 4, dt_parm_type, pvoid_type_node, - integer_type_node, gfc_charlen_type_node); - - /* Library entry points */ - - iocall[IOCALL_READ] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_read")), ".w", - void_type_node, 1, dt_parm_type); - - iocall[IOCALL_WRITE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_write")), ".w", - void_type_node, 1, dt_parm_type); - - parm_type = build_pointer_type (st_parameter[IOPARM_ptype_open].type); - iocall[IOCALL_OPEN] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_open")), ".w", - void_type_node, 1, parm_type); - - parm_type = build_pointer_type (st_parameter[IOPARM_ptype_close].type); - iocall[IOCALL_CLOSE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_close")), ".w", - void_type_node, 1, parm_type); - - parm_type = build_pointer_type (st_parameter[IOPARM_ptype_inquire].type); - iocall[IOCALL_INQUIRE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_inquire")), ".w", - void_type_node, 1, parm_type); - - iocall[IOCALL_IOLENGTH] = gfc_build_library_function_decl_with_spec( - get_identifier (PREFIX("st_iolength")), ".w", - void_type_node, 1, dt_parm_type); - - /* TODO: Change when asynchronous I/O is implemented. */ - parm_type = build_pointer_type (st_parameter[IOPARM_ptype_wait].type); - iocall[IOCALL_WAIT] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_wait")), ".X", - void_type_node, 1, parm_type); - - parm_type = build_pointer_type (st_parameter[IOPARM_ptype_filepos].type); - iocall[IOCALL_REWIND] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_rewind")), ".w", - void_type_node, 1, parm_type); - - iocall[IOCALL_BACKSPACE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_backspace")), ".w", - void_type_node, 1, parm_type); - - iocall[IOCALL_ENDFILE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_endfile")), ".w", - void_type_node, 1, parm_type); - - iocall[IOCALL_FLUSH] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_flush")), ".w", - void_type_node, 1, parm_type); - - /* Library helpers */ - - iocall[IOCALL_READ_DONE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_read_done")), ".w", - void_type_node, 1, dt_parm_type); - - iocall[IOCALL_WRITE_DONE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_write_done")), ".w", - void_type_node, 1, dt_parm_type); - - iocall[IOCALL_IOLENGTH_DONE] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_iolength_done")), ".w", - void_type_node, 1, dt_parm_type); - - iocall[IOCALL_SET_NML_VAL] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_set_nml_var")), ".w.R", - void_type_node, 6, dt_parm_type, pvoid_type_node, pvoid_type_node, - void_type_node, gfc_charlen_type_node, gfc_int4_type_node); - - iocall[IOCALL_SET_NML_VAL_DIM] = gfc_build_library_function_decl_with_spec ( - get_identifier (PREFIX("st_set_nml_var_dim")), ".w", - void_type_node, 5, dt_parm_type, gfc_int4_type_node, - gfc_array_index_type, gfc_array_index_type, gfc_array_index_type); -} - - -/* Generate code to store an integer constant into the - st_parameter_XXX structure. */ - -static unsigned int -set_parameter_const (stmtblock_t *block, tree var, enum iofield type, - unsigned int val) -{ - tree tmp; - gfc_st_parameter_field *p = &st_parameter_field[type]; - - if (p->param_type == IOPARM_ptype_common) - var = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - gfc_add_modify (block, tmp, build_int_cst (TREE_TYPE (p->field), val)); - return p->mask; -} - - -/* Generate code to store a non-string I/O parameter into the - st_parameter_XXX structure. This is a pass by value. */ - -static unsigned int -set_parameter_value (stmtblock_t *block, tree var, enum iofield type, - gfc_expr *e) -{ - gfc_se se; - tree tmp; - gfc_st_parameter_field *p = &st_parameter_field[type]; - tree dest_type = TREE_TYPE (p->field); - - gfc_init_se (&se, NULL); - gfc_conv_expr_val (&se, e); - - /* If we're storing a UNIT number, we need to check it first. */ - if (type == IOPARM_common_unit && e->ts.kind > 4) - { - tree cond, val; - int i; - - /* Don't evaluate the UNIT number multiple times. */ - se.expr = gfc_evaluate_now (se.expr, &se.pre); - - /* UNIT numbers should be greater than the min. */ - i = gfc_validate_kind (BT_INTEGER, 4, false); - val = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].pedantic_min_int, 4); - cond = fold_build2_loc (input_location, LT_EXPR, boolean_type_node, - se.expr, - fold_convert (TREE_TYPE (se.expr), val)); - gfc_trans_io_runtime_check (cond, var, LIBERROR_BAD_UNIT, - "Unit number in I/O statement too small", - &se.pre); - - /* UNIT numbers should be less than the max. */ - val = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, 4); - cond = fold_build2_loc (input_location, GT_EXPR, boolean_type_node, - se.expr, - fold_convert (TREE_TYPE (se.expr), val)); - gfc_trans_io_runtime_check (cond, var, LIBERROR_BAD_UNIT, - "Unit number in I/O statement too large", - &se.pre); - - } - - se.expr = convert (dest_type, se.expr); - gfc_add_block_to_block (block, &se.pre); - - if (p->param_type == IOPARM_ptype_common) - var = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - - tmp = fold_build3_loc (input_location, COMPONENT_REF, dest_type, var, - p->field, NULL_TREE); - gfc_add_modify (block, tmp, se.expr); - return p->mask; -} - - -/* Generate code to store a non-string I/O parameter into the - st_parameter_XXX structure. This is pass by reference. */ - -static unsigned int -set_parameter_ref (stmtblock_t *block, stmtblock_t *postblock, - tree var, enum iofield type, gfc_expr *e) -{ - gfc_se se; - tree tmp, addr; - gfc_st_parameter_field *p = &st_parameter_field[type]; - - gcc_assert (e->ts.type == BT_INTEGER || e->ts.type == BT_LOGICAL); - gfc_init_se (&se, NULL); - gfc_conv_expr_lhs (&se, e); - - gfc_add_block_to_block (block, &se.pre); - - if (TYPE_MODE (TREE_TYPE (se.expr)) - == TYPE_MODE (TREE_TYPE (TREE_TYPE (p->field)))) - { - addr = convert (TREE_TYPE (p->field), gfc_build_addr_expr (NULL_TREE, se.expr)); - - /* If this is for the iostat variable initialize the - user variable to LIBERROR_OK which is zero. */ - if (type == IOPARM_common_iostat) - gfc_add_modify (block, se.expr, - build_int_cst (TREE_TYPE (se.expr), LIBERROR_OK)); - } - else - { - /* The type used by the library has different size - from the type of the variable supplied by the user. - Need to use a temporary. */ - tree tmpvar = gfc_create_var (TREE_TYPE (TREE_TYPE (p->field)), - st_parameter_field[type].name); - - /* If this is for the iostat variable, initialize the - user variable to LIBERROR_OK which is zero. */ - if (type == IOPARM_common_iostat) - gfc_add_modify (block, tmpvar, - build_int_cst (TREE_TYPE (tmpvar), LIBERROR_OK)); - - addr = gfc_build_addr_expr (NULL_TREE, tmpvar); - /* After the I/O operation, we set the variable from the temporary. */ - tmp = convert (TREE_TYPE (se.expr), tmpvar); - gfc_add_modify (postblock, se.expr, tmp); - } - - if (p->param_type == IOPARM_ptype_common) - var = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - gfc_add_modify (block, tmp, addr); - return p->mask; -} - -/* Given an array expr, find its address and length to get a string. If the - array is full, the string's address is the address of array's first element - and the length is the size of the whole array. If it is an element, the - string's address is the element's address and the length is the rest size of - the array. */ - -static void -gfc_convert_array_to_string (gfc_se * se, gfc_expr * e) -{ - tree size; - - if (e->rank == 0) - { - tree type, array, tmp; - gfc_symbol *sym; - int rank; - - /* If it is an element, we need its address and size of the rest. */ - gcc_assert (e->expr_type == EXPR_VARIABLE); - gcc_assert (e->ref->u.ar.type == AR_ELEMENT); - sym = e->symtree->n.sym; - rank = sym->as->rank - 1; - gfc_conv_expr (se, e); - - array = sym->backend_decl; - type = TREE_TYPE (array); - - if (GFC_ARRAY_TYPE_P (type)) - size = GFC_TYPE_ARRAY_SIZE (type); - else - { - gcc_assert (GFC_DESCRIPTOR_TYPE_P (type)); - size = gfc_conv_array_stride (array, rank); - tmp = fold_build2_loc (input_location, MINUS_EXPR, - gfc_array_index_type, - gfc_conv_array_ubound (array, rank), - gfc_conv_array_lbound (array, rank)); - 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, tmp, size); - } - gcc_assert (size); - - size = fold_build2_loc (input_location, MINUS_EXPR, - gfc_array_index_type, size, - TREE_OPERAND (se->expr, 1)); - se->expr = gfc_build_addr_expr (NULL_TREE, se->expr); - tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); - size = fold_build2_loc (input_location, MULT_EXPR, - gfc_array_index_type, size, - fold_convert (gfc_array_index_type, tmp)); - se->string_length = fold_convert (gfc_charlen_type_node, size); - return; - } - - gfc_conv_array_parameter (se, e, true, NULL, NULL, &size); - se->string_length = fold_convert (gfc_charlen_type_node, size); -} - - -/* Generate code to store a string and its length into the - st_parameter_XXX structure. */ - -static unsigned int -set_string (stmtblock_t * block, stmtblock_t * postblock, tree var, - enum iofield type, gfc_expr * e) -{ - gfc_se se; - tree tmp; - tree io; - tree len; - gfc_st_parameter_field *p = &st_parameter_field[type]; - - gfc_init_se (&se, NULL); - - if (p->param_type == IOPARM_ptype_common) - var = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - io = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - len = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (p->field_len), - var, p->field_len, NULL_TREE); - - /* Integer variable assigned a format label. */ - if (e->ts.type == BT_INTEGER - && e->rank == 0 - && e->symtree->n.sym->attr.assign == 1) - { - char * msg; - tree cond; - - gfc_conv_label_variable (&se, e); - tmp = GFC_DECL_STRING_LEN (se.expr); - cond = fold_build2_loc (input_location, LT_EXPR, boolean_type_node, - tmp, build_int_cst (TREE_TYPE (tmp), 0)); - - asprintf(&msg, "Label assigned to variable '%s' (%%ld) is not a format " - "label", e->symtree->name); - gfc_trans_runtime_check (true, false, cond, &se.pre, &e->where, msg, - fold_convert (long_integer_type_node, tmp)); - free (msg); - - gfc_add_modify (&se.pre, io, - fold_convert (TREE_TYPE (io), GFC_DECL_ASSIGN_ADDR (se.expr))); - gfc_add_modify (&se.pre, len, GFC_DECL_STRING_LEN (se.expr)); - } - else - { - /* General character. */ - if (e->ts.type == BT_CHARACTER && e->rank == 0) - gfc_conv_expr (&se, e); - /* Array assigned Hollerith constant or character array. */ - else if (e->rank > 0 || (e->symtree && e->symtree->n.sym->as->rank > 0)) - gfc_convert_array_to_string (&se, e); - else - gcc_unreachable (); - - gfc_conv_string_parameter (&se); - gfc_add_modify (&se.pre, io, fold_convert (TREE_TYPE (io), se.expr)); - gfc_add_modify (&se.pre, len, se.string_length); - } - - gfc_add_block_to_block (block, &se.pre); - gfc_add_block_to_block (postblock, &se.post); - return p->mask; -} - - -/* Generate code to store the character (array) and the character length - for an internal unit. */ - -static unsigned int -set_internal_unit (stmtblock_t * block, stmtblock_t * post_block, - tree var, gfc_expr * e) -{ - gfc_se se; - tree io; - tree len; - tree desc; - tree tmp; - gfc_st_parameter_field *p; - unsigned int mask; - - gfc_init_se (&se, NULL); - - p = &st_parameter_field[IOPARM_dt_internal_unit]; - mask = p->mask; - io = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - len = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field_len), - var, p->field_len, NULL_TREE); - p = &st_parameter_field[IOPARM_dt_internal_unit_desc]; - desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - - gcc_assert (e->ts.type == BT_CHARACTER); - - /* Character scalars. */ - if (e->rank == 0) - { - gfc_conv_expr (&se, e); - gfc_conv_string_parameter (&se); - tmp = se.expr; - se.expr = build_int_cst (pchar_type_node, 0); - } - - /* Character array. */ - else if (e->rank > 0) - { - if (is_subref_array (e)) - { - /* Use a temporary for components of arrays of derived types - or substring array references. */ - gfc_conv_subref_array_arg (&se, e, 0, - last_dt == READ ? INTENT_IN : INTENT_OUT, false); - tmp = build_fold_indirect_ref_loc (input_location, - se.expr); - se.expr = gfc_build_addr_expr (pchar_type_node, tmp); - tmp = gfc_conv_descriptor_data_get (tmp); - } - else - { - /* Return the data pointer and rank from the descriptor. */ - gfc_conv_expr_descriptor (&se, e); - tmp = gfc_conv_descriptor_data_get (se.expr); - se.expr = gfc_build_addr_expr (pchar_type_node, se.expr); - } - } - else - gcc_unreachable (); - - /* The cast is needed for character substrings and the descriptor - data. */ - gfc_add_modify (&se.pre, io, fold_convert (TREE_TYPE (io), tmp)); - gfc_add_modify (&se.pre, len, - fold_convert (TREE_TYPE (len), se.string_length)); - gfc_add_modify (&se.pre, desc, se.expr); - - gfc_add_block_to_block (block, &se.pre); - gfc_add_block_to_block (post_block, &se.post); - return mask; -} - -/* Add a case to a IO-result switch. */ - -static void -add_case (int label_value, gfc_st_label * label, stmtblock_t * body) -{ - tree tmp, value; - - if (label == NULL) - return; /* No label, no case */ - - value = build_int_cst (integer_type_node, label_value); - - /* Make a backend label for this case. */ - tmp = gfc_build_label_decl (NULL_TREE); - - /* And the case itself. */ - tmp = build_case_label (value, NULL_TREE, tmp); - gfc_add_expr_to_block (body, tmp); - - /* Jump to the label. */ - tmp = build1_v (GOTO_EXPR, gfc_get_label_decl (label)); - gfc_add_expr_to_block (body, tmp); -} - - -/* Generate a switch statement that branches to the correct I/O - result label. The last statement of an I/O call stores the - result into a variable because there is often cleanup that - must be done before the switch, so a temporary would have to - be created anyway. */ - -static void -io_result (stmtblock_t * block, tree var, gfc_st_label * err_label, - gfc_st_label * end_label, gfc_st_label * eor_label) -{ - stmtblock_t body; - tree tmp, rc; - gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_flags]; - - /* If no labels are specified, ignore the result instead - of building an empty switch. */ - if (err_label == NULL - && end_label == NULL - && eor_label == NULL) - return; - - /* Build a switch statement. */ - gfc_start_block (&body); - - /* The label values here must be the same as the values - in the library_return enum in the runtime library */ - add_case (1, err_label, &body); - add_case (2, end_label, &body); - add_case (3, eor_label, &body); - - tmp = gfc_finish_block (&body); - - var = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - rc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (p->field), - var, p->field, NULL_TREE); - rc = fold_build2_loc (input_location, BIT_AND_EXPR, TREE_TYPE (rc), - rc, build_int_cst (TREE_TYPE (rc), - IOPARM_common_libreturn_mask)); - - tmp = fold_build3_loc (input_location, SWITCH_EXPR, NULL_TREE, - rc, tmp, NULL_TREE); - - gfc_add_expr_to_block (block, tmp); -} - - -/* Store the current file and line number to variables so that if a - library call goes awry, we can tell the user where the problem is. */ - -static void -set_error_locus (stmtblock_t * block, tree var, locus * where) -{ - gfc_file *f; - tree str, locus_file; - int line; - gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_filename]; - - locus_file = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE); - locus_file = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (p->field), locus_file, - p->field, NULL_TREE); - f = where->lb->file; - str = gfc_build_cstring_const (f->filename); - - str = gfc_build_addr_expr (pchar_type_node, str); - gfc_add_modify (block, locus_file, str); - - line = LOCATION_LINE (where->lb->location); - set_parameter_const (block, var, IOPARM_common_line, line); -} - - -/* Translate an OPEN statement. */ - -tree -gfc_trans_open (gfc_code * code) -{ - stmtblock_t block, post_block; - gfc_open *p; - tree tmp, var; - unsigned int mask = 0; - - gfc_start_block (&block); - gfc_init_block (&post_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_open].type, "open_parm"); - - set_error_locus (&block, var, &code->loc); - p = code->ext.open; - - if (p->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - p->iomsg); - - if (p->iostat) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat, - p->iostat); - - if (p->err) - mask |= IOPARM_common_err; - - if (p->file) - mask |= set_string (&block, &post_block, var, IOPARM_open_file, p->file); - - if (p->status) - mask |= set_string (&block, &post_block, var, IOPARM_open_status, - p->status); - - if (p->access) - mask |= set_string (&block, &post_block, var, IOPARM_open_access, - p->access); - - if (p->form) - mask |= set_string (&block, &post_block, var, IOPARM_open_form, p->form); - - if (p->recl) - mask |= set_parameter_value (&block, var, IOPARM_open_recl_in, p->recl); - - if (p->blank) - mask |= set_string (&block, &post_block, var, IOPARM_open_blank, - p->blank); - - if (p->position) - mask |= set_string (&block, &post_block, var, IOPARM_open_position, - p->position); - - if (p->action) - mask |= set_string (&block, &post_block, var, IOPARM_open_action, - p->action); - - if (p->delim) - mask |= set_string (&block, &post_block, var, IOPARM_open_delim, - p->delim); - - if (p->pad) - mask |= set_string (&block, &post_block, var, IOPARM_open_pad, p->pad); - - if (p->decimal) - mask |= set_string (&block, &post_block, var, IOPARM_open_decimal, - p->decimal); - - if (p->encoding) - mask |= set_string (&block, &post_block, var, IOPARM_open_encoding, - p->encoding); - - if (p->round) - mask |= set_string (&block, &post_block, var, IOPARM_open_round, p->round); - - if (p->sign) - mask |= set_string (&block, &post_block, var, IOPARM_open_sign, p->sign); - - if (p->asynchronous) - mask |= set_string (&block, &post_block, var, IOPARM_open_asynchronous, - p->asynchronous); - - if (p->convert) - mask |= set_string (&block, &post_block, var, IOPARM_open_convert, - p->convert); - - if (p->newunit) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_open_newunit, - p->newunit); - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (p->unit) - set_parameter_value (&block, var, IOPARM_common_unit, p->unit); - else - set_parameter_const (&block, var, IOPARM_common_unit, 0); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_OPEN], 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - io_result (&block, var, p->err, NULL, NULL); - - return gfc_finish_block (&block); -} - - -/* Translate a CLOSE statement. */ - -tree -gfc_trans_close (gfc_code * code) -{ - stmtblock_t block, post_block; - gfc_close *p; - tree tmp, var; - unsigned int mask = 0; - - gfc_start_block (&block); - gfc_init_block (&post_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_close].type, "close_parm"); - - set_error_locus (&block, var, &code->loc); - p = code->ext.close; - - if (p->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - p->iomsg); - - if (p->iostat) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat, - p->iostat); - - if (p->err) - mask |= IOPARM_common_err; - - if (p->status) - mask |= set_string (&block, &post_block, var, IOPARM_close_status, - p->status); - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (p->unit) - set_parameter_value (&block, var, IOPARM_common_unit, p->unit); - else - set_parameter_const (&block, var, IOPARM_common_unit, 0); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_CLOSE], 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - io_result (&block, var, p->err, NULL, NULL); - - return gfc_finish_block (&block); -} - - -/* Common subroutine for building a file positioning statement. */ - -static tree -build_filepos (tree function, gfc_code * code) -{ - stmtblock_t block, post_block; - gfc_filepos *p; - tree tmp, var; - unsigned int mask = 0; - - p = code->ext.filepos; - - gfc_start_block (&block); - gfc_init_block (&post_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_filepos].type, - "filepos_parm"); - - set_error_locus (&block, var, &code->loc); - - if (p->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - p->iomsg); - - if (p->iostat) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat, - p->iostat); - - if (p->err) - mask |= IOPARM_common_err; - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (p->unit) - set_parameter_value (&block, var, IOPARM_common_unit, p->unit); - else - set_parameter_const (&block, var, IOPARM_common_unit, 0); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (input_location, - function, 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - io_result (&block, var, p->err, NULL, NULL); - - return gfc_finish_block (&block); -} - - -/* Translate a BACKSPACE statement. */ - -tree -gfc_trans_backspace (gfc_code * code) -{ - return build_filepos (iocall[IOCALL_BACKSPACE], code); -} - - -/* Translate an ENDFILE statement. */ - -tree -gfc_trans_endfile (gfc_code * code) -{ - return build_filepos (iocall[IOCALL_ENDFILE], code); -} - - -/* Translate a REWIND statement. */ - -tree -gfc_trans_rewind (gfc_code * code) -{ - return build_filepos (iocall[IOCALL_REWIND], code); -} - - -/* Translate a FLUSH statement. */ - -tree -gfc_trans_flush (gfc_code * code) -{ - return build_filepos (iocall[IOCALL_FLUSH], code); -} - - -/* Create a dummy iostat variable to catch any error due to bad unit. */ - -static gfc_expr * -create_dummy_iostat (void) -{ - gfc_symtree *st; - gfc_expr *e; - - gfc_get_ha_sym_tree ("@iostat", &st); - st->n.sym->ts.type = BT_INTEGER; - st->n.sym->ts.kind = gfc_default_integer_kind; - gfc_set_sym_referenced (st->n.sym); - gfc_commit_symbol (st->n.sym); - st->n.sym->backend_decl - = gfc_create_var (gfc_get_int_type (st->n.sym->ts.kind), - st->n.sym->name); - - e = gfc_get_expr (); - e->expr_type = EXPR_VARIABLE; - e->symtree = st; - e->ts.type = BT_INTEGER; - e->ts.kind = st->n.sym->ts.kind; - - return e; -} - - -/* Translate the non-IOLENGTH form of an INQUIRE statement. */ - -tree -gfc_trans_inquire (gfc_code * code) -{ - stmtblock_t block, post_block; - gfc_inquire *p; - tree tmp, var; - unsigned int mask = 0, mask2 = 0; - - gfc_start_block (&block); - gfc_init_block (&post_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_inquire].type, - "inquire_parm"); - - set_error_locus (&block, var, &code->loc); - p = code->ext.inquire; - - if (p->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - p->iomsg); - - if (p->iostat) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat, - p->iostat); - - if (p->err) - mask |= IOPARM_common_err; - - /* Sanity check. */ - if (p->unit && p->file) - gfc_error ("INQUIRE statement at %L cannot contain both FILE and UNIT specifiers", &code->loc); - - if (p->file) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_file, - p->file); - - if (p->exist) - { - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_exist, - p->exist); - - if (p->unit && !p->iostat) - { - p->iostat = create_dummy_iostat (); - mask |= set_parameter_ref (&block, &post_block, var, - IOPARM_common_iostat, p->iostat); - } - } - - if (p->opened) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_opened, - p->opened); - - if (p->number) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_number, - p->number); - - if (p->named) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_named, - p->named); - - if (p->name) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_name, - p->name); - - if (p->access) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_access, - p->access); - - if (p->sequential) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_sequential, - p->sequential); - - if (p->direct) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_direct, - p->direct); - - if (p->form) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_form, - p->form); - - if (p->formatted) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_formatted, - p->formatted); - - if (p->unformatted) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_unformatted, - p->unformatted); - - if (p->recl) - mask |= set_parameter_ref (&block, &post_block, var, - IOPARM_inquire_recl_out, p->recl); - - if (p->nextrec) - mask |= set_parameter_ref (&block, &post_block, var, - IOPARM_inquire_nextrec, p->nextrec); - - if (p->blank) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_blank, - p->blank); - - if (p->delim) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_delim, - p->delim); - - if (p->position) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_position, - p->position); - - if (p->action) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_action, - p->action); - - if (p->read) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_read, - p->read); - - if (p->write) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_write, - p->write); - - if (p->readwrite) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_readwrite, - p->readwrite); - - if (p->pad) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_pad, - p->pad); - - if (p->convert) - mask |= set_string (&block, &post_block, var, IOPARM_inquire_convert, - p->convert); - - if (p->strm_pos) - mask |= set_parameter_ref (&block, &post_block, var, - IOPARM_inquire_strm_pos_out, p->strm_pos); - - /* The second series of flags. */ - if (p->asynchronous) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_asynchronous, - p->asynchronous); - - if (p->decimal) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_decimal, - p->decimal); - - if (p->encoding) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_encoding, - p->encoding); - - if (p->round) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_round, - p->round); - - if (p->sign) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_sign, - p->sign); - - if (p->pending) - mask2 |= set_parameter_ref (&block, &post_block, var, - IOPARM_inquire_pending, p->pending); - - if (p->size) - mask2 |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_size, - p->size); - - if (p->id) - mask2 |= set_parameter_ref (&block, &post_block,var, IOPARM_inquire_id, - p->id); - if (p->iqstream) - mask2 |= set_string (&block, &post_block, var, IOPARM_inquire_iqstream, - p->iqstream); - - if (mask2) - mask |= set_parameter_const (&block, var, IOPARM_inquire_flags2, mask2); - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (p->unit) - set_parameter_value (&block, var, IOPARM_common_unit, p->unit); - else - set_parameter_const (&block, var, IOPARM_common_unit, 0); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_INQUIRE], 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - io_result (&block, var, p->err, NULL, NULL); - - return gfc_finish_block (&block); -} - - -tree -gfc_trans_wait (gfc_code * code) -{ - stmtblock_t block, post_block; - gfc_wait *p; - tree tmp, var; - unsigned int mask = 0; - - gfc_start_block (&block); - gfc_init_block (&post_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_wait].type, - "wait_parm"); - - set_error_locus (&block, var, &code->loc); - p = code->ext.wait; - - /* Set parameters here. */ - if (p->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - p->iomsg); - - if (p->iostat) - mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat, - p->iostat); - - if (p->err) - mask |= IOPARM_common_err; - - if (p->id) - mask |= set_parameter_value (&block, var, IOPARM_wait_id, p->id); - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (p->unit) - set_parameter_value (&block, var, IOPARM_common_unit, p->unit); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_WAIT], 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - io_result (&block, var, p->err, NULL, NULL); - - return gfc_finish_block (&block); - -} - - -/* nml_full_name builds up the fully qualified name of a - derived type component. */ - -static char* -nml_full_name (const char* var_name, const char* cmp_name) -{ - int full_name_length; - char * full_name; - - full_name_length = strlen (var_name) + strlen (cmp_name) + 1; - full_name = XCNEWVEC (char, full_name_length + 1); - strcpy (full_name, var_name); - full_name = strcat (full_name, "%"); - full_name = strcat (full_name, cmp_name); - return full_name; -} - - -/* nml_get_addr_expr builds an address expression from the - gfc_symbol or gfc_component backend_decl's. An offset is - provided so that the address of an element of an array of - derived types is returned. This is used in the runtime to - determine that span of the derived type. */ - -static tree -nml_get_addr_expr (gfc_symbol * sym, gfc_component * c, - tree base_addr) -{ - tree decl = NULL_TREE; - tree tmp; - - if (sym) - { - sym->attr.referenced = 1; - decl = gfc_get_symbol_decl (sym); - - /* If this is the enclosing function declaration, use - the fake result instead. */ - if (decl == current_function_decl) - decl = gfc_get_fake_result_decl (sym, 0); - else if (decl == DECL_CONTEXT (current_function_decl)) - decl = gfc_get_fake_result_decl (sym, 1); - } - else - decl = c->backend_decl; - - gcc_assert (decl && ((TREE_CODE (decl) == FIELD_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == PARM_DECL) - || TREE_CODE (decl) == COMPONENT_REF)); - - tmp = decl; - - /* Build indirect reference, if dummy argument. */ - - if (POINTER_TYPE_P (TREE_TYPE(tmp))) - tmp = build_fold_indirect_ref_loc (input_location, tmp); - - /* Treat the component of a derived type, using base_addr for - the derived type. */ - - if (TREE_CODE (decl) == FIELD_DECL) - tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (tmp), - base_addr, tmp, NULL_TREE); - - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp))) - tmp = gfc_conv_array_data (tmp); - else - { - if (!POINTER_TYPE_P (TREE_TYPE (tmp))) - tmp = gfc_build_addr_expr (NULL_TREE, tmp); - - if (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) - tmp = gfc_build_array_ref (tmp, gfc_index_zero_node, NULL); - - if (!POINTER_TYPE_P (TREE_TYPE (tmp))) - tmp = build_fold_indirect_ref_loc (input_location, - tmp); - } - - gcc_assert (tmp && POINTER_TYPE_P (TREE_TYPE (tmp))); - - return tmp; -} - - -/* For an object VAR_NAME whose base address is BASE_ADDR, generate a - call to iocall[IOCALL_SET_NML_VAL]. For derived type variable, recursively - generate calls to iocall[IOCALL_SET_NML_VAL] for each component. */ - -#define IARG(i) build_int_cst (gfc_array_index_type, i) - -static void -transfer_namelist_element (stmtblock_t * block, const char * var_name, - gfc_symbol * sym, gfc_component * c, - tree base_addr) -{ - gfc_typespec * ts = NULL; - gfc_array_spec * as = NULL; - tree addr_expr = NULL; - tree dt = NULL; - tree string; - tree tmp; - tree dtype; - tree dt_parm_addr; - tree decl = NULL_TREE; - int n_dim; - int itype; - int rank = 0; - - gcc_assert (sym || c); - - /* Build the namelist object name. */ - - string = gfc_build_cstring_const (var_name); - string = gfc_build_addr_expr (pchar_type_node, string); - - /* Build ts, as and data address using symbol or component. */ - - ts = (sym) ? &sym->ts : &c->ts; - as = (sym) ? sym->as : c->as; - - addr_expr = nml_get_addr_expr (sym, c, base_addr); - - if (as) - rank = as->rank; - - if (rank) - { - decl = (sym) ? sym->backend_decl : c->backend_decl; - if (sym && sym->attr.dummy) - decl = build_fold_indirect_ref_loc (input_location, decl); - dt = TREE_TYPE (decl); - dtype = gfc_get_dtype (dt); - } - else - { - itype = ts->type; - dtype = IARG (itype << GFC_DTYPE_TYPE_SHIFT); - } - - /* Build up the arguments for the transfer call. - The call for the scalar part transfers: - (address, name, type, kind or string_length, dtype) */ - - dt_parm_addr = gfc_build_addr_expr (NULL_TREE, dt_parm); - - if (ts->type == BT_CHARACTER) - tmp = ts->u.cl->backend_decl; - else - tmp = build_int_cst (gfc_charlen_type_node, 0); - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_SET_NML_VAL], 6, - dt_parm_addr, addr_expr, string, - IARG (ts->kind), tmp, dtype); - gfc_add_expr_to_block (block, tmp); - - /* If the object is an array, transfer rank times: - (null pointer, name, stride, lbound, ubound) */ - - for ( n_dim = 0 ; n_dim < rank ; n_dim++ ) - { - tmp = build_call_expr_loc (input_location, - iocall[IOCALL_SET_NML_VAL_DIM], 5, - dt_parm_addr, - IARG (n_dim), - gfc_conv_array_stride (decl, n_dim), - gfc_conv_array_lbound (decl, n_dim), - gfc_conv_array_ubound (decl, n_dim)); - gfc_add_expr_to_block (block, tmp); - } - - if (ts->type == BT_DERIVED && ts->u.derived->components) - { - gfc_component *cmp; - - /* Provide the RECORD_TYPE to build component references. */ - - tree expr = build_fold_indirect_ref_loc (input_location, - addr_expr); - - for (cmp = ts->u.derived->components; cmp; cmp = cmp->next) - { - char *full_name = nml_full_name (var_name, cmp->name); - transfer_namelist_element (block, - full_name, - NULL, cmp, expr); - free (full_name); - } - } -} - -#undef IARG - -/* Create a data transfer statement. Not all of the fields are valid - for both reading and writing, but improper use has been filtered - out by now. */ - -static tree -build_dt (tree function, gfc_code * code) -{ - stmtblock_t block, post_block, post_end_block, post_iu_block; - gfc_dt *dt; - tree tmp, var; - gfc_expr *nmlname; - gfc_namelist *nml; - unsigned int mask = 0; - - gfc_start_block (&block); - gfc_init_block (&post_block); - gfc_init_block (&post_end_block); - gfc_init_block (&post_iu_block); - - var = gfc_create_var (st_parameter[IOPARM_ptype_dt].type, "dt_parm"); - - set_error_locus (&block, var, &code->loc); - - if (last_dt == IOLENGTH) - { - gfc_inquire *inq; - - inq = code->ext.inquire; - - /* First check that preconditions are met. */ - gcc_assert (inq != NULL); - gcc_assert (inq->iolength != NULL); - - /* Connect to the iolength variable. */ - mask |= set_parameter_ref (&block, &post_end_block, var, - IOPARM_dt_iolength, inq->iolength); - dt = NULL; - } - else - { - dt = code->ext.dt; - gcc_assert (dt != NULL); - } - - if (dt && dt->io_unit) - { - if (dt->io_unit->ts.type == BT_CHARACTER) - { - mask |= set_internal_unit (&block, &post_iu_block, - var, dt->io_unit); - set_parameter_const (&block, var, IOPARM_common_unit, - dt->io_unit->ts.kind == 1 ? 0 : -1); - } - } - else - set_parameter_const (&block, var, IOPARM_common_unit, 0); - - if (dt) - { - if (dt->iomsg) - mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg, - dt->iomsg); - - if (dt->iostat) - mask |= set_parameter_ref (&block, &post_end_block, var, - IOPARM_common_iostat, dt->iostat); - - if (dt->err) - mask |= IOPARM_common_err; - - if (dt->eor) - mask |= IOPARM_common_eor; - - if (dt->end) - mask |= IOPARM_common_end; - - if (dt->id) - mask |= set_parameter_ref (&block, &post_end_block, var, - IOPARM_dt_id, dt->id); - - if (dt->pos) - mask |= set_parameter_value (&block, var, IOPARM_dt_pos, dt->pos); - - if (dt->asynchronous) - mask |= set_string (&block, &post_block, var, IOPARM_dt_asynchronous, - dt->asynchronous); - - if (dt->blank) - mask |= set_string (&block, &post_block, var, IOPARM_dt_blank, - dt->blank); - - if (dt->decimal) - mask |= set_string (&block, &post_block, var, IOPARM_dt_decimal, - dt->decimal); - - if (dt->delim) - mask |= set_string (&block, &post_block, var, IOPARM_dt_delim, - dt->delim); - - if (dt->pad) - mask |= set_string (&block, &post_block, var, IOPARM_dt_pad, - dt->pad); - - if (dt->round) - mask |= set_string (&block, &post_block, var, IOPARM_dt_round, - dt->round); - - if (dt->sign) - mask |= set_string (&block, &post_block, var, IOPARM_dt_sign, - dt->sign); - - if (dt->rec) - mask |= set_parameter_value (&block, var, IOPARM_dt_rec, dt->rec); - - if (dt->advance) - mask |= set_string (&block, &post_block, var, IOPARM_dt_advance, - dt->advance); - - if (dt->format_expr) - mask |= set_string (&block, &post_end_block, var, IOPARM_dt_format, - dt->format_expr); - - if (dt->format_label) - { - if (dt->format_label == &format_asterisk) - mask |= IOPARM_dt_list_format; - else - mask |= set_string (&block, &post_block, var, IOPARM_dt_format, - dt->format_label->format); - } - - if (dt->size) - mask |= set_parameter_ref (&block, &post_end_block, var, - IOPARM_dt_size, dt->size); - - if (dt->namelist) - { - if (dt->format_expr || dt->format_label) - gfc_internal_error ("build_dt: format with namelist"); - - nmlname = gfc_get_character_expr (gfc_default_character_kind, NULL, - dt->namelist->name, - strlen (dt->namelist->name)); - - mask |= set_string (&block, &post_block, var, IOPARM_dt_namelist_name, - nmlname); - - gfc_free_expr (nmlname); - - if (last_dt == READ) - mask |= IOPARM_dt_namelist_read_mode; - - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - dt_parm = var; - - for (nml = dt->namelist->namelist; nml; nml = nml->next) - transfer_namelist_element (&block, nml->sym->name, nml->sym, - NULL, NULL_TREE); - } - else - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - if (dt->io_unit && dt->io_unit->ts.type == BT_INTEGER) - set_parameter_value (&block, var, IOPARM_common_unit, dt->io_unit); - } - else - set_parameter_const (&block, var, IOPARM_common_flags, mask); - - tmp = gfc_build_addr_expr (NULL_TREE, var); - tmp = build_call_expr_loc (UNKNOWN_LOCATION, - function, 1, tmp); - gfc_add_expr_to_block (&block, tmp); - - gfc_add_block_to_block (&block, &post_block); - - dt_parm = var; - dt_post_end_block = &post_end_block; - - /* Set implied do loop exit condition. */ - if (last_dt == READ || last_dt == WRITE) - { - gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_flags]; - - tmp = fold_build3_loc (input_location, COMPONENT_REF, - st_parameter[IOPARM_ptype_common].type, - dt_parm, TYPE_FIELDS (TREE_TYPE (dt_parm)), - NULL_TREE); - tmp = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (p->field), tmp, p->field, NULL_TREE); - tmp = fold_build2_loc (input_location, BIT_AND_EXPR, TREE_TYPE (tmp), - tmp, build_int_cst (TREE_TYPE (tmp), - IOPARM_common_libreturn_mask)); - } - else /* IOLENGTH */ - tmp = NULL_TREE; - - gfc_add_expr_to_block (&block, gfc_trans_code_cond (code->block->next, tmp)); - - gfc_add_block_to_block (&block, &post_iu_block); - - dt_parm = NULL; - dt_post_end_block = NULL; - - return gfc_finish_block (&block); -} - - -/* Translate the IOLENGTH form of an INQUIRE statement. We treat - this as a third sort of data transfer statement, except that - lengths are summed instead of actually transferring any data. */ - -tree -gfc_trans_iolength (gfc_code * code) -{ - last_dt = IOLENGTH; - return build_dt (iocall[IOCALL_IOLENGTH], code); -} - - -/* Translate a READ statement. */ - -tree -gfc_trans_read (gfc_code * code) -{ - last_dt = READ; - return build_dt (iocall[IOCALL_READ], code); -} - - -/* Translate a WRITE statement */ - -tree -gfc_trans_write (gfc_code * code) -{ - last_dt = WRITE; - return build_dt (iocall[IOCALL_WRITE], code); -} - - -/* Finish a data transfer statement. */ - -tree -gfc_trans_dt_end (gfc_code * code) -{ - tree function, tmp; - stmtblock_t block; - - gfc_init_block (&block); - - switch (last_dt) - { - case READ: - function = iocall[IOCALL_READ_DONE]; - break; - - case WRITE: - function = iocall[IOCALL_WRITE_DONE]; - break; - - case IOLENGTH: - function = iocall[IOCALL_IOLENGTH_DONE]; - break; - - default: - gcc_unreachable (); - } - - tmp = gfc_build_addr_expr (NULL_TREE, dt_parm); - tmp = build_call_expr_loc (input_location, - function, 1, tmp); - gfc_add_expr_to_block (&block, tmp); - gfc_add_block_to_block (&block, dt_post_end_block); - gfc_init_block (dt_post_end_block); - - if (last_dt != IOLENGTH) - { - gcc_assert (code->ext.dt != NULL); - io_result (&block, dt_parm, code->ext.dt->err, - code->ext.dt->end, code->ext.dt->eor); - } - - return gfc_finish_block (&block); -} - -static void -transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr, gfc_code * code); - -/* Given an array field in a derived type variable, generate the code - for the loop that iterates over array elements, and the code that - accesses those array elements. Use transfer_expr to generate code - for transferring that element. Because elements may also be - derived types, transfer_expr and transfer_array_component are mutually - recursive. */ - -static tree -transfer_array_component (tree expr, gfc_component * cm, locus * where) -{ - tree tmp; - stmtblock_t body; - stmtblock_t block; - gfc_loopinfo loop; - int n; - gfc_ss *ss; - gfc_se se; - gfc_array_info *ss_array; - - gfc_start_block (&block); - gfc_init_se (&se, NULL); - - /* Create and initialize Scalarization Status. Unlike in - gfc_trans_transfer, we can't simply use gfc_walk_expr to take - care of this task, because we don't have a gfc_expr at hand. - Build one manually, as in gfc_trans_subarray_assign. */ - - ss = gfc_get_array_ss (gfc_ss_terminator, NULL, cm->as->rank, - GFC_SS_COMPONENT); - ss_array = &ss->info->data.array; - ss_array->shape = gfc_get_shape (cm->as->rank); - ss_array->descriptor = expr; - ss_array->data = gfc_conv_array_data (expr); - ss_array->offset = gfc_conv_array_offset (expr); - for (n = 0; n < cm->as->rank; n++) - { - ss_array->start[n] = gfc_conv_array_lbound (expr, n); - ss_array->stride[n] = gfc_index_one_node; - - mpz_init (ss_array->shape[n]); - mpz_sub (ss_array->shape[n], cm->as->upper[n]->value.integer, - cm->as->lower[n]->value.integer); - mpz_add_ui (ss_array->shape[n], ss_array->shape[n], 1); - } - - /* Once we got ss, we use scalarizer to create the loop. */ - - gfc_init_loopinfo (&loop); - gfc_add_ss_to_loop (&loop, ss); - gfc_conv_ss_startstride (&loop); - gfc_conv_loop_setup (&loop, where); - gfc_mark_ss_chain_used (ss, 1); - gfc_start_scalarized_body (&loop, &body); - - gfc_copy_loopinfo_to_se (&se, &loop); - se.ss = ss; - - /* gfc_conv_tmp_array_ref assumes that se.expr contains the array. */ - se.expr = expr; - gfc_conv_tmp_array_ref (&se); - - /* Now se.expr contains an element of the array. Take the address and pass - it to the IO routines. */ - tmp = gfc_build_addr_expr (NULL_TREE, se.expr); - transfer_expr (&se, &cm->ts, tmp, NULL); - - /* We are done now with the loop body. Wrap up the scalarizer and - return. */ - - gfc_add_block_to_block (&body, &se.pre); - gfc_add_block_to_block (&body, &se.post); - - gfc_trans_scalarizing_loops (&loop, &body); - - gfc_add_block_to_block (&block, &loop.pre); - gfc_add_block_to_block (&block, &loop.post); - - gcc_assert (ss_array->shape != NULL); - gfc_free_shape (&ss_array->shape, cm->as->rank); - gfc_cleanup_loop (&loop); - - return gfc_finish_block (&block); -} - -/* Generate the call for a scalar transfer node. */ - -static void -transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr, gfc_code * code) -{ - tree tmp, function, arg2, arg3, field, expr; - gfc_component *c; - int kind; - - /* It is possible to get a C_NULL_PTR or C_NULL_FUNPTR expression here if - the user says something like: print *, 'c_null_ptr: ', c_null_ptr - We need to translate the expression to a constant if it's either - C_NULL_PTR or C_NULL_FUNPTR. We could also get a user variable of - type C_PTR or C_FUNPTR, in which case the ts->type may no longer be - BT_DERIVED (could have been changed by gfc_conv_expr). */ - if ((ts->type == BT_DERIVED || ts->type == BT_INTEGER) - && ts->u.derived != NULL - && (ts->is_iso_c == 1 || ts->u.derived->ts.is_iso_c == 1)) - { - /* C_PTR and C_FUNPTR have private components which means they can not - be printed. However, if -std=gnu and not -pedantic, allow - the component to be printed to help debugging. */ - if (gfc_notification_std (GFC_STD_GNU) != SILENT) - { - gfc_error_now ("Derived type '%s' at %L has PRIVATE components", - ts->u.derived->name, code != NULL ? &(code->loc) : - &gfc_current_locus); - return; - } - - ts->type = ts->u.derived->ts.type; - ts->kind = ts->u.derived->ts.kind; - ts->f90_type = ts->u.derived->ts.f90_type; - } - - kind = ts->kind; - function = NULL; - arg2 = NULL; - arg3 = NULL; - - switch (ts->type) - { - case BT_INTEGER: - arg2 = build_int_cst (integer_type_node, kind); - if (last_dt == READ) - function = iocall[IOCALL_X_INTEGER]; - else - function = iocall[IOCALL_X_INTEGER_WRITE]; - - break; - - case BT_REAL: - arg2 = build_int_cst (integer_type_node, kind); - if (last_dt == READ) - { - if (gfc_real16_is_float128 && ts->kind == 16) - function = iocall[IOCALL_X_REAL128]; - else - function = iocall[IOCALL_X_REAL]; - } - else - { - if (gfc_real16_is_float128 && ts->kind == 16) - function = iocall[IOCALL_X_REAL128_WRITE]; - else - function = iocall[IOCALL_X_REAL_WRITE]; - } - - break; - - case BT_COMPLEX: - arg2 = build_int_cst (integer_type_node, kind); - if (last_dt == READ) - { - if (gfc_real16_is_float128 && ts->kind == 16) - function = iocall[IOCALL_X_COMPLEX128]; - else - function = iocall[IOCALL_X_COMPLEX]; - } - else - { - if (gfc_real16_is_float128 && ts->kind == 16) - function = iocall[IOCALL_X_COMPLEX128_WRITE]; - else - function = iocall[IOCALL_X_COMPLEX_WRITE]; - } - - break; - - case BT_LOGICAL: - arg2 = build_int_cst (integer_type_node, kind); - if (last_dt == READ) - function = iocall[IOCALL_X_LOGICAL]; - else - function = iocall[IOCALL_X_LOGICAL_WRITE]; - - break; - - case BT_CHARACTER: - if (kind == 4) - { - if (se->string_length) - arg2 = se->string_length; - else - { - tmp = build_fold_indirect_ref_loc (input_location, - addr_expr); - gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE); - arg2 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp))); - arg2 = fold_convert (gfc_charlen_type_node, arg2); - } - arg3 = build_int_cst (integer_type_node, kind); - if (last_dt == READ) - function = iocall[IOCALL_X_CHARACTER_WIDE]; - else - function = iocall[IOCALL_X_CHARACTER_WIDE_WRITE]; - - tmp = gfc_build_addr_expr (NULL_TREE, dt_parm); - tmp = build_call_expr_loc (input_location, - function, 4, tmp, addr_expr, arg2, arg3); - gfc_add_expr_to_block (&se->pre, tmp); - gfc_add_block_to_block (&se->pre, &se->post); - return; - } - /* Fall through. */ - case BT_HOLLERITH: - if (se->string_length) - arg2 = se->string_length; - else - { - tmp = build_fold_indirect_ref_loc (input_location, - addr_expr); - gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE); - arg2 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp))); - } - if (last_dt == READ) - function = iocall[IOCALL_X_CHARACTER]; - else - function = iocall[IOCALL_X_CHARACTER_WRITE]; - - break; - - case BT_DERIVED: - if (ts->u.derived->components == NULL) - return; - - /* Recurse into the elements of the derived type. */ - expr = gfc_evaluate_now (addr_expr, &se->pre); - expr = build_fold_indirect_ref_loc (input_location, - expr); - - for (c = ts->u.derived->components; c; c = c->next) - { - field = c->backend_decl; - gcc_assert (field && TREE_CODE (field) == FIELD_DECL); - - tmp = fold_build3_loc (UNKNOWN_LOCATION, - COMPONENT_REF, TREE_TYPE (field), - expr, field, NULL_TREE); - - if (c->attr.dimension) - { - tmp = transfer_array_component (tmp, c, & code->loc); - gfc_add_expr_to_block (&se->pre, tmp); - } - else - { - if (!c->attr.pointer) - tmp = gfc_build_addr_expr (NULL_TREE, tmp); - transfer_expr (se, &c->ts, tmp, code); - } - } - return; - - default: - internal_error ("Bad IO basetype (%d)", ts->type); - } - - tmp = gfc_build_addr_expr (NULL_TREE, dt_parm); - tmp = build_call_expr_loc (input_location, - function, 3, tmp, addr_expr, arg2); - gfc_add_expr_to_block (&se->pre, tmp); - gfc_add_block_to_block (&se->pre, &se->post); - -} - - -/* Generate a call to pass an array descriptor to the IO library. The - array should be of one of the intrinsic types. */ - -static void -transfer_array_desc (gfc_se * se, gfc_typespec * ts, tree addr_expr) -{ - tree tmp, charlen_arg, kind_arg, io_call; - - if (ts->type == BT_CHARACTER) - charlen_arg = se->string_length; - else - charlen_arg = build_int_cst (gfc_charlen_type_node, 0); - - kind_arg = build_int_cst (integer_type_node, ts->kind); - - tmp = gfc_build_addr_expr (NULL_TREE, dt_parm); - if (last_dt == READ) - io_call = iocall[IOCALL_X_ARRAY]; - else - io_call = iocall[IOCALL_X_ARRAY_WRITE]; - - tmp = build_call_expr_loc (UNKNOWN_LOCATION, - io_call, 4, - tmp, addr_expr, kind_arg, charlen_arg); - gfc_add_expr_to_block (&se->pre, tmp); - gfc_add_block_to_block (&se->pre, &se->post); -} - - -/* gfc_trans_transfer()-- Translate a TRANSFER code node */ - -tree -gfc_trans_transfer (gfc_code * code) -{ - stmtblock_t block, body; - gfc_loopinfo loop; - gfc_expr *expr; - gfc_ref *ref; - gfc_ss *ss; - gfc_se se; - tree tmp; - int n; - - gfc_start_block (&block); - gfc_init_block (&body); - - expr = code->expr1; - ref = NULL; - gfc_init_se (&se, NULL); - - if (expr->rank == 0) - { - /* Transfer a scalar value. */ - gfc_conv_expr_reference (&se, expr); - transfer_expr (&se, &expr->ts, se.expr, code); - } - else - { - /* Transfer an array. If it is an array of an intrinsic - type, pass the descriptor to the library. Otherwise - scalarize the transfer. */ - if (expr->ref && !gfc_is_proc_ptr_comp (expr)) - { - for (ref = expr->ref; ref && ref->type != REF_ARRAY; - ref = ref->next); - gcc_assert (ref && ref->type == REF_ARRAY); - } - - if (expr->ts.type != BT_DERIVED - && ref && ref->next == NULL - && !is_subref_array (expr)) - { - bool seen_vector = false; - - if (ref && ref->u.ar.type == AR_SECTION) - { - for (n = 0; n < ref->u.ar.dimen; n++) - if (ref->u.ar.dimen_type[n] == DIMEN_VECTOR) - seen_vector = true; - } - - if (seen_vector && last_dt == READ) - { - /* Create a temp, read to that and copy it back. */ - gfc_conv_subref_array_arg (&se, expr, 0, INTENT_OUT, false); - tmp = se.expr; - } - else - { - /* Get the descriptor. */ - gfc_conv_expr_descriptor (&se, expr); - tmp = gfc_build_addr_expr (NULL_TREE, se.expr); - } - - transfer_array_desc (&se, &expr->ts, tmp); - goto finish_block_label; - } - - /* Initialize the scalarizer. */ - ss = gfc_walk_expr (expr); - gfc_init_loopinfo (&loop); - gfc_add_ss_to_loop (&loop, ss); - - /* Initialize the loop. */ - gfc_conv_ss_startstride (&loop); - gfc_conv_loop_setup (&loop, &code->expr1->where); - - /* The main loop body. */ - gfc_mark_ss_chain_used (ss, 1); - gfc_start_scalarized_body (&loop, &body); - - gfc_copy_loopinfo_to_se (&se, &loop); - se.ss = ss; - - gfc_conv_expr_reference (&se, expr); - transfer_expr (&se, &expr->ts, se.expr, code); - } - - finish_block_label: - - gfc_add_block_to_block (&body, &se.pre); - gfc_add_block_to_block (&body, &se.post); - - if (se.ss == NULL) - tmp = gfc_finish_block (&body); - else - { - gcc_assert (expr->rank != 0); - gcc_assert (se.ss == gfc_ss_terminator); - gfc_trans_scalarizing_loops (&loop, &body); - - gfc_add_block_to_block (&loop.pre, &loop.post); - tmp = gfc_finish_block (&loop.pre); - gfc_cleanup_loop (&loop); - } - - gfc_add_expr_to_block (&block, tmp); - - return gfc_finish_block (&block); -} - -#include "gt-fortran-trans-io.h" |