trans-io.c 49.6 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
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,
163
	  len + 1);
jakub's avatar
jakub committed
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
  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);
230 231 232 233 234 235 236 237

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

jb's avatar
jb committed
238
  gfc_c_int_type_node = gfc_get_int_type (gfc_c_int_kind);
dnovillo's avatar
 
dnovillo committed
239

jakub's avatar
jakub committed
240 241
  for (ptype = IOPARM_ptype_common; ptype < IOPARM_ptype_num; ptype++)
    gfc_build_st_parameter (ptype, types);
dnovillo's avatar
 
dnovillo committed
242 243 244

  /* Define the transfer functions.  */

jakub's avatar
jakub committed
245 246 247
  dt_parm_type = build_pointer_type (st_parameter[IOPARM_ptype_dt].type);

  iocall[IOCALL_X_INTEGER] =
dnovillo's avatar
 
dnovillo committed
248 249
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_integer")),
jakub's avatar
jakub committed
250 251
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
252

jakub's avatar
jakub committed
253
  iocall[IOCALL_X_LOGICAL] =
dnovillo's avatar
 
dnovillo committed
254 255
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_logical")),
jakub's avatar
jakub committed
256 257
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
258

jakub's avatar
jakub committed
259
  iocall[IOCALL_X_CHARACTER] =
dnovillo's avatar
 
dnovillo committed
260 261
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_character")),
jakub's avatar
jakub committed
262 263
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
264

jakub's avatar
jakub committed
265
  iocall[IOCALL_X_REAL] =
dnovillo's avatar
 
dnovillo committed
266
    gfc_build_library_function_decl (get_identifier (PREFIX("transfer_real")),
jakub's avatar
jakub committed
267
				     void_type_node, 3, dt_parm_type,
dnovillo's avatar
 
dnovillo committed
268 269
				     pvoid_type_node, gfc_int4_type_node);

jakub's avatar
jakub committed
270
  iocall[IOCALL_X_COMPLEX] =
dnovillo's avatar
 
dnovillo committed
271 272
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_complex")),
jakub's avatar
jakub committed
273 274
				     void_type_node, 3, dt_parm_type,
				     pvoid_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
275

jakub's avatar
jakub committed
276
  iocall[IOCALL_X_ARRAY] =
277 278
    gfc_build_library_function_decl (get_identifier
				     (PREFIX("transfer_array")),
jakub's avatar
jakub committed
279 280
				     void_type_node, 4, dt_parm_type,
				     pvoid_type_node, gfc_c_int_type_node,
281 282
				     gfc_charlen_type_node);

dnovillo's avatar
 
dnovillo committed
283 284
  /* Library entry points */

jakub's avatar
jakub committed
285
  iocall[IOCALL_READ] =
dnovillo's avatar
 
dnovillo committed
286
    gfc_build_library_function_decl (get_identifier (PREFIX("st_read")),
jakub's avatar
jakub committed
287
				     void_type_node, 1, dt_parm_type);
dnovillo's avatar
 
dnovillo committed
288

jakub's avatar
jakub committed
289
  iocall[IOCALL_WRITE] =
dnovillo's avatar
 
dnovillo committed
290
    gfc_build_library_function_decl (get_identifier (PREFIX("st_write")),
jakub's avatar
jakub committed
291 292 293 294
				     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
295
    gfc_build_library_function_decl (get_identifier (PREFIX("st_open")),
jakub's avatar
jakub committed
296
				     void_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
297

jakub's avatar
jakub committed
298 299 300

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

jakub's avatar
jakub committed
304 305
  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_inquire].type);
  iocall[IOCALL_INQUIRE] =
dnovillo's avatar
 
dnovillo committed
306
    gfc_build_library_function_decl (get_identifier (PREFIX("st_inquire")),
jakub's avatar
jakub committed
307
				     gfc_int4_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
308

jakub's avatar
jakub committed
309
  iocall[IOCALL_IOLENGTH] =
pbrook's avatar
pbrook committed
310
    gfc_build_library_function_decl(get_identifier (PREFIX("st_iolength")),
jakub's avatar
jakub committed
311
				    void_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
312

jakub's avatar
jakub committed
313 314
  parm_type = build_pointer_type (st_parameter[IOPARM_ptype_filepos].type);
  iocall[IOCALL_REWIND] =
dnovillo's avatar
 
dnovillo committed
315
    gfc_build_library_function_decl (get_identifier (PREFIX("st_rewind")),
jakub's avatar
jakub committed
316
				     gfc_int4_type_node, 1, parm_type);
dnovillo's avatar
 
dnovillo committed
317

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

jakub's avatar
jakub committed
322
  iocall[IOCALL_ENDFILE] =
dnovillo's avatar
 
dnovillo committed
323
    gfc_build_library_function_decl (get_identifier (PREFIX("st_endfile")),
jakub's avatar
jakub committed
324
				     gfc_int4_type_node, 1, parm_type);
325

jakub's avatar
jakub committed
326
  iocall[IOCALL_FLUSH] =
327
    gfc_build_library_function_decl (get_identifier (PREFIX("st_flush")),
jakub's avatar
jakub committed
328
				     gfc_int4_type_node, 1, parm_type);
329

dnovillo's avatar
 
dnovillo committed
330 331
  /* Library helpers */

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

jakub's avatar
jakub committed
336
  iocall[IOCALL_WRITE_DONE] =
dnovillo's avatar
 
dnovillo committed
337
    gfc_build_library_function_decl (get_identifier (PREFIX("st_write_done")),
jakub's avatar
jakub committed
338
				     gfc_int4_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
339

jakub's avatar
jakub committed
340
  iocall[IOCALL_IOLENGTH_DONE] =
pbrook's avatar
pbrook committed
341
    gfc_build_library_function_decl (get_identifier (PREFIX("st_iolength_done")),
jakub's avatar
jakub committed
342
				     gfc_int4_type_node, 1, dt_parm_type);
pbrook's avatar
pbrook committed
343

dnovillo's avatar
 
dnovillo committed
344

jakub's avatar
jakub committed
345
  iocall[IOCALL_SET_NML_VAL] =
346
    gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var")),
jakub's avatar
jakub committed
347 348 349
				     void_type_node, 6, dt_parm_type,
				     pvoid_type_node, pvoid_type_node,
				     gfc_int4_type_node, gfc_charlen_type_node,
350
				     gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
351

jakub's avatar
jakub committed
352
  iocall[IOCALL_SET_NML_VAL_DIM] =
353
    gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_dim")),
jakub's avatar
jakub committed
354
				     void_type_node, 5, dt_parm_type,
355 356
				     gfc_int4_type_node, gfc_int4_type_node,
				     gfc_int4_type_node, gfc_int4_type_node);
dnovillo's avatar
 
dnovillo committed
357 358 359
}


jakub's avatar
jakub committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
/* 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;
}


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

jakub's avatar
jakub committed
383 384 385
static unsigned int
set_parameter_value (stmtblock_t *block, tree var, enum iofield type,
		     gfc_expr *e)
dnovillo's avatar
 
dnovillo committed
386 387 388
{
  gfc_se se;
  tree tmp;
jakub's avatar
jakub committed
389
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
390 391

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

jakub's avatar
jakub committed
395 396 397 398 399
  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
400
  gfc_add_modify_expr (block, tmp, se.expr);
jakub's avatar
jakub committed
401
  return p->mask;
dnovillo's avatar
 
dnovillo committed
402 403 404
}


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

jakub's avatar
jakub committed
408 409 410
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
411 412
{
  gfc_se se;
jakub's avatar
jakub committed
413 414
  tree tmp, addr;
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
415

jakub's avatar
jakub committed
416
  gcc_assert (e->ts.type == BT_INTEGER || e->ts.type == BT_LOGICAL);
dnovillo's avatar
 
dnovillo committed
417
  gfc_init_se (&se, NULL);
jakub's avatar
jakub committed
418
  gfc_conv_expr_lhs (&se, e);
dnovillo's avatar
 
dnovillo committed
419 420 421

  gfc_add_block_to_block (block, &se.pre);

jakub's avatar
jakub committed
422 423 424
  if (TYPE_MODE (TREE_TYPE (se.expr))
      == TYPE_MODE (TREE_TYPE (TREE_TYPE (p->field))))
    addr = convert (TREE_TYPE (p->field),
425
		    build_fold_addr_expr (se.expr));
jakub's avatar
jakub committed
426 427 428 429 430 431 432 433
  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);
434
      addr = build_fold_addr_expr (tmpvar);
jakub's avatar
jakub committed
435 436 437 438 439 440 441 442 443 444 445
      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
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 494 495 496 497 498 499 500 501
/* 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));
502
      se->expr = build_fold_addr_expr (se->expr);
503 504 505 506 507 508 509
    }

  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
510

511

dnovillo's avatar
 
dnovillo committed
512
/* Generate code to store a string and its length into the
jakub's avatar
jakub committed
513
   st_parameter_XXX structure.  */
dnovillo's avatar
 
dnovillo committed
514

jakub's avatar
jakub committed
515
static unsigned int
dnovillo's avatar
 
dnovillo committed
516
set_string (stmtblock_t * block, stmtblock_t * postblock, tree var,
jakub's avatar
jakub committed
517
	    enum iofield type, gfc_expr * e)
dnovillo's avatar
 
dnovillo committed
518 519 520 521 522
{
  gfc_se se;
  tree tmp;
  tree io;
  tree len;
jakub's avatar
jakub committed
523
  gfc_st_parameter_field *p = &st_parameter_field[type];
dnovillo's avatar
 
dnovillo committed
524 525 526

  gfc_init_se (&se, NULL);

jakub's avatar
jakub committed
527 528 529 530 531 532
  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,
533
		NULL_TREE);
dnovillo's avatar
 
dnovillo committed
534

535
  /* Integer variable assigned a format label.  */
dnovillo's avatar
 
dnovillo committed
536 537
  if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1)
    {
538 539
      char * msg;

fengwang's avatar
fengwang committed
540
      gfc_conv_label_variable (&se, e);
dnovillo's avatar
 
dnovillo committed
541
      tmp = GFC_DECL_STRING_LEN (se.expr);
sayle's avatar
 
sayle committed
542 543
      tmp = fold_build2 (LT_EXPR, boolean_type_node,
			 tmp, build_int_cst (TREE_TYPE (tmp), 0));
544 545 546 547 548 549

      asprintf(&msg, "Label assigned to variable '%s' is not a format label",
	       e->symtree->name);
      gfc_trans_runtime_check (tmp, msg, &se.pre, &e->where);
      gfc_free (msg);

550 551
      gfc_add_modify_expr (&se.pre, io,
		 fold_convert (TREE_TYPE (io), GFC_DECL_ASSIGN_ADDR (se.expr)));
dnovillo's avatar
 
dnovillo committed
552 553 554 555
      gfc_add_modify_expr (&se.pre, len, GFC_DECL_STRING_LEN (se.expr));
    }
  else
    {
556 557 558 559 560 561 562 563 564
      /* 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
565
      gfc_conv_string_parameter (&se);
566
      gfc_add_modify_expr (&se.pre, io, fold_convert (TREE_TYPE (io), se.expr));
dnovillo's avatar
 
dnovillo committed
567 568 569 570 571
      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
572
  return p->mask;
dnovillo's avatar
 
dnovillo committed
573 574 575
}


576 577 578
/* Generate code to store the character (array) and the character length
   for an internal unit.  */

jakub's avatar
jakub committed
579 580
static unsigned int
set_internal_unit (stmtblock_t * block, tree var, gfc_expr * e)
581 582 583 584 585 586
{
  gfc_se se;
  tree io;
  tree len;
  tree desc;
  tree tmp;
jakub's avatar
jakub committed
587 588
  gfc_st_parameter_field *p;
  unsigned int mask;
589 590 591

  gfc_init_se (&se, NULL);

jakub's avatar
jakub committed
592 593 594 595 596
  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,
597
		NULL_TREE);
jakub's avatar
jakub committed
598 599
  p = &st_parameter_field[IOPARM_dt_internal_unit_desc];
  desc = build3 (COMPONENT_REF, TREE_TYPE (p->field), var, p->field,
600 601 602 603 604 605 606 607 608 609
		 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;
610
      se.expr = build_int_cst (pchar_type_node, 0);
611 612 613
    }

  /* Character array.  */
eedelman's avatar
eedelman committed
614
  else if (e->rank > 0)
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
    {
      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
633
  return mask;
634 635
}

dnovillo's avatar
 
dnovillo committed
636 637 638 639 640 641 642 643 644 645
/* 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 */

646
  value = build_int_cst (NULL_TREE, label_value);
dnovillo's avatar
 
dnovillo committed
647 648

  /* Make a backend label for this case.  */
649
  tmp = gfc_build_label_decl (NULL_TREE);
dnovillo's avatar
 
dnovillo committed
650 651

  /* And the case itself.  */
652
  tmp = build3_v (CASE_LABEL_EXPR, value, NULL_TREE, tmp);
dnovillo's avatar
 
dnovillo committed
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
  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
668
io_result (stmtblock_t * block, tree var, gfc_st_label * err_label,
dnovillo's avatar
 
dnovillo committed
669 670 671 672
	   gfc_st_label * end_label, gfc_st_label * eor_label)
{
  stmtblock_t body;
  tree tmp, rc;
jakub's avatar
jakub committed
673
  gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_flags];
dnovillo's avatar
 
dnovillo committed
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

  /* 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
693 694 695 696 697 698
  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
699

700
  tmp = build3_v (SWITCH_EXPR, rc, tmp, NULL_TREE);
dnovillo's avatar
 
dnovillo committed
701 702 703 704 705 706 707 708 709

  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
710
set_error_locus (stmtblock_t * block, tree var, locus * where)
dnovillo's avatar
 
dnovillo committed
711 712
{
  gfc_file *f;
jakub's avatar
jakub committed
713
  tree str, locus_file;
dnovillo's avatar
 
dnovillo committed
714
  int line;
jakub's avatar
jakub committed
715
  gfc_st_parameter_field *p = &st_parameter_field[IOPARM_common_filename];
dnovillo's avatar
 
dnovillo committed
716

jakub's avatar
jakub committed
717 718 719 720
  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
721
  f = where->lb->file;
jakub's avatar
jakub committed
722
  str = gfc_build_cstring_const (f->filename);
dnovillo's avatar
 
dnovillo committed
723

jakub's avatar
jakub committed
724 725
  str = gfc_build_addr_expr (pchar_type_node, str);
  gfc_add_modify_expr (block, locus_file, str);
dnovillo's avatar
 
dnovillo committed
726

727 728 729
#ifdef USE_MAPPED_LOCATION
  line = LOCATION_LINE (where->lb->location);
#else
tobi's avatar
tobi committed
730
  line = where->lb->linenum;
731
#endif
jakub's avatar
jakub committed
732
  set_parameter_const (block, var, IOPARM_common_line, line);
dnovillo's avatar
 
dnovillo committed
733 734 735 736 737 738 739 740 741 742
}


/* Translate an OPEN statement.  */

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

jakub's avatar
jakub committed
746
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
747 748
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
749 750 751
  var = gfc_create_var (st_parameter[IOPARM_ptype_open].type, "open_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
752 753 754
  p = code->ext.open;

  if (p->unit)
jakub's avatar
jakub committed
755 756 757
    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
758 759

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

  if (p->status)
jakub's avatar
jakub committed
763 764
    mask |= set_string (&block, &post_block, var, IOPARM_open_status,
			p->status);
dnovillo's avatar
 
dnovillo committed
765 766

  if (p->access)
jakub's avatar
jakub committed
767 768
    mask |= set_string (&block, &post_block, var, IOPARM_open_access,
			p->access);
dnovillo's avatar
 
dnovillo committed
769 770

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

  if (p->recl)
jakub's avatar
jakub committed
774
    mask |= set_parameter_value (&block, var, IOPARM_open_recl_in, p->recl);
dnovillo's avatar
 
dnovillo committed
775 776

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

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

  if (p->action)
jakub's avatar
jakub committed
785 786
    mask |= set_string (&block, &post_block, var, IOPARM_open_action,
			p->action);
dnovillo's avatar
 
dnovillo committed
787 788

  if (p->delim)
jakub's avatar
jakub committed
789 790
    mask |= set_string (&block, &post_block, var, IOPARM_open_delim,
			p->delim);
dnovillo's avatar
 
dnovillo committed
791 792

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

795
  if (p->iomsg)
jakub's avatar
jakub committed
796 797
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
798

dnovillo's avatar
 
dnovillo committed
799
  if (p->iostat)
jakub's avatar
jakub committed
800 801
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
802 803

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

806 807 808 809
  if (p->convert)
    mask |= set_string (&block, &post_block, var, IOPARM_open_convert,
			p->convert);

jakub's avatar
jakub committed
810 811
  set_parameter_const (&block, var, IOPARM_common_flags, mask);

812
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
813
  tmp = gfc_chainon_list (NULL_TREE, tmp);
814
  tmp = build_function_call_expr (iocall[IOCALL_OPEN], tmp);
dnovillo's avatar
 
dnovillo committed
815 816 817 818
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
819
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
820 821 822 823 824 825 826 827 828 829 830 831

  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
832 833
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
834

jakub's avatar
jakub committed
835
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
836 837
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
838 839 840
  var = gfc_create_var (st_parameter[IOPARM_ptype_close].type, "close_parm");

  set_error_locus (&block, var, &code->loc);
dnovillo's avatar
 
dnovillo committed
841 842 843
  p = code->ext.close;

  if (p->unit)
jakub's avatar
jakub committed
844 845 846
    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
847 848

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

852
  if (p->iomsg)
jakub's avatar
jakub committed
853 854
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
855

dnovillo's avatar
 
dnovillo committed
856
  if (p->iostat)
jakub's avatar
jakub committed
857 858
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
859 860

  if (p->err)
jakub's avatar
jakub committed
861 862 863
    mask |= IOPARM_common_err;

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

865
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
866
  tmp = gfc_chainon_list (NULL_TREE, tmp);
867
  tmp = build_function_call_expr (iocall[IOCALL_CLOSE], tmp);
dnovillo's avatar
 
dnovillo committed
868 869 870 871
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
872
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
873 874 875 876 877 878 879 880 881 882

  return gfc_finish_block (&block);
}


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

static tree
build_filepos (tree function, gfc_code * code)
{
883
  stmtblock_t block, post_block;
dnovillo's avatar
 
dnovillo committed
884
  gfc_filepos *p;
jakub's avatar
jakub committed
885 886
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
887 888 889

  p = code->ext.filepos;

jakub's avatar
jakub committed
890
  gfc_start_block (&block);
891
  gfc_init_block (&post_block);
dnovillo's avatar
 
dnovillo committed
892

jakub's avatar
jakub committed
893 894 895 896
  var = gfc_create_var (st_parameter[IOPARM_ptype_filepos].type,
			"filepos_parm");

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

  if (p->unit)
jakub's avatar
jakub committed
899 900 901
    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
902

903
  if (p->iomsg)
jakub's avatar
jakub committed
904 905
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
906

dnovillo's avatar
 
dnovillo committed
907
  if (p->iostat)
jakub's avatar
jakub committed
908 909
    mask |= set_parameter_ref (&block, &post_block, var, IOPARM_common_iostat,
			       p->iostat);
dnovillo's avatar
 
dnovillo committed
910 911

  if (p->err)
jakub's avatar
jakub committed
912 913 914
    mask |= IOPARM_common_err;

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

916
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
917
  tmp = gfc_chainon_list (NULL_TREE, tmp);
918
  tmp = build_function_call_expr (function, tmp);
dnovillo's avatar
 
dnovillo committed
919 920
  gfc_add_expr_to_block (&block, tmp);

921 922
  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
923
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
924 925 926 927 928 929 930 931 932 933

  return gfc_finish_block (&block);
}


/* Translate a BACKSPACE statement.  */

tree
gfc_trans_backspace (gfc_code * code)
{
jakub's avatar
jakub committed
934
  return build_filepos (iocall[IOCALL_BACKSPACE], code);
dnovillo's avatar
 
dnovillo committed
935 936 937 938 939 940 941 942
}


/* Translate an ENDFILE statement.  */

tree
gfc_trans_endfile (gfc_code * code)
{
jakub's avatar
jakub committed
943
  return build_filepos (iocall[IOCALL_ENDFILE], code);
dnovillo's avatar
 
dnovillo committed
944 945 946 947 948 949 950 951
}


/* Translate a REWIND statement.  */

tree
gfc_trans_rewind (gfc_code * code)
{
jakub's avatar
jakub committed
952
  return build_filepos (iocall[IOCALL_REWIND], code);
dnovillo's avatar
 
dnovillo committed
953 954 955
}


956 957 958 959 960
/* Translate a FLUSH statement.  */

tree
gfc_trans_flush (gfc_code * code)
{
jakub's avatar
jakub committed
961
  return build_filepos (iocall[IOCALL_FLUSH], code);
962 963 964
}


dnovillo's avatar
 
dnovillo committed
965 966 967 968 969 970 971
/* 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
972 973
  tree tmp, var;
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
974

jakub's avatar
jakub committed
975
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
976 977
  gfc_init_block (&post_block);

jakub's avatar
jakub committed
978 979 980 981
  var = gfc_create_var (st_parameter[IOPARM_ptype_inquire].type,
			"inquire_parm");

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

984 985 986 987
  /* 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
988
  if (p->unit)
jakub's avatar
jakub committed
989 990 991
    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
992 993

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

997
  if (p->iomsg)
jakub's avatar
jakub committed
998 999
    mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			p->iomsg);
1000

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  if (p->write)
jakub's avatar
jakub committed
1074 1075
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_write,
			p->write);
dnovillo's avatar
 
dnovillo committed
1076 1077

  if (p->readwrite)
jakub's avatar
jakub committed
1078 1079
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_readwrite,
			p->readwrite);
dnovillo's avatar
 
dnovillo committed
1080 1081

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

1085
  if (p->pad)
jakub's avatar
jakub committed
1086 1087
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_pad,
			p->pad);
1088

dnovillo's avatar
 
dnovillo committed
1089
  if (p->err)
jakub's avatar
jakub committed
1090 1091
    mask |= IOPARM_common_err;

1092 1093 1094 1095
  if (p->convert)
    mask |= set_string (&block, &post_block, var, IOPARM_inquire_convert,
			p->convert);

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

1098
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
1099
  tmp = gfc_chainon_list (NULL_TREE, tmp);
1100
  tmp = build_function_call_expr (iocall[IOCALL_INQUIRE], tmp);
dnovillo's avatar
 
dnovillo committed
1101 1102 1103 1104
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
1105
  io_result (&block, var, p->err, NULL, NULL);
dnovillo's avatar
 
dnovillo committed
1106 1107 1108 1109 1110

  return gfc_finish_block (&block);
}

static gfc_expr *
1111
gfc_new_nml_name_expr (const char * name)
dnovillo's avatar
 
dnovillo committed
1112 1113
{
   gfc_expr * nml_name;
1114

dnovillo's avatar
 
dnovillo committed
1115 1116 1117
   nml_name = gfc_get_expr();
   nml_name->ref = NULL;
   nml_name->expr_type = EXPR_CONSTANT;
1118
   nml_name->ts.kind = gfc_default_character_kind;
dnovillo's avatar
 
dnovillo committed
1119 1120
   nml_name->ts.type = BT_CHARACTER;
   nml_name->value.character.length = strlen(name);
1121 1122
   nml_name->value.character.string = gfc_getmem (strlen (name) + 1);
   strcpy (nml_name->value.character.string, name);
dnovillo's avatar
 
dnovillo committed
1123 1124 1125 1126

   return nml_name;
}

1127 1128 1129 1130 1131
/* 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
1132
{
1133 1134 1135 1136 1137 1138 1139 1140 1141
  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
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 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
/* 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));

1179
  itmp = (dummy_arg_flagged) ? build_fold_indirect_ref (tmp) : tmp;
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205

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

1206
  tmp = build_fold_addr_expr (tmp);
1207 1208 1209 1210

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

  if (dummy_arg_flagged && !array_flagged)
1211
    tmp = build_fold_indirect_ref (tmp);
1212 1213 1214 1215 1216

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

  return tmp;
}
1217

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

1222 1223 1224
#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)
1225 1226

static void
1227 1228 1229
transfer_namelist_element (stmtblock_t * block, const char * var_name,
			   gfc_symbol * sym, gfc_component * c,
			   tree base_addr)
1230
{
1231 1232 1233 1234 1235 1236 1237 1238
  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
1239
  tree dt_parm_addr;
1240 1241 1242
  int n_dim; 
  int itype;
  int rank = 0;
1243

1244
  gcc_assert (sym || c);
1245

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
  /* 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)
1262
    {
1263 1264
      dt =  TREE_TYPE ((sym) ? sym->backend_decl : c->backend_decl);
      dtype = gfc_get_dtype (dt);
1265
    }
1266 1267 1268
  else
    {
      itype = GFC_DTYPE_UNKNOWN;
1269

1270
      switch (ts->type)
1271

1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
	{
	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);
1296 1297
    }

1298 1299 1300 1301
  /* Build up the arguments for the transfer call.
     The call for the scalar part transfers:
     (address, name, type, kind or string_length, dtype)  */

1302
  dt_parm_addr = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1303 1304
  NML_FIRST_ARG (dt_parm_addr);
  NML_ADD_ARG (addr_expr);
1305 1306 1307 1308 1309 1310
  NML_ADD_ARG (string);
  NML_ADD_ARG (IARG (ts->kind));

  if (ts->type == BT_CHARACTER)
    NML_ADD_ARG (ts->cl->backend_decl);
  else
1311
    NML_ADD_ARG (build_int_cst (gfc_charlen_type_node, 0));
1312 1313

  NML_ADD_ARG (dtype);
1314
  tmp = build_function_call_expr (iocall[IOCALL_SET_NML_VAL], args);
1315
  gfc_add_expr_to_block (block, tmp);
1316 1317 1318 1319 1320 1321

  /* 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
1322 1323
      NML_FIRST_ARG (dt_parm_addr);
      NML_ADD_ARG (IARG (n_dim));
1324 1325 1326
      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));
1327
      tmp = build_function_call_expr (iocall[IOCALL_SET_NML_VAL_DIM], args);
1328 1329 1330 1331 1332 1333 1334 1335 1336
      gfc_add_expr_to_block (block, tmp);
    }

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

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

1337
      tree expr = build_fold_indirect_ref (addr_expr);
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347

      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);
	}
    }
1348
}
dnovillo's avatar
 
dnovillo committed
1349

1350 1351 1352 1353
#undef IARG
#undef NML_ADD_ARG
#undef NML_FIRST_ARG

dnovillo's avatar
 
dnovillo committed
1354 1355 1356 1357 1358
/* 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
1359
build_dt (tree function, gfc_code * code)
dnovillo's avatar
 
dnovillo committed
1360
{
jakub's avatar
jakub committed
1361
  stmtblock_t block, post_block, post_end_block;
dnovillo's avatar
 
dnovillo committed
1362
  gfc_dt *dt;
jakub's avatar
jakub committed
1363
  tree tmp, var;
1364
  gfc_expr *nmlname;
1365
  gfc_namelist *nml;
jakub's avatar
jakub committed
1366
  unsigned int mask = 0;
dnovillo's avatar
 
dnovillo committed
1367

jakub's avatar
jakub committed
1368
  gfc_start_block (&block);
dnovillo's avatar
 
dnovillo committed
1369
  gfc_init_block (&post_block);
jakub's avatar
jakub committed
1370 1371 1372 1373 1374
  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
1375

jakub's avatar
jakub committed
1376 1377 1378 1379 1380
  if (last_dt == IOLENGTH)
    {
      gfc_inquire *inq;

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

jakub's avatar
jakub committed
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
      /* 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
1396

jakub's avatar
jakub committed
1397
  if (dt && dt->io_unit)
dnovillo's avatar
 
dnovillo committed
1398 1399 1400
    {
      if (dt->io_unit->ts.type == BT_CHARACTER)
	{
jakub's avatar
jakub committed
1401 1402
	  mask |= set_internal_unit (&block, var, dt->io_unit);
	  set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
1403 1404
	}
      else
jakub's avatar
jakub committed
1405
	set_parameter_value (&block, var, IOPARM_common_unit, dt->io_unit);
dnovillo's avatar
 
dnovillo committed
1406
    }
jakub's avatar
jakub committed
1407 1408
  else
    set_parameter_const (&block, var, IOPARM_common_unit, 0);
dnovillo's avatar
 
dnovillo committed
1409

jakub's avatar
jakub committed
1410 1411 1412 1413
  if (dt)
    {
      if (dt->rec)
	mask |= set_parameter_value (&block, var, IOPARM_dt_rec, dt->rec);
dnovillo's avatar
 
dnovillo committed
1414

jakub's avatar
jakub committed
1415 1416 1417
      if (dt->advance)
	mask |= set_string (&block, &post_block, var, IOPARM_dt_advance,
			    dt->advance);
dnovillo's avatar
 
dnovillo committed
1418

jakub's avatar
jakub committed
1419 1420 1421
      if (dt->format_expr)
	mask |= set_string (&block, &post_block, var, IOPARM_dt_format,
			    dt->format_expr);
dnovillo's avatar
 
dnovillo committed
1422

jakub's avatar
jakub committed
1423 1424 1425 1426 1427 1428 1429 1430
      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
1431

jakub's avatar
jakub committed
1432 1433 1434
      if (dt->iomsg)
	mask |= set_string (&block, &post_block, var, IOPARM_common_iomsg,
			    dt->iomsg);
1435

jakub's avatar
jakub committed
1436 1437 1438
      if (dt->iostat)
	mask |= set_parameter_ref (&block, &post_end_block, var,
				   IOPARM_common_iostat, dt->iostat);
dnovillo's avatar
 
dnovillo committed
1439

jakub's avatar
jakub committed
1440 1441 1442
      if (dt->size)
	mask |= set_parameter_ref (&block, &post_end_block, var,
				   IOPARM_dt_size, dt->size);
dnovillo's avatar
 
dnovillo committed
1443

jakub's avatar
jakub committed
1444 1445
      if (dt->err)
	mask |= IOPARM_common_err;
dnovillo's avatar
 
dnovillo committed
1446

jakub's avatar
jakub committed
1447 1448
      if (dt->eor)
	mask |= IOPARM_common_eor;
dnovillo's avatar
 
dnovillo committed
1449

jakub's avatar
jakub committed
1450 1451
      if (dt->end)
	mask |= IOPARM_common_end;
dnovillo's avatar
 
dnovillo committed
1452

jakub's avatar
jakub committed
1453 1454 1455 1456 1457 1458
      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);
1459

jakub's avatar
jakub committed
1460 1461
	  mask |= set_string (&block, &post_block, var, IOPARM_dt_namelist_name,
			      nmlname);
1462

jakub's avatar
jakub committed
1463 1464
	  if (last_dt == READ)
	    mask |= IOPARM_dt_namelist_read_mode;
1465

jakub's avatar
jakub committed
1466
	  set_parameter_const (&block, var, IOPARM_common_flags, mask);
1467

jakub's avatar
jakub committed
1468 1469 1470 1471 1472 1473 1474 1475
	  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
1476
    }
jakub's avatar
jakub committed
1477 1478
  else
    set_parameter_const (&block, var, IOPARM_common_flags, mask);
dnovillo's avatar
 
dnovillo committed
1479

1480
  tmp = build_fold_addr_expr (var);
jakub's avatar
jakub committed
1481
  tmp = gfc_chainon_list (NULL_TREE, tmp);
1482
  tmp = build_function_call_expr (function, tmp);
dnovillo's avatar
 
dnovillo committed
1483 1484 1485 1486
  gfc_add_expr_to_block (&block, tmp);

  gfc_add_block_to_block (&block, &post_block);

jakub's avatar
jakub committed
1487 1488 1489 1490 1491 1492 1493 1494
  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
1495 1496 1497 1498
  return gfc_finish_block (&block);
}


pbrook's avatar
pbrook committed
1499 1500
/* Translate the IOLENGTH form of an INQUIRE statement.  We treat
   this as a third sort of data transfer statement, except that
1501
   lengths are summed instead of actually transferring any data.  */
pbrook's avatar
pbrook committed
1502 1503 1504 1505 1506

tree
gfc_trans_iolength (gfc_code * code)
{
  last_dt = IOLENGTH;
jakub's avatar
jakub committed
1507
  return build_dt (iocall[IOCALL_IOLENGTH], code);
pbrook's avatar
pbrook committed
1508 1509 1510
}


dnovillo's avatar
 
dnovillo committed
1511 1512 1513 1514 1515 1516
/* Translate a READ statement.  */

tree
gfc_trans_read (gfc_code * code)
{
  last_dt = READ;
jakub's avatar
jakub committed
1517
  return build_dt (iocall[IOCALL_READ], code);
dnovillo's avatar
 
dnovillo committed
1518 1519 1520 1521 1522 1523 1524 1525 1526
}


/* Translate a WRITE statement */

tree
gfc_trans_write (gfc_code * code)
{
  last_dt = WRITE;
jakub's avatar
jakub committed
1527
  return build_dt (iocall[IOCALL_WRITE], code);
dnovillo's avatar
 
dnovillo committed
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
}


/* 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
1541 1542 1543
  switch (last_dt)
    {
    case READ:
jakub's avatar
jakub committed
1544
      function = iocall[IOCALL_READ_DONE];
pbrook's avatar
pbrook committed
1545 1546 1547
      break;

    case WRITE:
jakub's avatar
jakub committed
1548
      function = iocall[IOCALL_WRITE_DONE];
pbrook's avatar
pbrook committed
1549 1550 1551
      break;

    case IOLENGTH:
jakub's avatar
jakub committed
1552
      function = iocall[IOCALL_IOLENGTH_DONE];
pbrook's avatar
pbrook committed
1553 1554 1555
      break;

    default:
pbrook's avatar
pbrook committed
1556
      gcc_unreachable ();
pbrook's avatar
pbrook committed
1557
    }
dnovillo's avatar
 
dnovillo committed
1558

1559
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1560
  tmp = gfc_chainon_list (NULL_TREE, tmp);
1561
  tmp = build_function_call_expr (function, tmp);
dnovillo's avatar
 
dnovillo committed
1562
  gfc_add_expr_to_block (&block, tmp);
jakub's avatar
jakub committed
1563 1564
  gfc_add_block_to_block (&block, dt_post_end_block);
  gfc_init_block (dt_post_end_block);
dnovillo's avatar
 
dnovillo committed
1565

pbrook's avatar
pbrook committed
1566 1567
  if (last_dt != IOLENGTH)
    {
pbrook's avatar
pbrook committed
1568
      gcc_assert (code->ext.dt != NULL);
jakub's avatar
jakub committed
1569
      io_result (&block, dt_parm, code->ext.dt->err,
pbrook's avatar
pbrook committed
1570 1571
		 code->ext.dt->end, code->ext.dt->eor);
    }
dnovillo's avatar
 
dnovillo committed
1572 1573 1574 1575

  return gfc_finish_block (&block);
}

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 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
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);
    }

1626
  /* Once we got ss, we use scalarizer to create the loop.  */
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643

  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.  */
1644
  tmp = build_fold_addr_expr (se.expr);
1645 1646 1647
  transfer_expr (&se, &cm->ts, tmp);

  /* We are done now with the loop body.  Wrap up the scalarizer and
1648
     return.  */
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661

  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
1662 1663
  gfc_cleanup_loop (&loop);

1664 1665
  return gfc_finish_block (&block);
}
dnovillo's avatar
 
dnovillo committed
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682

/* 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:
1683
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1684
      function = iocall[IOCALL_X_INTEGER];
dnovillo's avatar
 
dnovillo committed
1685 1686 1687
      break;

    case BT_REAL:
1688
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1689
      function = iocall[IOCALL_X_REAL];
dnovillo's avatar
 
dnovillo committed
1690 1691 1692
      break;

    case BT_COMPLEX:
1693
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1694
      function = iocall[IOCALL_X_COMPLEX];
dnovillo's avatar
 
dnovillo committed
1695 1696 1697
      break;

    case BT_LOGICAL:
1698
      arg2 = build_int_cst (NULL_TREE, kind);
jakub's avatar
jakub committed
1699
      function = iocall[IOCALL_X_LOGICAL];
dnovillo's avatar
 
dnovillo committed
1700 1701 1702
      break;

    case BT_CHARACTER:
1703 1704 1705 1706
      if (se->string_length)
	arg2 = se->string_length;
      else
	{
1707
	  tmp = build_fold_indirect_ref (addr_expr);
1708 1709 1710
	  gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE);
	  arg2 = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp)));
	}
jakub's avatar
jakub committed
1711
      function = iocall[IOCALL_X_CHARACTER];
dnovillo's avatar
 
dnovillo committed
1712 1713 1714
      break;

    case BT_DERIVED:
1715
      /* Recurse into the elements of the derived type.  */
dnovillo's avatar
 
dnovillo committed
1716
      expr = gfc_evaluate_now (addr_expr, &se->pre);
1717
      expr = build_fold_indirect_ref (expr);
dnovillo's avatar
 
dnovillo committed
1718 1719 1720 1721

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

1724 1725
	  tmp = build3 (COMPONENT_REF, TREE_TYPE (field), expr, field,
			NULL_TREE);
dnovillo's avatar
 
dnovillo committed
1726

1727 1728 1729 1730 1731 1732 1733 1734
          if (c->dimension)
            {
              tmp = transfer_array_component (tmp, c);
              gfc_add_expr_to_block (&se->pre, tmp);
            }
          else
            {
              if (!c->pointer)
1735
                tmp = build_fold_addr_expr (tmp);
1736 1737
              transfer_expr (se, &c->ts, tmp);
            }
dnovillo's avatar
 
dnovillo committed
1738 1739 1740 1741 1742 1743 1744
	}
      return;

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

1745
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1746 1747
  args = gfc_chainon_list (NULL_TREE, tmp);
  args = gfc_chainon_list (args, addr_expr);
dnovillo's avatar
 
dnovillo committed
1748 1749
  args = gfc_chainon_list (args, arg2);

1750
  tmp = build_function_call_expr (function, args);
dnovillo's avatar
 
dnovillo committed
1751 1752
  gfc_add_expr_to_block (&se->pre, tmp);
  gfc_add_block_to_block (&se->pre, &se->post);
pbrook's avatar
pbrook committed
1753

dnovillo's avatar
 
dnovillo committed
1754 1755 1756
}


1757 1758 1759 1760 1761 1762
/* 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
1763
  tree args, tmp, charlen_arg, kind_arg;
1764 1765 1766 1767 1768 1769

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

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

1772
  tmp = build_fold_addr_expr (dt_parm);
jakub's avatar
jakub committed
1773 1774
  args = gfc_chainon_list (NULL_TREE, tmp);
  args = gfc_chainon_list (args, addr_expr);
jb's avatar
jb committed
1775
  args = gfc_chainon_list (args, kind_arg);
1776
  args = gfc_chainon_list (args, charlen_arg);
1777
  tmp = build_function_call_expr (iocall[IOCALL_X_ARRAY], args);
1778 1779 1780 1781 1782
  gfc_add_expr_to_block (&se->pre, tmp);
  gfc_add_block_to_block (&se->pre, &se->post);
}


dnovillo's avatar
 
dnovillo committed
1783 1784 1785 1786 1787 1788 1789 1790
/* 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;
1791
  gfc_ref *ref;
dnovillo's avatar
 
dnovillo committed
1792 1793 1794 1795 1796
  gfc_ss *ss;
  gfc_se se;
  tree tmp;

  gfc_start_block (&block);
1797
  gfc_init_block (&body);
dnovillo's avatar
 
dnovillo committed
1798 1799 1800 1801

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

1802
  ref = NULL;
dnovillo's avatar
 
dnovillo committed
1803 1804 1805
  gfc_init_se (&se, NULL);

  if (ss == gfc_ss_terminator)
1806
    {
jb's avatar
jb committed
1807
      /* Transfer a scalar value.  */
1808 1809 1810
      gfc_conv_expr_reference (&se, expr);
      transfer_expr (&se, &expr->ts, se.expr);
    }
jb's avatar
jb committed
1811
  else
dnovillo's avatar
 
dnovillo committed
1812
    {
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
      /* 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
1824 1825 1826
	{
	  /* Get the descriptor.  */
	  gfc_conv_expr_descriptor (&se, expr, ss);
1827
	  tmp = build_fold_addr_expr (se.expr);
1828 1829
	  transfer_array_desc (&se, &expr->ts, tmp);
	  goto finish_block_label;
jb's avatar
jb committed
1830 1831
	}
      
dnovillo's avatar
 
dnovillo committed
1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
      /* 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;

1847 1848 1849
      gfc_conv_expr_reference (&se, expr);
      transfer_expr (&se, &expr->ts, se.expr);
    }
jb's avatar
jb committed
1850 1851

 finish_block_label:
dnovillo's avatar
 
dnovillo committed
1852 1853 1854 1855 1856 1857 1858 1859

  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
1860
      gcc_assert (se.ss == gfc_ss_terminator);
dnovillo's avatar
 
dnovillo committed
1861 1862 1863 1864 1865 1866 1867 1868 1869
      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);

1870
  return gfc_finish_block (&block);
dnovillo's avatar
 
dnovillo committed
1871 1872 1873 1874
}

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