trans-io.c 49.2 KB
Newer Older
dnovillo's avatar
 
dnovillo committed
1
/* IO Code translation/library interface
2
   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
dnovillo's avatar
 
dnovillo committed
3 4
   Contributed by Paul Brook

5
This file is part of GCC.
dnovillo's avatar
 
dnovillo committed
6

7 8 9 10
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 2, or (at your option) any later
version.
dnovillo's avatar
 
dnovillo committed
11

12 13 14 15
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.
dnovillo's avatar
 
dnovillo committed
16 17

You should have received a copy of the GNU General Public License
18
along with GCC; see the file COPYING.  If not, write to the Free
kcook's avatar
kcook committed
19 20
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.  */
dnovillo's avatar
 
dnovillo committed
21 22 23 24 25 26


#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
dnovillo's avatar
 
dnovillo committed
27
#include "tree-gimple.h"
dnovillo's avatar
 
dnovillo committed
28 29 30 31 32 33 34 35 36 37 38 39 40
#include "ggc.h"
#include "toplev.h"
#include "real.h"
#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.  */

jakub's avatar
jakub committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
enum ioparam_type
{
  IOPARM_ptype_common,
  IOPARM_ptype_open,
  IOPARM_ptype_close,
  IOPARM_ptype_filepos,
  IOPARM_ptype_inquire,
  IOPARM_ptype_dt,
  IOPARM_ptype_num
};

enum iofield_type
{
  IOPARM_type_int4,
  IOPARM_type_pint4,
  IOPARM_type_pchar,
  IOPARM_type_parray,
  IOPARM_type_pad,
  IOPARM_type_char1,
  IOPARM_type_char2,
  IOPARM_type_common,
  IOPARM_type_num
};

typedef struct gfc_st_parameter_field GTY(())
{
  const char *name;
  unsigned int mask;
  enum ioparam_type param_type;
  enum iofield_type type;
  tree field;
  tree field_len;
}
gfc_st_parameter_field;
dnovillo's avatar
 
dnovillo committed
75

jakub's avatar
jakub committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
typedef struct gfc_st_parameter GTY(())
{
  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 }
};

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, 0, 0, NULL, NULL }
};
dnovillo's avatar
 
dnovillo committed
109 110 111

/* Library I/O subroutines */

jakub's avatar
jakub committed
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
enum iocall
{
  IOCALL_READ,
  IOCALL_READ_DONE,
  IOCALL_WRITE,
  IOCALL_WRITE_DONE,
  IOCALL_X_INTEGER,
  IOCALL_X_LOGICAL,
  IOCALL_X_CHARACTER,
  IOCALL_X_REAL,
  IOCALL_X_COMPLEX,
  IOCALL_X_ARRAY,
  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_NUM
};

static GTY(()) tree iocall[IOCALL_NUM];
dnovillo's avatar
 
dnovillo committed
139 140 141

/* Variable for keeping track of what the last data transfer statement
   was.  Used for deciding which subroutine to call when the data
142
   transfer is complete.  */
pbrook's avatar
pbrook committed
143
static enum { READ, WRITE, IOLENGTH } last_dt;
dnovillo's avatar
 
dnovillo committed
144

jakub's avatar
jakub committed
145 146 147 148
/* 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;
dnovillo's avatar
 
dnovillo committed
149

jakub's avatar
jakub committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
static void
gfc_build_st_parameter (enum ioparam_type ptype, tree *types)
{
  enum iofield type;
  gfc_st_parameter_field *p;
  char name[64];
  size_t len;
  tree t = make_node (RECORD_TYPE);

  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);
  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_pint4:
	case IOPARM_type_parray:
	case IOPARM_type_pchar:
	case IOPARM_type_pad:
	  p->field = gfc_add_field_to_struct (&TYPE_FIELDS (t), t,
					      get_identifier (p->name),
					      types[p->type]);
	  break;
	case IOPARM_type_char1:
	  p->field = gfc_add_field_to_struct (&TYPE_FIELDS (t), t,
					      get_identifier (p->name),
					      pchar_type_node);
	  /* 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 (&TYPE_FIELDS (t), t,
						  get_identifier (name),
						  gfc_charlen_type_node);
	  if (p->type == IOPARM_type_char2)
	    p->field = gfc_add_field_to_struct (&TYPE_FIELDS (t), t,
						get_identifier (p->name),
						pchar_type_node);
	  break;
	case IOPARM_type_common:
	  p->field
	    = gfc_add_field_to_struct (&TYPE_FIELDS (t), t,
				       get_identifier (p->name),
				       st_parameter[IOPARM_ptype_common].type);
	  break;
	case IOPARM_type_num:
	  gcc_unreachable ();
	}
dnovillo's avatar
 
dnovillo committed
206

jakub's avatar
jakub committed
207 208 209
  gfc_finish_type (t);
  st_parameter[ptype].type = t;
}
dnovillo's avatar
 
dnovillo committed
210 211 212 213 214 215

/* Create function decls for IO library functions.  */

void
gfc_build_io_library_fndecls (void)
{
jakub's avatar
jakub committed
216 217
  tree types[IOPARM_type_num], pad_idx, gfc_int4_type_node;
  tree parm_type, dt_parm_type;
jb's avatar
jb committed
218
  tree gfc_c_int_type_node;
jakub's avatar
jakub committed
219 220 221 222 223 224 225 226 227 228 229
  HOST_WIDE_INT pad_size;
  enum ioparam_type ptype;

  types[IOPARM_type_int4] = gfc_int4_type_node = gfc_get_int_type (4);
  types[IOPARM_type_pint4] = build_pointer_type (gfc_int4_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 (build_int_cst (NULL_TREE, pad_size));
  types[IOPARM_type_pad] = build_array_type (char_type_node, pad_idx);
jb's avatar
jb committed
230
  gfc_c_int_type_node = gfc_get_int_type (gfc_c_int_kind);
dnovillo's avatar
 
dnovillo committed
231

jakub's avatar
jakub committed
232 233
  for (ptype = IOPARM_ptype_common; ptype < IOPARM_ptype_num; ptype++)
    gfc_build_st_parameter (ptype, types);
dnovillo's avatar
 
dnovillo committed
234 235 236

  /* Define the transfer functions.  */

jakub's avatar
jakub committed
237 238 239
  dt_parm_type = build_pointer_type (st_parameter[IOPARM_ptype_dt].type);

  iocall[IOCALL_X_INTEGER] =
dnovillo's avatar
 
dnovillo committed
240 241
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_integer")),
jakub's avatar
jakub committed
242 243
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
244

jakub's avatar
jakub committed
245
  iocall[IOCALL_X_LOGICAL] =
dnovillo's avatar
 
dnovillo committed
246 247
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_logical")),
jakub's avatar
jakub committed
248 249
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
250

jakub's avatar
jakub committed
251
  iocall[IOCALL_X_CHARACTER] =
dnovillo's avatar
 
dnovillo committed
252 253
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_character")),
jakub's avatar
jakub committed
254 255
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
256

jakub's avatar
jakub committed
257
  iocall[IOCALL_X_REAL] =
dnovillo's avatar
 
dnovillo committed
258
    gfc_build_library_function_decl (get_identifier (PREFIX("transfer_real")),
jakub's avatar
jakub committed
259
				     void_type_node, 3, dt_parm_type,
dnovillo's avatar
 
dnovillo committed
260 261
				     pvoid_type_node, gfc_int4_type_node);

jakub's avatar
jakub committed
262
  iocall[IOCALL_X_COMPLEX] =
dnovillo's avatar
 
dnovillo committed
263 264
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_complex")),
jakub's avatar
jakub committed
265 266
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
267

jakub's avatar
jakub committed
268
  iocall[IOCALL_X_ARRAY] =
269 270
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_array")),
jakub's avatar
jakub committed
271 272
				     void_type_node, 4, dt_parm_type,
				     pvoid_type_node, gfc_c_int_type_node,
273 274
				     gfc_charlen_type_node);

dnovillo's avatar
 
dnovillo committed
275 276
  /* Library entry points */

jakub's avatar
jakub committed
277
  iocall[IOCALL_READ] =
dnovillo's avatar
 
dnovillo committed
278
    gfc_build_library_function_decl (get_identifier (PREFIX("st_read")),
jakub's avatar
jakub committed
279
				     void_type_node, 1, dt_parm_type);
dnovillo's avatar
 
dnovillo committed
280

jakub's avatar
jakub committed
281
  iocall[IOCALL_WRITE] =
dnovillo's avatar
 
dnovillo committed
282
    gfc_build_library_function_decl (get_identifier (PREFIX("st_write")),
jakub's avatar
jakub committed
283 284 285 286
				     void_type_node, 1, dt_parm_type);

  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_open].type);
  iocall[IOCALL_OPEN] =
dnovillo's avatar
 
dnovillo committed
287
    gfc_build_library_function_decl (get_identifier (PREFIX("st_open")),
jakub's avatar
jakub committed
288
				     void_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
289

jakub's avatar
jakub committed
290 291 292

  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_close].type);
  iocall[IOCALL_CLOSE] =
dnovillo's avatar
 
dnovillo committed
293
    gfc_build_library_function_decl (get_identifier (PREFIX("st_close")),
jakub's avatar
jakub committed
294
				     void_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
295

jakub's avatar
jakub committed
296 297
  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_inquire].type);
  iocall[IOCALL_INQUIRE] =
dnovillo's avatar
 
dnovillo committed
298
    gfc_build_library_function_decl (get_identifier (PREFIX("st_inquire")),
jakub's avatar
jakub committed
299
				     gfc_int4_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
300

jakub's avatar
jakub committed
301
  iocall[IOCALL_IOLENGTH] =
pbrook's avatar
pbrook committed
302
    gfc_build_library_function_decl(get_identifier (PREFIX("st_iolength")),
jakub's avatar
jakub committed
303
				    void_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
304

jakub's avatar
jakub committed
305 306
  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_filepos].type);
  iocall[IOCALL_REWIND] =
dnovillo's avatar
 
dnovillo committed
307
    gfc_build_library_function_decl (get_identifier (PREFIX("st_rewind")),
jakub's avatar
jakub committed
308
				     gfc_int4_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
309

jakub's avatar
jakub committed
310
  iocall[IOCALL_BACKSPACE] =
dnovillo's avatar
 
dnovillo committed
311
    gfc_build_library_function_decl (get_identifier (PREFIX("st_backspace")),
jakub's avatar
jakub committed
312
				     gfc_int4_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
313

jakub's avatar
jakub committed
314
  iocall[IOCALL_ENDFILE] =
dnovillo's avatar
 
dnovillo committed
315
    gfc_build_library_function_decl (get_identifier (PREFIX("st_endfile")),
jakub's avatar
jakub committed
316
				     gfc_int4_type_node, 1, parm_type);
317

jakub's avatar
jakub committed
318
  iocall[IOCALL_FLUSH] =
319
    gfc_build_library_function_decl (get_identifier (PREFIX("st_flush")),
jakub's avatar
jakub committed
320
				     gfc_int4_type_node, 1, parm_type);
321

dnovillo's avatar
 
dnovillo committed
322 323
  /* Library helpers */

jakub's avatar
jakub committed
324
  iocall[IOCALL_READ_DONE] =
dnovillo's avatar
 
dnovillo committed
325
    gfc_build_library_function_decl (get_identifier (PREFIX("st_read_done")),
jakub's avatar
jakub committed
326
				     gfc_int4_type_node, 1, dt_parm_type);
dnovillo's avatar
 
dnovillo committed
327

jakub's avatar
jakub committed
328
  iocall[IOCALL_WRITE_DONE] =
dnovillo's avatar
 
dnovillo committed
329
    gfc_build_library_function_decl (get_identifier (PREFIX("st_write_done")),
jakub's avatar
jakub committed
330
				     gfc_int4_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
331

jakub's avatar
jakub committed
332
  iocall[IOCALL_IOLENGTH_DONE] =
pbrook's avatar
pbrook committed
333
    gfc_build_library_function_decl (get_identifier (PREFIX("st_iolength_done")),
jakub's avatar
jakub committed
334
				     gfc_int4_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
335

dnovillo's avatar
 
dnovillo committed
336

jakub's avatar
jakub committed
337
  iocall[IOCALL_SET_NML_VAL] =
338
    gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var")),
jakub's avatar
jakub committed
339 340 341
				     void_type_node, 6, dt_parm_type,
				     pvoid_type_node, pvoid_type_node,
				     gfc_int4_type_node, gfc_charlen_type_node,
342
				     gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
343

jakub's avatar
jakub committed
344
  iocall[IOCALL_SET_NML_VAL_DIM] =
345
    gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_dim")),
jakub's avatar
jakub committed
346
				     void_type_node, 5, dt_parm_type,
347 348
				     gfc_int4_type_node, gfc_int4_type_node,
				     gfc_int4_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
349 350 351
}


jakub's avatar
jakub committed
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
/* 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 = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		  var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  tmp = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
		NULL_TREE);
  gfc_add_modify_expr (block, tmp, build_int_cst (TREE_TYPE (p->field), val));
  return p->mask;
}


372
/* Generate code to store a non-string I/O parameter into the
jakub's avatar
jakub committed
373
   st_parameter_XXX structure.  This is a pass by value.  */
dnovillo's avatar
 
dnovillo committed
374

jakub's avatar
jakub committed
375 376 377
static unsigned int
set_parameter_value (stmtblock_t *block, tree var, enum iofield type,
		     gfc_expr *e)
dnovillo's avatar
 
dnovillo committed
378 379 380
{
  gfc_se se;
  tree tmp;
jakub's avatar
jakub committed
381
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
382 383

  gfc_init_se (&se, NULL);
jakub's avatar
jakub committed
384
  gfc_conv_expr_type (&se, e, TREE_TYPE (p->field));
dnovillo's avatar
 
dnovillo committed
385 386
  gfc_add_block_to_block (block, &se.pre);

jakub's avatar
jakub committed
387 388 389 390 391
  if (p->param_type == IOPARM_ptype_common)
    var = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		  var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  tmp = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
		NULL_TREE);
dnovillo's avatar
 
dnovillo committed
392
  gfc_add_modify_expr (block, tmp, se.expr);
jakub's avatar
jakub committed
393
  return p->mask;
dnovillo's avatar
 
dnovillo committed
394 395 396
}


397
/* Generate code to store a non-string I/O parameter into the
jakub's avatar
jakub committed
398
   st_parameter_XXX structure.  This is pass by reference.  */
dnovillo's avatar
 
dnovillo committed
399

jakub's avatar
jakub committed
400 401 402
static unsigned int
set_parameter_ref (stmtblock_t *block, stmtblock_t *postblock,
		   tree var, enum iofield type, gfc_expr *e)
dnovillo's avatar
 
dnovillo committed
403 404
{
  gfc_se se;
jakub's avatar
jakub committed
405 406
  tree tmp, addr;
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
407

jakub's avatar
jakub committed
408
  gcc_assert (e->ts.type == BT_INTEGER || e->ts.type == BT_LOGICAL);
dnovillo's avatar
 
dnovillo committed
409
  gfc_init_se (&se, NULL);
jakub's avatar
jakub committed
410
  gfc_conv_expr_lhs (&se, e);
dnovillo's avatar
 
dnovillo committed
411 412 413

  gfc_add_block_to_block (block, &se.pre);

jakub's avatar
jakub committed
414 415 416
  if (TYPE_MODE (TREE_TYPE (se.expr))
      == TYPE_MODE (TREE_TYPE (TREE_TYPE (p->field))))
    addr = convert (TREE_TYPE (p->field),
417
		    build_fold_addr_expr (se.expr));
jakub's avatar
jakub committed
418 419 420 421 422 423 424 425
  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);
426
      addr = build_fold_addr_expr (tmpvar);
jakub's avatar
jakub committed
427 428 429 430 431 432 433 434 435 436 437
      tmp = convert (TREE_TYPE (se.expr), tmpvar);
      gfc_add_modify_expr (postblock, se.expr, tmp);
    }

  if (p->param_type == IOPARM_ptype_common)
    var = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		  var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  tmp = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
		NULL_TREE);
  gfc_add_modify_expr (block, tmp, addr);
  return p->mask;
dnovillo's avatar
 
dnovillo committed
438 439
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
/* 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 tmp;
  tree array;
  tree type;
  tree size;
  int rank;
  gfc_symbol *sym;

  sym = e->symtree->n.sym;
  rank = sym->as->rank - 1;

  if (e->ref->u.ar.type == AR_FULL)
    {
      se->expr = gfc_get_symbol_decl (sym);
      se->expr = gfc_conv_array_data (se->expr);
    }
  else
    {
      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 (MINUS_EXPR, gfc_array_index_type,
		gfc_conv_array_ubound (array, rank),
		gfc_conv_array_lbound (array, rank));
      tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, tmp,
		gfc_index_one_node);
      size = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, size);      
    }

  gcc_assert (size);

  /* If it is an element, we need the its address and size of the rest.  */
  if (e->ref->u.ar.type == AR_ELEMENT)
    {
      size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
		TREE_OPERAND (se->expr, 1));
494
      se->expr = build_fold_addr_expr (se->expr);
495 496 497 498 499 500 501
    }

  tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
  size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, tmp);

  se->string_length = fold_convert (gfc_charlen_type_node, size);
}
dnovillo's avatar
 
dnovillo committed
502

503

dnovillo's avatar
 
dnovillo committed
504
/* Generate code to store a string and its length into the
jakub's avatar
jakub committed
505
   st_parameter_XXX structure.  */
dnovillo's avatar
 
dnovillo committed
506

jakub's avatar
jakub committed
507
static unsigned int
dnovillo's avatar
 
dnovillo committed
508
set_string (stmtblock_t * block, stmtblock_t * postblock, tree var,
jakub's avatar
jakub committed
509
	    enum iofield type, gfc_expr * e)
dnovillo's avatar
 
dnovillo committed
510 511 512 513 514 515
{
  gfc_se se;
  tree tmp;
  tree msg;
  tree io;
  tree len;
jakub's avatar
jakub committed
516
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
517 518 519

  gfc_init_se (&se, NULL);

jakub's avatar
jakub committed
520 521 522 523 524 525
  if (p->param_type == IOPARM_ptype_common)
    var = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		  var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  io = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
	       NULL_TREE);
  len = build3 (COMPONENT_REF, TREE_TYPE (p->field_len), var, p->field_len,
526
		NULL_TREE);
dnovillo's avatar
 
dnovillo committed
527

528
  /* Integer variable assigned a format label.  */
dnovillo's avatar
 
dnovillo committed
529 530
  if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1)
    {
fengwang's avatar
fengwang committed
531
      gfc_conv_label_variable (&se, e);
dnovillo's avatar
 
dnovillo committed
532
      msg =
533
        gfc_build_cstring_const ("Assigned label is not a format label");
dnovillo's avatar
 
dnovillo committed
534
      tmp = GFC_DECL_STRING_LEN (se.expr);
535 536
      tmp = build2 (LE_EXPR, boolean_type_node,
		    tmp, convert (TREE_TYPE (tmp), integer_minus_one_node));
dnovillo's avatar
 
dnovillo committed
537
      gfc_trans_runtime_check (tmp, msg, &se.pre);
538 539
      gfc_add_modify_expr (&se.pre, io,
		 fold_convert (TREE_TYPE (io), GFC_DECL_ASSIGN_ADDR (se.expr)));
dnovillo's avatar
 
dnovillo committed
540 541 542 543
      gfc_add_modify_expr (&se.pre, len, GFC_DECL_STRING_LEN (se.expr));
    }
  else
    {
544 545 546 547 548 549 550 551 552
      /* 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->symtree && (e->symtree->n.sym->as->rank > 0))
	gfc_convert_array_to_string (&se, e);
      else
	gcc_unreachable ();

dnovillo's avatar
 
dnovillo committed
553
      gfc_conv_string_parameter (&se);
554
      gfc_add_modify_expr (&se.pre, io, fold_convert (TREE_TYPE (io), se.expr));
dnovillo's avatar
 
dnovillo committed
555 556 557 558 559
      gfc_add_modify_expr (&se.pre, len, se.string_length);
    }

  gfc_add_block_to_block (block, &se.pre);
  gfc_add_block_to_block (postblock, &se.post);
jakub's avatar
jakub committed
560
  return p->mask;
dnovillo's avatar
 
dnovillo committed
561 562 563
}


564 565 566
/* Generate code to store the character (array) and the character length
   for an internal unit.  */

jakub's avatar
jakub committed
567 568
static unsigned int
set_internal_unit (stmtblock_t * block, tree var, gfc_expr * e)
569 570 571 572 573 574
{
  gfc_se se;
  tree io;
  tree len;
  tree desc;
  tree tmp;
jakub's avatar
jakub committed
575 576
  gfc_st_parameter_field *p;
  unsigned int mask;
577 578 579

  gfc_init_se (&se, NULL);

jakub's avatar
jakub committed
580 581 582 583 584
  p = &st_parameter_field[IOPARM_dt_internal_unit];
  mask = p->mask;
  io = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
	       NULL_TREE);
  len = build3 (COMPONENT_REF, TREE_TYPE (p->field_len), var, p->field_len,
585
		NULL_TREE);
jakub's avatar
jakub committed
586 587
  p = &st_parameter_field[IOPARM_dt_internal_unit_desc];
  desc = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		 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 = fold_convert (pchar_type_node, integer_zero_node);
    }

  /* Character array.  */
  else if (e->symtree && (e->symtree->n.sym->as->rank > 0))
    {
      se.ss = gfc_walk_expr (e);

      /* Return the data pointer and rank from the descriptor.  */
      gfc_conv_expr_descriptor (&se, e, se.ss);
      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_expr (&se.pre, io, fold_convert (TREE_TYPE (io), tmp));
  gfc_add_modify_expr (&se.pre, len, se.string_length);
  gfc_add_modify_expr (&se.pre, desc, se.expr);

  gfc_add_block_to_block (block, &se.pre);
jakub's avatar
jakub committed
621
  return mask;
622 623
}

dnovillo's avatar
 
dnovillo committed
624 625 626 627 628 629 630 631 632 633
/* 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 */

634
  value = build_int_cst (NULL_TREE, label_value);
dnovillo's avatar
 
dnovillo committed
635 636

  /* Make a backend label for this case.  */
637
  tmp = gfc_build_label_decl (NULL_TREE);
dnovillo's avatar
 
dnovillo committed
638 639

  /* And the case itself.  */
640
  tmp = build3_v (CASE_LABEL_EXPR, value, NULL_TREE, tmp);
dnovillo's avatar
 
dnovillo committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
  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
jakub's avatar
jakub committed
656
io_result (stmtblock_t * block, tree var, gfc_st_label * err_label,
dnovillo's avatar
 
dnovillo committed
657 658 659 660
	   gfc_st_label * end_label, gfc_st_label * eor_label)
{
  stmtblock_t body;
  tree tmp, rc;
jakub's avatar
jakub committed
661
  gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_flags];
dnovillo's avatar
 
dnovillo committed
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680

  /* 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);

jakub's avatar
jakub committed
681 682 683 684 685 686
  var = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  rc = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
	       NULL_TREE);
  rc = build2 (BIT_AND_EXPR, TREE_TYPE (rc), rc,
	       build_int_cst (TREE_TYPE (rc), IOPARM_common_libreturn_mask));
dnovillo's avatar
 
dnovillo committed
687

688
  tmp = build3_v (SWITCH_EXPR, rc, tmp, NULL_TREE);
dnovillo's avatar
 
dnovillo committed
689 690 691 692 693 694 695 696 697

  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
jakub's avatar
jakub committed
698
set_error_locus (stmtblock_t * block, tree var, locus * where)
dnovillo's avatar
 
dnovillo committed
699 700
{
  gfc_file *f;
jakub's avatar
jakub committed
701
  tree str, locus_file;
dnovillo's avatar
 
dnovillo committed
702
  int line;
jakub's avatar
jakub committed
703
  gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_filename];
dnovillo's avatar
 
dnovillo committed
704

jakub's avatar
jakub committed
705 706 707 708
  locus_file = build3 (COMPONENT_REF, st_parameter[IOPARM_ptype_common].type,
		       var, TYPE_FIELDS (TREE_TYPE (var)), NULL_TREE);
  locus_file = build3 (COMPONENT_REF, TREE_TYPE (p->field), locus_file,
		       p->field, NULL_TREE);
tobi's avatar
tobi committed
709
  f = where->lb->file;
jakub's avatar
jakub committed
710
  str = gfc_build_cstring_const (f->filename);
dnovillo's avatar
 
dnovillo committed
711

jakub's avatar
jakub committed
712 713
  str = gfc_build_addr_expr (pchar_type_node, str);
  gfc_add_modify_expr (block, locus_file, str);
dnovillo's avatar
 
dnovillo committed
714

715 716 717
#ifdef USE_MAPPED_LOCATION
  line = LOCATION_LINE (where->lb->location);
#else
tobi's avatar
tobi committed
718
  line = where->lb->linenum;
719
#endif
jakub's avatar
jakub committed
720
  set_parameter_const (block, var, IOPARM_common_line, line);
dnovillo's avatar
 
dnovillo committed
721 722 723 724 725 726 727 728 729 730
}


/* Translate an OPEN statement.  */

tree
gfc_trans_open (gfc_code * code)
{
  stmtblock_t block, post_block;
  gfc_open *p;
jakub's avatar
jakub committed
731 732
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
733

jakub's avatar
jakub committed
734
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
735 736
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
737 738 739
  var = gfc_create_var (st_parameter[IOPARM_ptype_open].type, "open_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
740 741 742
  p = code->ext.open;

  if (p->unit)
jakub's avatar
jakub committed
743 744 745
    set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
746 747

  if (p->file)
jakub's avatar
jakub committed
748
    mask |= set_string (&block, &post_block, var, IOPARM_open_file, p->file);
dnovillo's avatar
 
dnovillo committed
749 750

  if (p->status)
jakub's avatar
jakub committed
751 752
    mask |= set_string (&block, &post_block, var, IOPARM_open_status,
			p->status);
dnovillo's avatar
 
dnovillo committed
753 754

  if (p->access)
jakub's avatar
jakub committed
755 756
    mask |= set_string (&block, &post_block, var, IOPARM_open_access,
			p->access);
dnovillo's avatar
 
dnovillo committed
757 758

  if (p->form)
jakub's avatar
jakub committed
759
    mask |= set_string (&block, &post_block, var, IOPARM_open_form, p->form);
dnovillo's avatar
 
dnovillo committed
760 761

  if (p->recl)
jakub's avatar
jakub committed
762
    mask |= set_parameter_value (&block, var, IOPARM_open_recl_in, p->recl);
dnovillo's avatar
 
dnovillo committed
763 764

  if (p->blank)
jakub's avatar
jakub committed
765 766
    mask |= set_string (&block, &post_block, var, IOPARM_open_blank,
			p->blank);
dnovillo's avatar
 
dnovillo committed
767 768

  if (p->position)
jakub's avatar
jakub committed
769 770
    mask |= set_string (&block, &post_block, var, IOPARM_open_position,
			p->position);
dnovillo's avatar
 
dnovillo committed
771 772

  if (p->action)
jakub's avatar
jakub committed
773 774
    mask |= set_string (&block, &post_block, var, IOPARM_open_action,
			p->action);
dnovillo's avatar
 
dnovillo committed
775 776

  if (p->delim)
jakub's avatar
jakub committed
777 778
    mask |= set_string (&block, &post_block, var, IOPARM_open_delim,
			p->delim);
dnovillo's avatar
 
dnovillo committed
779 780

  if (p->pad)
jakub's avatar
jakub committed
781
    mask |= set_string (&block, &post_block, var, IOPARM_open_pad, p->pad);
dnovillo's avatar
 
dnovillo committed
782

783
  if (p->iomsg)
jakub's avatar
jakub committed
784 785
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
786

dnovillo's avatar
 
dnovillo committed
787
  if (p->iostat)
jakub's avatar
jakub committed
788 789
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
790 791

  if (p->err)
jakub's avatar
jakub committed
792
    mask |= IOPARM_common_err;
dnovillo's avatar
 
dnovillo committed
793

794 795 796 797
  if (p->convert)
    mask |= set_string (&block, &post_block, var, IOPARM_open_convert,
			p->convert);

jakub's avatar
jakub committed
798 799
  set_parameter_const (&block, var, IOPARM_common_flags, mask);

800
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
801 802
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (iocall[IOCALL_OPEN], tmp);
dnovillo's avatar
 
dnovillo committed
803 804 805 806
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
807
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
808 809 810 811 812 813 814 815 816 817 818 819

  return gfc_finish_block (&block);
}


/* Translate a CLOSE statement.  */

tree
gfc_trans_close (gfc_code * code)
{
  stmtblock_t block, post_block;
  gfc_close *p;
jakub's avatar
jakub committed
820 821
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
822

jakub's avatar
jakub committed
823
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
824 825
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
826 827 828
  var = gfc_create_var (st_parameter[IOPARM_ptype_close].type, "close_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
829 830 831
  p = code->ext.close;

  if (p->unit)
jakub's avatar
jakub committed
832 833 834
    set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
835 836

  if (p->status)
jakub's avatar
jakub committed
837 838
    mask |= set_string (&block, &post_block, var, IOPARM_close_status,
			p->status);
dnovillo's avatar
 
dnovillo committed
839

840
  if (p->iomsg)
jakub's avatar
jakub committed
841 842
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
843

dnovillo's avatar
 
dnovillo committed
844
  if (p->iostat)
jakub's avatar
jakub committed
845 846
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
847 848

  if (p->err)
jakub's avatar
jakub committed
849 850 851
    mask |= IOPARM_common_err;

  set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
852

853
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
854 855
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (iocall[IOCALL_CLOSE], tmp);
dnovillo's avatar
 
dnovillo committed
856 857 858 859
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
860
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
861 862 863 864 865 866 867 868 869 870

  return gfc_finish_block (&block);
}


/* Common subroutine for building a file positioning statement.  */

static tree
build_filepos (tree function, gfc_code * code)
{
871
  stmtblock_t block, post_block;
dnovillo's avatar
 
dnovillo committed
872
  gfc_filepos *p;
jakub's avatar
jakub committed
873 874
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
875 876 877

  p = code->ext.filepos;

jakub's avatar
jakub committed
878
  gfc_start_block (&block);
879
  gfc_init_block (&post_block);
dnovillo's avatar
 
dnovillo committed
880

jakub's avatar
jakub committed
881 882 883 884
  var = gfc_create_var (st_parameter[IOPARM_ptype_filepos].type,
			"filepos_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
885 886

  if (p->unit)
jakub's avatar
jakub committed
887 888 889
    set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
890

891
  if (p->iomsg)
jakub's avatar
jakub committed
892 893
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
894

dnovillo's avatar
 
dnovillo committed
895
  if (p->iostat)
jakub's avatar
jakub committed
896 897
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
898 899

  if (p->err)
jakub's avatar
jakub committed
900 901 902
    mask |= IOPARM_common_err;

  set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
903

904
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
905 906
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (function, tmp);
dnovillo's avatar
 
dnovillo committed
907 908
  gfc_add_expr_to_block (&block, tmp);

909 910
  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
911
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
912 913 914 915 916 917 918 919 920 921

  return gfc_finish_block (&block);
}


/* Translate a BACKSPACE statement.  */

tree
gfc_trans_backspace (gfc_code * code)
{
jakub's avatar
jakub committed
922
  return build_filepos (iocall[IOCALL_BACKSPACE], code);
dnovillo's avatar
 
dnovillo committed
923 924 925 926 927 928 929 930
}


/* Translate an ENDFILE statement.  */

tree
gfc_trans_endfile (gfc_code * code)
{
jakub's avatar
jakub committed
931
  return build_filepos (iocall[IOCALL_ENDFILE], code);
dnovillo's avatar
 
dnovillo committed
932 933 934 935 936 937 938 939
}


/* Translate a REWIND statement.  */

tree
gfc_trans_rewind (gfc_code * code)
{
jakub's avatar
jakub committed
940
  return build_filepos (iocall[IOCALL_REWIND], code);
dnovillo's avatar
 
dnovillo committed
941 942 943
}


944 945 946 947 948
/* Translate a FLUSH statement.  */

tree
gfc_trans_flush (gfc_code * code)
{
jakub's avatar
jakub committed
949
  return build_filepos (iocall[IOCALL_FLUSH], code);
950 951 952
}


dnovillo's avatar
 
dnovillo committed
953 954 955 956 957 958 959
/* Translate the non-IOLENGTH form of an INQUIRE statement.  */

tree
gfc_trans_inquire (gfc_code * code)
{
  stmtblock_t block, post_block;
  gfc_inquire *p;
jakub's avatar
jakub committed
960 961
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
962

jakub's avatar
jakub committed
963
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
964 965
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
966 967 968 969
  var = gfc_create_var (st_parameter[IOPARM_ptype_inquire].type,
			"inquire_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
970 971
  p = code->ext.inquire;

972 973 974 975
  /* Sanity check.  */
  if (p->unit && p->file)
    gfc_error ("INQUIRE statement at %L cannot contain both FILE and UNIT specifiers.", &code->loc);

dnovillo's avatar
 
dnovillo committed
976
  if (p->unit)
jakub's avatar
jakub committed
977 978 979
    set_parameter_value (&block, var, IOPARM_common_unit, p->unit);
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
980 981

  if (p->file)
jakub's avatar
jakub committed
982 983
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_file,
			p->file);
dnovillo's avatar
 
dnovillo committed
984

985
  if (p->iomsg)
jakub's avatar
jakub committed
986 987
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
988

dnovillo's avatar
 
dnovillo committed
989
  if (p->iostat)
jakub's avatar
jakub committed
990 991
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
992 993

  if (p->exist)
jakub's avatar
jakub committed
994 995
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_exist,
			       p->exist);
dnovillo's avatar
 
dnovillo committed
996 997

  if (p->opened)
jakub's avatar
jakub committed
998 999
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_opened,
			       p->opened);
dnovillo's avatar
 
dnovillo committed
1000 1001

  if (p->number)
jakub's avatar
jakub committed
1002 1003
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_number,
			       p->number);
dnovillo's avatar
 
dnovillo committed
1004 1005

  if (p->named)
jakub's avatar
jakub committed
1006 1007
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_inquire_named,
			       p->named);
dnovillo's avatar
 
dnovillo committed
1008 1009

  if (p->name)
jakub's avatar
jakub committed
1010 1011
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_name,
			p->name);
dnovillo's avatar
 
dnovillo committed
1012 1013

  if (p->access)
jakub's avatar
jakub committed
1014 1015
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_access,
			p->access);
dnovillo's avatar
 
dnovillo committed
1016 1017

  if (p->sequential)
jakub's avatar
jakub committed
1018 1019
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_sequential,
			p->sequential);
dnovillo's avatar
 
dnovillo committed
1020 1021

  if (p->direct)
jakub's avatar
jakub committed
1022 1023
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_direct,
			p->direct);
dnovillo's avatar
 
dnovillo committed
1024 1025

  if (p->form)
jakub's avatar
jakub committed
1026 1027
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_form,
			p->form);
dnovillo's avatar
 
dnovillo committed
1028 1029

  if (p->formatted)
jakub's avatar
jakub committed
1030 1031
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_formatted,
			p->formatted);
dnovillo's avatar
 
dnovillo committed
1032 1033

  if (p->unformatted)
jakub's avatar
jakub committed
1034 1035
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_unformatted,
			p->unformatted);
dnovillo's avatar
 
dnovillo committed
1036 1037

  if (p->recl)
jakub's avatar
jakub committed
1038 1039
    mask |= set_parameter_ref (&block, &post_block, var,
			       IOPARM_inquire_recl_out, p->recl);
dnovillo's avatar
 
dnovillo committed
1040 1041

  if (p->nextrec)
jakub's avatar
jakub committed
1042 1043
    mask |= set_parameter_ref (&block, &post_block, var,
			       IOPARM_inquire_nextrec, p->nextrec);
dnovillo's avatar
 
dnovillo committed
1044 1045

  if (p->blank)
jakub's avatar
jakub committed
1046 1047
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_blank,
			p->blank);
dnovillo's avatar
 
dnovillo committed
1048 1049

  if (p->position)
jakub's avatar
jakub committed
1050 1051
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_position,
			p->position);
dnovillo's avatar
 
dnovillo committed
1052 1053

  if (p->action)
jakub's avatar
jakub committed
1054 1055
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_action,
			p->action);
dnovillo's avatar
 
dnovillo committed
1056 1057

  if (p->read)
jakub's avatar
jakub committed
1058 1059
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_read,
			p->read);
dnovillo's avatar
 
dnovillo committed
1060 1061

  if (p->write)
jakub's avatar
jakub committed
1062 1063
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_write,
			p->write);
dnovillo's avatar
 
dnovillo committed
1064 1065

  if (p->readwrite)
jakub's avatar
jakub committed
1066 1067
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_readwrite,
			p->readwrite);
dnovillo's avatar
 
dnovillo committed
1068 1069

  if (p->delim)
jakub's avatar
jakub committed
1070 1071
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_delim,
			p->delim);
dnovillo's avatar
 
dnovillo committed
1072

1073
  if (p->pad)
jakub's avatar
jakub committed
1074 1075
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_pad,
			p->pad);
1076

dnovillo's avatar
 
dnovillo committed
1077
  if (p->err)
jakub's avatar
jakub committed
1078 1079
    mask |= IOPARM_common_err;

1080 1081 1082 1083
  if (p->convert)
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_convert,
			p->convert);

jakub's avatar
jakub committed
1084
  set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
1085

1086
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
1087 1088
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (iocall[IOCALL_INQUIRE], tmp);
dnovillo's avatar
 
dnovillo committed
1089 1090 1091 1092
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
1093
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
1094 1095 1096 1097 1098

  return gfc_finish_block (&block);
}

static gfc_expr *
1099
gfc_new_nml_name_expr (const char * name)
dnovillo's avatar
 
dnovillo committed
1100 1101
{
   gfc_expr * nml_name;
1102

dnovillo's avatar
 
dnovillo committed
1103 1104 1105
   nml_name = gfc_get_expr();
   nml_name->ref = NULL;
   nml_name->expr_type = EXPR_CONSTANT;
1106
   nml_name->ts.kind = gfc_default_character_kind;
dnovillo's avatar
 
dnovillo committed
1107 1108
   nml_name->ts.type = BT_CHARACTER;
   nml_name->value.character.length = strlen(name);
1109 1110
   nml_name->value.character.string = gfc_getmem (strlen (name) + 1);
   strcpy (nml_name->value.character.string, name);
dnovillo's avatar
 
dnovillo committed
1111 1112 1113 1114

   return nml_name;
}

1115 1116 1117 1118 1119
/* 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)
dnovillo's avatar
 
dnovillo committed
1120
{
1121 1122 1123 1124 1125 1126 1127 1128 1129
  int full_name_length;
  char * full_name;

  full_name_length = strlen (var_name) + strlen (cmp_name) + 1;
  full_name = (char*)gfc_getmem (full_name_length + 1);
  strcpy (full_name, var_name);
  full_name = strcat (full_name, "%");
  full_name = strcat (full_name, cmp_name);
  return full_name;
dnovillo's avatar
 
dnovillo committed
1130 1131
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
/* 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;
  tree itmp;
  int array_flagged;
  int dummy_arg_flagged;

  if (sym)
    {
      sym->attr.referenced = 1;
      decl = gfc_get_symbol_decl (sym);
    }
  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.  */

  dummy_arg_flagged = POINTER_TYPE_P (TREE_TYPE(tmp));

1167
  itmp = (dummy_arg_flagged) ? build_fold_indirect_ref (tmp) : tmp;
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193

  /* If an array, set flag and use indirect ref. if built.  */

  array_flagged = (TREE_CODE (TREE_TYPE (itmp)) == ARRAY_TYPE
		   && !TYPE_STRING_FLAG (TREE_TYPE (itmp)));

  if (array_flagged)
    tmp = itmp;

  /* Treat the component of a derived type, using base_addr for
     the derived type.  */

  if (TREE_CODE (decl) == FIELD_DECL)
    tmp = build3 (COMPONENT_REF, TREE_TYPE (tmp),
		  base_addr, tmp, NULL_TREE);

  /* If we have a derived type component, a reference to the first
     element of the array is built.  This is done so that base_addr,
     used in the build of the component reference, always points to
     a RECORD_TYPE.  */

  if (array_flagged)
    tmp = gfc_build_array_ref (tmp, gfc_index_zero_node);

  /* Now build the address expression.  */

1194
  tmp = build_fold_addr_expr (tmp);
1195 1196 1197 1198

  /* If scalar dummy, resolve indirect reference now.  */

  if (dummy_arg_flagged && !array_flagged)
1199
    tmp = build_fold_indirect_ref (tmp);
1200 1201 1202 1203 1204

  gcc_assert (tmp && POINTER_TYPE_P (TREE_TYPE (tmp)));

  return tmp;
}
1205

1206
/* For an object VAR_NAME whose base address is BASE_ADDR, generate a
jakub's avatar
jakub committed
1207 1208
   call to iocall[IOCALL_SET_NML_VAL].  For derived type variable, recursively
   generate calls to iocall[IOCALL_SET_NML_VAL] for each component.  */
1209

1210 1211 1212
#define NML_FIRST_ARG(a) args = gfc_chainon_list (NULL_TREE, a)
#define NML_ADD_ARG(a) args = gfc_chainon_list (args, a)
#define IARG(i) build_int_cst (gfc_array_index_type, i)
1213 1214

static void
1215 1216 1217
transfer_namelist_element (stmtblock_t * block, const char * var_name,
			   gfc_symbol * sym, gfc_component * c,
			   tree base_addr)
1218
{
1219 1220 1221 1222 1223 1224 1225 1226
  gfc_typespec * ts = NULL;
  gfc_array_spec * as = NULL;
  tree addr_expr = NULL;
  tree dt = NULL;
  tree string;
  tree tmp;
  tree args;
  tree dtype;
jakub's avatar
jakub committed
1227
  tree dt_parm_addr;
1228 1229 1230
  int n_dim; 
  int itype;
  int rank = 0;
1231

1232
  gcc_assert (sym || c);
1233

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
  /* 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)
1250
    {
1251 1252
      dt =  TREE_TYPE ((sym) ? sym->backend_decl : c->backend_decl);
      dtype = gfc_get_dtype (dt);
1253
    }
1254 1255 1256
  else
    {
      itype = GFC_DTYPE_UNKNOWN;
1257

1258
      switch (ts->type)
1259

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
	{
	case BT_INTEGER:
	  itype = GFC_DTYPE_INTEGER;
	  break;
	case BT_LOGICAL:
	  itype = GFC_DTYPE_LOGICAL;
	  break;
	case BT_REAL:
	  itype = GFC_DTYPE_REAL;
	  break;
	case BT_COMPLEX:
	  itype = GFC_DTYPE_COMPLEX;
	break;
	case BT_DERIVED:
	  itype = GFC_DTYPE_DERIVED;
	  break;
	case BT_CHARACTER:
	  itype = GFC_DTYPE_CHARACTER;
	  break;
	default:
	  gcc_unreachable ();
	}

      dtype = IARG (itype << GFC_DTYPE_TYPE_SHIFT);
1284 1285
    }

1286 1287 1288 1289
  /* Build up the arguments for the transfer call.
     The call for the scalar part transfers:
     (address, name, type, kind or string_length, dtype)  */

1290
  dt_parm_addr = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1291 1292
  NML_FIRST_ARG (dt_parm_addr);
  NML_ADD_ARG (addr_expr);
1293 1294 1295 1296 1297 1298 1299 1300 1301
  NML_ADD_ARG (string);
  NML_ADD_ARG (IARG (ts->kind));

  if (ts->type == BT_CHARACTER)
    NML_ADD_ARG (ts->cl->backend_decl);
  else
    NML_ADD_ARG (convert (gfc_charlen_type_node, integer_zero_node));

  NML_ADD_ARG (dtype);
jakub's avatar
jakub committed
1302
  tmp = gfc_build_function_call (iocall[IOCALL_SET_NML_VAL], args);
1303
  gfc_add_expr_to_block (block, tmp);
1304 1305 1306 1307 1308 1309

  /* If the object is an array, transfer rank times:
     (null pointer, name, stride, lbound, ubound)  */

  for ( n_dim = 0 ; n_dim < rank ; n_dim++ )
    {
jakub's avatar
jakub committed
1310 1311
      NML_FIRST_ARG (dt_parm_addr);
      NML_ADD_ARG (IARG (n_dim));
1312 1313 1314
      NML_ADD_ARG (GFC_TYPE_ARRAY_STRIDE (dt, n_dim));
      NML_ADD_ARG (GFC_TYPE_ARRAY_LBOUND (dt, n_dim));
      NML_ADD_ARG (GFC_TYPE_ARRAY_UBOUND (dt, n_dim));
jakub's avatar
jakub committed
1315
      tmp = gfc_build_function_call (iocall[IOCALL_SET_NML_VAL_DIM], args);
1316 1317 1318 1319 1320 1321 1322 1323 1324
      gfc_add_expr_to_block (block, tmp);
    }

  if (ts->type == BT_DERIVED)
    {
      gfc_component *cmp;

      /* Provide the RECORD_TYPE to build component references.  */

1325
      tree expr = build_fold_indirect_ref (addr_expr);
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335

      for (cmp = ts->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);
	  gfc_free (full_name);
	}
    }
1336
}
dnovillo's avatar
 
dnovillo committed
1337

1338 1339 1340 1341
#undef IARG
#undef NML_ADD_ARG
#undef NML_FIRST_ARG

dnovillo's avatar
 
dnovillo committed
1342 1343 1344 1345 1346
/* 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
jakub's avatar
jakub committed
1347
build_dt (tree function, gfc_code * code)
dnovillo's avatar
 
dnovillo committed
1348
{
jakub's avatar
jakub committed
1349
  stmtblock_t block, post_block, post_end_block;
dnovillo's avatar
 
dnovillo committed
1350
  gfc_dt *dt;
jakub's avatar
jakub committed
1351
  tree tmp, var;
1352
  gfc_expr *nmlname;
1353
  gfc_namelist *nml;
jakub's avatar
jakub committed
1354
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
1355

jakub's avatar
jakub committed
1356
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
1357
  gfc_init_block (&post_block);
jakub's avatar
jakub committed
1358 1359 1360 1361 1362
  gfc_init_block (&post_end_block);

  var = gfc_create_var (st_parameter[IOPARM_ptype_dt].type, "dt_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
1363

jakub's avatar
jakub committed
1364 1365 1366 1367 1368
  if (last_dt == IOLENGTH)
    {
      gfc_inquire *inq;

      inq = code->ext.inquire;
dnovillo's avatar
 
dnovillo committed
1369

jakub's avatar
jakub committed
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
      /* 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);
    }
pbrook's avatar
pbrook committed
1384

jakub's avatar
jakub committed
1385
  if (dt && dt->io_unit)
dnovillo's avatar
 
dnovillo committed
1386 1387 1388
    {
      if (dt->io_unit->ts.type == BT_CHARACTER)
	{
jakub's avatar
jakub committed
1389 1390
	  mask |= set_internal_unit (&block, var, dt->io_unit);
	  set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
1391 1392
	}
      else
jakub's avatar
jakub committed
1393
	set_parameter_value (&block, var, IOPARM_common_unit, dt->io_unit);
dnovillo's avatar
 
dnovillo committed
1394
    }
jakub's avatar
jakub committed
1395 1396
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
1397

jakub's avatar
jakub committed
1398 1399 1400 1401
  if (dt)
    {
      if (dt->rec)
	mask |= set_parameter_value (&block, var, IOPARM_dt_rec, dt->rec);
dnovillo's avatar
 
dnovillo committed
1402

jakub's avatar
jakub committed
1403 1404 1405
      if (dt->advance)
	mask |= set_string (&block, &post_block, var, IOPARM_dt_advance,
			    dt->advance);
dnovillo's avatar
 
dnovillo committed
1406

jakub's avatar
jakub committed
1407 1408 1409
      if (dt->format_expr)
	mask |= set_string (&block, &post_block, var, IOPARM_dt_format,
			    dt->format_expr);
dnovillo's avatar
 
dnovillo committed
1410

jakub's avatar
jakub committed
1411 1412 1413 1414 1415 1416 1417 1418
      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);
	}
dnovillo's avatar
 
dnovillo committed
1419

jakub's avatar
jakub committed
1420 1421 1422
      if (dt->iomsg)
	mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			    dt->iomsg);
1423

jakub's avatar
jakub committed
1424 1425 1426
      if (dt->iostat)
	mask |= set_parameter_ref (&block, &post_end_block, var,
				   IOPARM_common_iostat, dt->iostat);
dnovillo's avatar
 
dnovillo committed
1427

jakub's avatar
jakub committed
1428 1429 1430
      if (dt->size)
	mask |= set_parameter_ref (&block, &post_end_block, var,
				   IOPARM_dt_size, dt->size);
dnovillo's avatar
 
dnovillo committed
1431

jakub's avatar
jakub committed
1432 1433
      if (dt->err)
	mask |= IOPARM_common_err;
dnovillo's avatar
 
dnovillo committed
1434

jakub's avatar
jakub committed
1435 1436
      if (dt->eor)
	mask |= IOPARM_common_eor;
dnovillo's avatar
 
dnovillo committed
1437

jakub's avatar
jakub committed
1438 1439
      if (dt->end)
	mask |= IOPARM_common_end;
dnovillo's avatar
 
dnovillo committed
1440

jakub's avatar
jakub committed
1441 1442 1443 1444 1445 1446
      if (dt->namelist)
	{
	  if (dt->format_expr || dt->format_label)
	    gfc_internal_error ("build_dt: format with namelist");

	  nmlname = gfc_new_nml_name_expr (dt->namelist->name);
1447

jakub's avatar
jakub committed
1448 1449
	  mask |= set_string (&block, &post_block, var, IOPARM_dt_namelist_name,
			      nmlname);
1450

jakub's avatar
jakub committed
1451 1452
	  if (last_dt == READ)
	    mask |= IOPARM_dt_namelist_read_mode;
1453

jakub's avatar
jakub committed
1454
	  set_parameter_const (&block, var, IOPARM_common_flags, mask);
1455

jakub's avatar
jakub committed
1456 1457 1458 1459 1460 1461 1462 1463
	  dt_parm = var;

	  for (nml = dt->namelist->namelist; nml; nml = nml->next)
	    transfer_namelist_element (&block, nml->sym->name, nml->sym,
				       NULL, NULL);
	}
      else
	set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
1464
    }
jakub's avatar
jakub committed
1465 1466
  else
    set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
1467

1468
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
1469 1470
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (function, tmp);
dnovillo's avatar
 
dnovillo committed
1471 1472 1473 1474
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
1475 1476 1477 1478 1479 1480 1481 1482
  dt_parm = var;
  dt_post_end_block = &post_end_block;

  gfc_add_expr_to_block (&block, gfc_trans_code (code->block->next));

  dt_parm = NULL;
  dt_post_end_block = NULL;

dnovillo's avatar
 
dnovillo committed
1483 1484 1485 1486
  return gfc_finish_block (&block);
}


pbrook's avatar
pbrook committed
1487 1488
/* Translate the IOLENGTH form of an INQUIRE statement.  We treat
   this as a third sort of data transfer statement, except that
1489
   lengths are summed instead of actually transferring any data.  */
pbrook's avatar
pbrook committed
1490 1491 1492 1493 1494

tree
gfc_trans_iolength (gfc_code * code)
{
  last_dt = IOLENGTH;
jakub's avatar
jakub committed
1495
  return build_dt (iocall[IOCALL_IOLENGTH], code);
pbrook's avatar
pbrook committed
1496 1497 1498
}


dnovillo's avatar
 
dnovillo committed
1499 1500 1501 1502 1503 1504
/* Translate a READ statement.  */

tree
gfc_trans_read (gfc_code * code)
{
  last_dt = READ;
jakub's avatar
jakub committed
1505
  return build_dt (iocall[IOCALL_READ], code);
dnovillo's avatar
 
dnovillo committed
1506 1507 1508 1509 1510 1511 1512 1513 1514
}


/* Translate a WRITE statement */

tree
gfc_trans_write (gfc_code * code)
{
  last_dt = WRITE;
jakub's avatar
jakub committed
1515
  return build_dt (iocall[IOCALL_WRITE], code);
dnovillo's avatar
 
dnovillo committed
1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
}


/* Finish a data transfer statement.  */

tree
gfc_trans_dt_end (gfc_code * code)
{
  tree function, tmp;
  stmtblock_t block;

  gfc_init_block (&block);

pbrook's avatar
pbrook committed
1529 1530 1531
  switch (last_dt)
    {
    case READ:
jakub's avatar
jakub committed
1532
      function = iocall[IOCALL_READ_DONE];
pbrook's avatar
pbrook committed
1533 1534 1535
      break;

    case WRITE:
jakub's avatar
jakub committed
1536
      function = iocall[IOCALL_WRITE_DONE];
pbrook's avatar
pbrook committed
1537 1538 1539
      break;

    case IOLENGTH:
jakub's avatar
jakub committed
1540
      function = iocall[IOCALL_IOLENGTH_DONE];
pbrook's avatar
pbrook committed
1541 1542 1543
      break;

    default:
pbrook's avatar
pbrook committed
1544
      gcc_unreachable ();
pbrook's avatar
pbrook committed
1545
    }
dnovillo's avatar
 
dnovillo committed
1546

1547
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1548 1549
  tmp = gfc_chainon_list (NULL_TREE, tmp);
  tmp = gfc_build_function_call (function, tmp);
dnovillo's avatar
 
dnovillo committed
1550
  gfc_add_expr_to_block (&block, tmp);
jakub's avatar
jakub committed
1551 1552
  gfc_add_block_to_block (&block, dt_post_end_block);
  gfc_init_block (dt_post_end_block);
dnovillo's avatar
 
dnovillo committed
1553

pbrook's avatar
pbrook committed
1554 1555
  if (last_dt != IOLENGTH)
    {
pbrook's avatar
pbrook committed
1556
      gcc_assert (code->ext.dt != NULL);
jakub's avatar
jakub committed
1557
      io_result (&block, dt_parm, code->ext.dt->err,
pbrook's avatar
pbrook committed
1558 1559
		 code->ext.dt->end, code->ext.dt->eor);
    }
dnovillo's avatar
 
dnovillo committed
1560 1561 1562 1563

  return gfc_finish_block (&block);
}

1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
static void
transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr);

/* 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)
{
  tree tmp;
  stmtblock_t body;
  stmtblock_t block;
  gfc_loopinfo loop;
  int n;
  gfc_ss *ss;
  gfc_se se;

  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_ss ();
  ss->type = GFC_SS_COMPONENT;
  ss->expr = NULL;
  ss->shape = gfc_get_shape (cm->as->rank);
  ss->next = gfc_ss_terminator;
  ss->data.info.dimen = cm->as->rank;
  ss->data.info.descriptor = expr;
  ss->data.info.data = gfc_conv_array_data (expr);
  ss->data.info.offset = gfc_conv_array_offset (expr);
  for (n = 0; n < cm->as->rank; n++)
    {
      ss->data.info.dim[n] = n;
      ss->data.info.start[n] = gfc_conv_array_lbound (expr, n);
      ss->data.info.stride[n] = gfc_index_one_node;

      mpz_init (ss->shape[n]);
      mpz_sub (ss->shape[n], cm->as->upper[n]->value.integer,
               cm->as->lower[n]->value.integer);
      mpz_add_ui (ss->shape[n], ss->shape[n], 1);
    }

1614
  /* Once we got ss, we use scalarizer to create the loop.  */
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631

  gfc_init_loopinfo (&loop);
  gfc_add_ss_to_loop (&loop, ss);
  gfc_conv_ss_startstride (&loop);
  gfc_conv_loop_setup (&loop);
  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.  */
1632
  tmp = build_fold_addr_expr (se.expr);
1633 1634 1635
  transfer_expr (&se, &cm->ts, tmp);

  /* We are done now with the loop body.  Wrap up the scalarizer and
1636
     return.  */
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649

  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);

  for (n = 0; n < cm->as->rank; n++)
    mpz_clear (ss->shape[n]);
  gfc_free (ss->shape);

pbrook's avatar
pbrook committed
1650 1651
  gfc_cleanup_loop (&loop);

1652 1653
  return gfc_finish_block (&block);
}
dnovillo's avatar
 
dnovillo committed
1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670

/* Generate the call for a scalar transfer node.  */

static void
transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr)
{
  tree args, tmp, function, arg2, field, expr;
  gfc_component *c;
  int kind;

  kind = ts->kind;
  function = NULL;
  arg2 = NULL;

  switch (ts->type)
    {
    case BT_INTEGER:
1671
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1672
      function = iocall[IOCALL_X_INTEGER];
dnovillo's avatar
 
dnovillo committed
1673 1674 1675
      break;

    case BT_REAL:
1676
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1677
      function = iocall[IOCALL_X_REAL];
dnovillo's avatar
 
dnovillo committed
1678 1679 1680
      break;

    case BT_COMPLEX:
1681
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1682
      function = iocall[IOCALL_X_COMPLEX];
dnovillo's avatar
 
dnovillo committed
1683 1684 1685
      break;

    case BT_LOGICAL:
1686
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1687
      function = iocall[IOCALL_X_LOGICAL];
dnovillo's avatar
 
dnovillo committed
1688 1689 1690
      break;

    case BT_CHARACTER:
1691 1692 1693 1694
      if (se->string_length)
	arg2 = se->string_length;
      else
	{
1695
	  tmp = build_fold_indirect_ref (addr_expr);
1696 1697 1698
	  gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE);
	  arg2 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp)));
	}
jakub's avatar
jakub committed
1699
      function = iocall[IOCALL_X_CHARACTER];
dnovillo's avatar
 
dnovillo committed
1700 1701 1702
      break;

    case BT_DERIVED:
1703
      /* Recurse into the elements of the derived type.  */
dnovillo's avatar
 
dnovillo committed
1704
      expr = gfc_evaluate_now (addr_expr, &se->pre);
1705
      expr = build_fold_indirect_ref (expr);
dnovillo's avatar
 
dnovillo committed
1706 1707 1708 1709

      for (c = ts->derived->components; c; c = c->next)
	{
	  field = c->backend_decl;
pbrook's avatar
pbrook committed
1710
	  gcc_assert (field && TREE_CODE (field) == FIELD_DECL);
dnovillo's avatar
 
dnovillo committed
1711

1712 1713
	  tmp = build3 (COMPONENT_REF, TREE_TYPE (field), expr, field,
			NULL_TREE);
dnovillo's avatar
 
dnovillo committed
1714

1715 1716 1717 1718 1719 1720 1721 1722
          if (c->dimension)
            {
              tmp = transfer_array_component (tmp, c);
              gfc_add_expr_to_block (&se->pre, tmp);
            }
          else
            {
              if (!c->pointer)
1723
                tmp = build_fold_addr_expr (tmp);
1724 1725
              transfer_expr (se, &c->ts, tmp);
            }
dnovillo's avatar
 
dnovillo committed
1726 1727 1728 1729 1730 1731 1732
	}
      return;

    default:
      internal_error ("Bad IO basetype (%d)", ts->type);
    }

1733
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1734 1735
  args = gfc_chainon_list (NULL_TREE, tmp);
  args = gfc_chainon_list (args, addr_expr);
dnovillo's avatar
 
dnovillo committed
1736 1737 1738 1739 1740
  args = gfc_chainon_list (args, arg2);

  tmp = gfc_build_function_call (function, args);
  gfc_add_expr_to_block (&se->pre, tmp);
  gfc_add_block_to_block (&se->pre, &se->post);
pbrook's avatar
pbrook committed
1741

dnovillo's avatar
 
dnovillo committed
1742 1743 1744
}


1745 1746 1747 1748 1749 1750
/* 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)
{
jb's avatar
jb committed
1751
  tree args, tmp, charlen_arg, kind_arg;
1752 1753 1754 1755 1756 1757

  if (ts->type == BT_CHARACTER)
    charlen_arg = se->string_length;
  else
    charlen_arg = build_int_cstu (NULL_TREE, 0);

jb's avatar
jb committed
1758 1759
  kind_arg = build_int_cst (NULL_TREE, ts->kind);

1760
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1761 1762
  args = gfc_chainon_list (NULL_TREE, tmp);
  args = gfc_chainon_list (args, addr_expr);
jb's avatar
jb committed
1763
  args = gfc_chainon_list (args, kind_arg);
1764
  args = gfc_chainon_list (args, charlen_arg);
jakub's avatar
jakub committed
1765
  tmp = gfc_build_function_call (iocall[IOCALL_X_ARRAY], args);
1766 1767 1768 1769 1770
  gfc_add_expr_to_block (&se->pre, tmp);
  gfc_add_block_to_block (&se->pre, &se->post);
}


dnovillo's avatar
 
dnovillo committed
1771 1772 1773 1774 1775 1776 1777 1778
/* 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;
1779
  gfc_ref *ref;
dnovillo's avatar
 
dnovillo committed
1780 1781 1782 1783 1784
  gfc_ss *ss;
  gfc_se se;
  tree tmp;

  gfc_start_block (&block);
1785
  gfc_init_block (&body);
dnovillo's avatar
 
dnovillo committed
1786 1787 1788 1789

  expr = code->expr;
  ss = gfc_walk_expr (expr);

1790
  ref = NULL;
dnovillo's avatar
 
dnovillo committed
1791 1792 1793
  gfc_init_se (&se, NULL);

  if (ss == gfc_ss_terminator)
1794
    {
jb's avatar
jb committed
1795
      /* Transfer a scalar value.  */
1796 1797 1798
      gfc_conv_expr_reference (&se, expr);
      transfer_expr (&se, &expr->ts, se.expr);
    }
jb's avatar
jb committed
1799
  else
dnovillo's avatar
 
dnovillo committed
1800
    {
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
      /* 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)
	{
	  for (ref = expr->ref; ref && ref->type != REF_ARRAY;
		 ref = ref->next);
	  gcc_assert (ref->type == REF_ARRAY);
	}

      if (expr->ts.type != BT_DERIVED && ref && ref->next == NULL)
jb's avatar
jb committed
1812 1813 1814
	{
	  /* Get the descriptor.  */
	  gfc_conv_expr_descriptor (&se, expr, ss);
1815
	  tmp = build_fold_addr_expr (se.expr);
1816 1817
	  transfer_array_desc (&se, &expr->ts, tmp);
	  goto finish_block_label;
jb's avatar
jb committed
1818 1819
	}
      
dnovillo's avatar
 
dnovillo committed
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834
      /* Initialize the scalarizer.  */
      gfc_init_loopinfo (&loop);
      gfc_add_ss_to_loop (&loop, ss);

      /* Initialize the loop.  */
      gfc_conv_ss_startstride (&loop);
      gfc_conv_loop_setup (&loop);

      /* 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;

1835 1836 1837
      gfc_conv_expr_reference (&se, expr);
      transfer_expr (&se, &expr->ts, se.expr);
    }
jb's avatar
jb committed
1838 1839

 finish_block_label:
dnovillo's avatar
 
dnovillo committed
1840 1841 1842 1843 1844 1845 1846 1847

  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
    {
pbrook's avatar
pbrook committed
1848
      gcc_assert (se.ss == gfc_ss_terminator);
dnovillo's avatar
 
dnovillo committed
1849 1850 1851 1852 1853 1854 1855 1856 1857
      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);

1858
  return gfc_finish_block (&block);
dnovillo's avatar
 
dnovillo committed
1859 1860 1861 1862
}

#include "gt-fortran-trans-io.h"