OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [fortran/] [trans-common.c] - Blame information for rev 20

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 jlechner
/* Common block and equivalence list handling
2
   Copyright (C) 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
3
   Contributed by Canqun Yang <canqun@nudt.edu.cn>
4
 
5
This file is part of GCC.
6
 
7
GCC is free software; you can redistribute it and/or modify it under
8
the terms of the GNU General Public License as published by the Free
9
Software Foundation; either version 2, or (at your option) any later
10
version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
for more details.
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
19
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301, USA.  */
21
 
22
/* The core algorithm is based on Andy Vaught's g95 tree.  Also the
23
   way to build UNION_TYPE is borrowed from Richard Henderson.
24
 
25
   Transform common blocks.  An integral part of this is processing
26
   equivalence variables.  Equivalenced variables that are not in a
27
   common block end up in a private block of their own.
28
 
29
   Each common block or local equivalence list is declared as a union.
30
   Variables within the block are represented as a field within the
31
   block with the proper offset.
32
 
33
   So if two variables are equivalenced, they just point to a common
34
   area in memory.
35
 
36
   Mathematically, laying out an equivalence block is equivalent to
37
   solving a linear system of equations.  The matrix is usually a
38
   sparse matrix in which each row contains all zero elements except
39
   for a +1 and a -1, a sort of a generalized Vandermonde matrix.  The
40
   matrix is usually block diagonal.  The system can be
41
   overdetermined, underdetermined or have a unique solution.  If the
42
   system is inconsistent, the program is not standard conforming.
43
   The solution vector is integral, since all of the pivots are +1 or -1.
44
 
45
   How we lay out an equivalence block is a little less complicated.
46
   In an equivalence list with n elements, there are n-1 conditions to
47
   be satisfied.  The conditions partition the variables into what we
48
   will call segments.  If A and B are equivalenced then A and B are
49
   in the same segment.  If B and C are equivalenced as well, then A,
50
   B and C are in a segment and so on.  Each segment is a block of
51
   memory that has one or more variables equivalenced in some way.  A
52
   common block is made up of a series of segments that are joined one
53
   after the other.  In the linear system, a segment is a block
54
   diagonal.
55
 
56
   To lay out a segment we first start with some variable and
57
   determine its length.  The first variable is assumed to start at
58
   offset one and extends to however long it is.  We then traverse the
59
   list of equivalences to find an unused condition that involves at
60
   least one of the variables currently in the segment.
61
 
62
   Each equivalence condition amounts to the condition B+b=C+c where B
63
   and C are the offsets of the B and C variables, and b and c are
64
   constants which are nonzero for array elements, substrings or
65
   structure components.  So for
66
 
67
     EQUIVALENCE(B(2), C(3))
68
   we have
69
     B + 2*size of B's elements = C + 3*size of C's elements.
70
 
71
   If B and C are known we check to see if the condition already
72
   holds.  If B is known we can solve for C.  Since we know the length
73
   of C, we can see if the minimum and maximum extents of the segment
74
   are affected.  Eventually, we make a full pass through the
75
   equivalence list without finding any new conditions and the segment
76
   is fully specified.
77
 
78
   At this point, the segment is added to the current common block.
79
   Since we know the minimum extent of the segment, everything in the
80
   segment is translated to its position in the common block.  The
81
   usual case here is that there are no equivalence statements and the
82
   common block is series of segments with one variable each, which is
83
   a diagonal matrix in the matrix formulation.
84
 
85
   Each segment is described by a chain of segment_info structures.  Each
86
   segment_info structure describes the extents of a single varible within
87
   the segment.  This list is maintained in the order the elements are
88
   positioned withing the segment.  If two elements have the same starting
89
   offset the smaller will come first.  If they also have the same size their
90
   ordering is undefined.
91
 
92
   Once all common blocks have been created, the list of equivalences
93
   is examined for still-unused equivalence conditions.  We create a
94
   block for each merged equivalence list.  */
95
 
96
#include "config.h"
97
#include "system.h"
98
#include "coretypes.h"
99
#include "tree.h"
100
#include "toplev.h"
101
#include "tm.h"
102
#include "gfortran.h"
103
#include "trans.h"
104
#include "trans-types.h"
105
#include "trans-const.h"
106
 
107
 
108
/* Holds a single variable in an equivalence set.  */
109
typedef struct segment_info
110
{
111
  gfc_symbol *sym;
112
  HOST_WIDE_INT offset;
113
  HOST_WIDE_INT length;
114
  /* This will contain the field type until the field is created.  */
115
  tree field;
116
  struct segment_info *next;
117
} segment_info;
118
 
119
static segment_info * current_segment;
120
static gfc_namespace *gfc_common_ns = NULL;
121
 
122
 
123
/* Make a segment_info based on a symbol.  */
124
 
125
static segment_info *
126
get_segment_info (gfc_symbol * sym, HOST_WIDE_INT offset)
127
{
128
  segment_info *s;
129
 
130
  /* Make sure we've got the character length.  */
131
  if (sym->ts.type == BT_CHARACTER)
132
    gfc_conv_const_charlen (sym->ts.cl);
133
 
134
  /* Create the segment_info and fill it in.  */
135
  s = (segment_info *) gfc_getmem (sizeof (segment_info));
136
  s->sym = sym;
137
  /* We will use this type when building the segment aggregate type.  */
138
  s->field = gfc_sym_type (sym);
139
  s->length = int_size_in_bytes (s->field);
140
  s->offset = offset;
141
 
142
  return s;
143
}
144
 
145
 
146
/* Add a copy of a segment list to the namespace.  This is specifically for
147
   equivalence segments, so that dependency checking can be done on
148
   equivalence group members.  */
149
 
150
static void
151
copy_equiv_list_to_ns (segment_info *c)
152
{
153
  segment_info *f;
154
  gfc_equiv_info *s;
155
  gfc_equiv_list *l;
156
 
157
  l = (gfc_equiv_list *) gfc_getmem (sizeof (gfc_equiv_list));
158
 
159
  l->next = c->sym->ns->equiv_lists;
160
  c->sym->ns->equiv_lists = l;
161
 
162
  for (f = c; f; f = f->next)
163
    {
164
      s = (gfc_equiv_info *) gfc_getmem (sizeof (gfc_equiv_info));
165
      s->next = l->equiv;
166
      l->equiv = s;
167
      s->sym = f->sym;
168
      s->offset = f->offset;
169
    }
170
}
171
 
172
 
173
/* Add combine segment V and segment LIST.  */
174
 
175
static segment_info *
176
add_segments (segment_info *list, segment_info *v)
177
{
178
  segment_info *s;
179
  segment_info *p;
180
  segment_info *next;
181
 
182
  p = NULL;
183
  s = list;
184
 
185
  while (v)
186
    {
187
      /* Find the location of the new element.  */
188
      while (s)
189
        {
190
          if (v->offset < s->offset)
191
            break;
192
          if (v->offset == s->offset
193
              && v->length <= s->length)
194
            break;
195
 
196
          p = s;
197
          s = s->next;
198
        }
199
 
200
      /* Insert the new element in between p and s.  */
201
      next = v->next;
202
      v->next = s;
203
      if (p == NULL)
204
        list = v;
205
      else
206
        p->next = v;
207
 
208
      p = v;
209
      v = next;
210
    }
211
 
212
  return list;
213
}
214
 
215
/* Construct mangled common block name from symbol name.  */
216
 
217
static tree
218
gfc_sym_mangled_common_id (const char  *name)
219
{
220
  int has_underscore;
221
  char mangled_name[GFC_MAX_MANGLED_SYMBOL_LEN + 1];
222
 
223
  if (strcmp (name, BLANK_COMMON_NAME) == 0)
224
    return get_identifier (name);
225
 
226
  if (gfc_option.flag_underscoring)
227
    {
228
      has_underscore = strchr (name, '_') != 0;
229
      if (gfc_option.flag_second_underscore && has_underscore)
230
        snprintf (mangled_name, sizeof mangled_name, "%s__", name);
231
      else
232
        snprintf (mangled_name, sizeof mangled_name, "%s_", name);
233
 
234
      return get_identifier (mangled_name);
235
    }
236
  else
237
    return get_identifier (name);
238
}
239
 
240
 
241
/* Build a field declaration for a common variable or a local equivalence
242
   object.  */
243
 
244
static void
245
build_field (segment_info *h, tree union_type, record_layout_info rli)
246
{
247
  tree field;
248
  tree name;
249
  HOST_WIDE_INT offset = h->offset;
250
  unsigned HOST_WIDE_INT desired_align, known_align;
251
 
252
  name = get_identifier (h->sym->name);
253
  field = build_decl (FIELD_DECL, name, h->field);
254
  gfc_set_decl_location (field, &h->sym->declared_at);
255
  known_align = (offset & -offset) * BITS_PER_UNIT;
256
  if (known_align == 0 || known_align > BIGGEST_ALIGNMENT)
257
    known_align = BIGGEST_ALIGNMENT;
258
 
259
  desired_align = update_alignment_for_field (rli, field, known_align);
260
  if (desired_align > known_align)
261
    DECL_PACKED (field) = 1;
262
 
263
  DECL_FIELD_CONTEXT (field) = union_type;
264
  DECL_FIELD_OFFSET (field) = size_int (offset);
265
  DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
266
  SET_DECL_OFFSET_ALIGN (field, known_align);
267
 
268
  rli->offset = size_binop (MAX_EXPR, rli->offset,
269
                            size_binop (PLUS_EXPR,
270
                                        DECL_FIELD_OFFSET (field),
271
                                        DECL_SIZE_UNIT (field)));
272
  /* If this field is assigned to a label, we create another two variables.
273
     One will hold the address of target label or format label. The other will
274
     hold the length of format label string.  */
275
  if (h->sym->attr.assign)
276
    {
277
      tree len;
278
      tree addr;
279
 
280
      gfc_allocate_lang_decl (field);
281
      GFC_DECL_ASSIGN (field) = 1;
282
      len = gfc_create_var_np (gfc_charlen_type_node,h->sym->name);
283
      addr = gfc_create_var_np (pvoid_type_node, h->sym->name);
284
      TREE_STATIC (len) = 1;
285
      TREE_STATIC (addr) = 1;
286
      DECL_INITIAL (len) = build_int_cst (NULL_TREE, -2);
287
      gfc_set_decl_location (len, &h->sym->declared_at);
288
      gfc_set_decl_location (addr, &h->sym->declared_at);
289
      GFC_DECL_STRING_LEN (field) = pushdecl_top_level (len);
290
      GFC_DECL_ASSIGN_ADDR (field) = pushdecl_top_level (addr);
291
    }
292
 
293
  h->field = field;
294
}
295
 
296
 
297
/* Get storage for local equivalence.  */
298
 
299
static tree
300
build_equiv_decl (tree union_type, bool is_init, bool is_saved)
301
{
302
  tree decl;
303
  char name[15];
304
  static int serial = 0;
305
 
306
  if (is_init)
307
    {
308
      decl = gfc_create_var (union_type, "equiv");
309
      TREE_STATIC (decl) = 1;
310
      return decl;
311
    }
312
 
313
  snprintf (name, sizeof (name), "equiv.%d", serial++);
314
  decl = build_decl (VAR_DECL, get_identifier (name), union_type);
315
  DECL_ARTIFICIAL (decl) = 1;
316
  DECL_IGNORED_P (decl) = 1;
317
 
318
  if (!gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))
319
      || is_saved)
320
    TREE_STATIC (decl) = 1;
321
 
322
  TREE_ADDRESSABLE (decl) = 1;
323
  TREE_USED (decl) = 1;
324
 
325
  /* The source location has been lost, and doesn't really matter.
326
     We need to set it to something though.  */
327
  gfc_set_decl_location (decl, &gfc_current_locus);
328
 
329
  gfc_add_decl_to_function (decl);
330
 
331
  return decl;
332
}
333
 
334
 
335
/* Get storage for common block.  */
336
 
337
static tree
338
build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
339
{
340
  gfc_symbol *common_sym;
341
  tree decl;
342
 
343
  /* Create a namespace to store symbols for common blocks.  */
344
  if (gfc_common_ns == NULL)
345
    gfc_common_ns = gfc_get_namespace (NULL, 0);
346
 
347
  gfc_get_symbol (com->name, gfc_common_ns, &common_sym);
348
  decl = common_sym->backend_decl;
349
 
350
  /* Update the size of this common block as needed.  */
351
  if (decl != NULL_TREE)
352
    {
353
      tree size = TYPE_SIZE_UNIT (union_type);
354
      if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size))
355
        {
356
          /* Named common blocks of the same name shall be of the same size
357
             in all scoping units of a program in which they appear, but
358
             blank common blocks may be of different sizes.  */
359
          if (strcmp (com->name, BLANK_COMMON_NAME))
360
            gfc_warning ("Named COMMON block '%s' at %L shall be of the "
361
                         "same size", com->name, &com->where);
362
          DECL_SIZE_UNIT (decl) = size;
363
        }
364
     }
365
 
366
  /* If this common block has been declared in a previous program unit,
367
     and either it is already initialized or there is no new initialization
368
     for it, just return.  */
369
  if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl)))
370
    return decl;
371
 
372
  /* If there is no backend_decl for the common block, build it.  */
373
  if (decl == NULL_TREE)
374
    {
375
      decl = build_decl (VAR_DECL, get_identifier (com->name), union_type);
376
      SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (com->name));
377
      TREE_PUBLIC (decl) = 1;
378
      TREE_STATIC (decl) = 1;
379
      DECL_ALIGN (decl) = BIGGEST_ALIGNMENT;
380
      DECL_USER_ALIGN (decl) = 0;
381
 
382
      gfc_set_decl_location (decl, &com->where);
383
 
384
      /* Place the back end declaration for this common block in
385
         GLOBAL_BINDING_LEVEL.  */
386
      common_sym->backend_decl = pushdecl_top_level (decl);
387
    }
388
 
389
  /* Has no initial values.  */
390
  if (!is_init)
391
    {
392
      DECL_INITIAL (decl) = NULL_TREE;
393
      DECL_COMMON (decl) = 1;
394
      DECL_DEFER_OUTPUT (decl) = 1;
395
    }
396
  else
397
    {
398
      DECL_INITIAL (decl) = error_mark_node;
399
      DECL_COMMON (decl) = 0;
400
      DECL_DEFER_OUTPUT (decl) = 0;
401
    }
402
  return decl;
403
}
404
 
405
 
406
/* Declare memory for the common block or local equivalence, and create
407
   backend declarations for all of the elements.  */
408
 
409
static void
410
create_common (gfc_common_head *com, segment_info * head, bool saw_equiv)
411
{
412
  segment_info *s, *next_s;
413
  tree union_type;
414
  tree *field_link;
415
  record_layout_info rli;
416
  tree decl;
417
  bool is_init = false;
418
  bool is_saved = false;
419
 
420
  /* Declare the variables inside the common block.
421
     If the current common block contains any equivalence object, then
422
     make a UNION_TYPE node, otherwise RECORD_TYPE. This will let the
423
     alias analyzer work well when there is no address overlapping for
424
     common variables in the current common block.  */
425
  if (saw_equiv)
426
    union_type = make_node (UNION_TYPE);
427
  else
428
    union_type = make_node (RECORD_TYPE);
429
 
430
  rli = start_record_layout (union_type);
431
  field_link = &TYPE_FIELDS (union_type);
432
 
433
  for (s = head; s; s = s->next)
434
    {
435
      build_field (s, union_type, rli);
436
 
437
      /* Link the field into the type.  */
438
      *field_link = s->field;
439
      field_link = &TREE_CHAIN (s->field);
440
 
441
      /* Has initial value.  */
442
      if (s->sym->value)
443
        is_init = true;
444
 
445
      /* Has SAVE attribute.  */
446
      if (s->sym->attr.save)
447
        is_saved = true;
448
    }
449
  finish_record_layout (rli, true);
450
 
451
  if (com)
452
    decl = build_common_decl (com, union_type, is_init);
453
  else
454
    decl = build_equiv_decl (union_type, is_init, is_saved);
455
 
456
  if (is_init)
457
    {
458
      tree ctor, tmp;
459
      HOST_WIDE_INT offset = 0;
460
      VEC(constructor_elt,gc) *v = NULL;
461
 
462
      for (s = head; s; s = s->next)
463
        {
464
          if (s->sym->value)
465
            {
466
              if (s->offset < offset)
467
                {
468
                    /* We have overlapping initializers.  It could either be
469
                       partially initialized arrays (legal), or the user
470
                       specified multiple initial values (illegal).
471
                       We don't implement this yet, so bail out.  */
472
                  gfc_todo_error ("Initialization of overlapping variables");
473
                }
474
              /* Add the initializer for this field.  */
475
              tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts,
476
                  TREE_TYPE (s->field), s->sym->attr.dimension,
477
                  s->sym->attr.pointer || s->sym->attr.allocatable);
478
 
479
              CONSTRUCTOR_APPEND_ELT (v, s->field, tmp);
480
              offset = s->offset + s->length;
481
            }
482
        }
483
      gcc_assert (!VEC_empty (constructor_elt, v));
484
      ctor = build_constructor (union_type, v);
485
      TREE_CONSTANT (ctor) = 1;
486
      TREE_INVARIANT (ctor) = 1;
487
      TREE_STATIC (ctor) = 1;
488
      DECL_INITIAL (decl) = ctor;
489
 
490
#ifdef ENABLE_CHECKING
491
      {
492
        tree field, value;
493
        unsigned HOST_WIDE_INT idx;
494
        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, field, value)
495
          gcc_assert (TREE_CODE (field) == FIELD_DECL);
496
      }
497
#endif
498
    }
499
 
500
  /* Build component reference for each variable.  */
501
  for (s = head; s; s = next_s)
502
    {
503
      tree var_decl;
504
 
505
      var_decl = build_decl (VAR_DECL, DECL_NAME (s->field),
506
                             TREE_TYPE (s->field));
507
      gfc_set_decl_location (var_decl, &s->sym->declared_at);
508
      TREE_PUBLIC (var_decl) = TREE_PUBLIC (decl);
509
      TREE_STATIC (var_decl) = TREE_STATIC (decl);
510
      TREE_USED (var_decl) = TREE_USED (decl);
511
      if (s->sym->attr.target)
512
        TREE_ADDRESSABLE (var_decl) = 1;
513
      /* This is a fake variable just for debugging purposes.  */
514
      TREE_ASM_WRITTEN (var_decl) = 1;
515
 
516
      if (com)
517
        var_decl = pushdecl_top_level (var_decl);
518
      else
519
        gfc_add_decl_to_function (var_decl);
520
 
521
      SET_DECL_VALUE_EXPR (var_decl,
522
                           build3 (COMPONENT_REF, TREE_TYPE (s->field),
523
                                   decl, s->field, NULL_TREE));
524
      DECL_HAS_VALUE_EXPR_P (var_decl) = 1;
525
 
526
      if (s->sym->attr.assign)
527
        {
528
          gfc_allocate_lang_decl (var_decl);
529
          GFC_DECL_ASSIGN (var_decl) = 1;
530
          GFC_DECL_STRING_LEN (var_decl) = GFC_DECL_STRING_LEN (s->field);
531
          GFC_DECL_ASSIGN_ADDR (var_decl) = GFC_DECL_ASSIGN_ADDR (s->field);
532
        }
533
 
534
      s->sym->backend_decl = var_decl;
535
 
536
      next_s = s->next;
537
      gfc_free (s);
538
    }
539
}
540
 
541
 
542
/* Given a symbol, find it in the current segment list. Returns NULL if
543
   not found.  */
544
 
545
static segment_info *
546
find_segment_info (gfc_symbol *symbol)
547
{
548
  segment_info *n;
549
 
550
  for (n = current_segment; n; n = n->next)
551
    {
552
      if (n->sym == symbol)
553
        return n;
554
    }
555
 
556
  return NULL;
557
}
558
 
559
 
560
/* Given an expression node, make sure it is a constant integer and return
561
   the mpz_t value.  */
562
 
563
static mpz_t *
564
get_mpz (gfc_expr *e)
565
{
566
 
567
  if (e->expr_type != EXPR_CONSTANT)
568
    gfc_internal_error ("get_mpz(): Not an integer constant");
569
 
570
  return &e->value.integer;
571
}
572
 
573
 
574
/* Given an array specification and an array reference, figure out the
575
   array element number (zero based). Bounds and elements are guaranteed
576
   to be constants.  If something goes wrong we generate an error and
577
   return zero.  */
578
 
579
static HOST_WIDE_INT
580
element_number (gfc_array_ref *ar)
581
{
582
  mpz_t multiplier, offset, extent, n;
583
  gfc_array_spec *as;
584
  HOST_WIDE_INT i, rank;
585
 
586
  as = ar->as;
587
  rank = as->rank;
588
  mpz_init_set_ui (multiplier, 1);
589
  mpz_init_set_ui (offset, 0);
590
  mpz_init (extent);
591
  mpz_init (n);
592
 
593
  for (i = 0; i < rank; i++)
594
    {
595
      if (ar->dimen_type[i] != DIMEN_ELEMENT)
596
        gfc_internal_error ("element_number(): Bad dimension type");
597
 
598
      mpz_sub (n, *get_mpz (ar->start[i]), *get_mpz (as->lower[i]));
599
 
600
      mpz_mul (n, n, multiplier);
601
      mpz_add (offset, offset, n);
602
 
603
      mpz_sub (extent, *get_mpz (as->upper[i]), *get_mpz (as->lower[i]));
604
      mpz_add_ui (extent, extent, 1);
605
 
606
      if (mpz_sgn (extent) < 0)
607
        mpz_set_ui (extent, 0);
608
 
609
      mpz_mul (multiplier, multiplier, extent);
610
    }
611
 
612
  i = mpz_get_ui (offset);
613
 
614
  mpz_clear (multiplier);
615
  mpz_clear (offset);
616
  mpz_clear (extent);
617
  mpz_clear (n);
618
 
619
  return i;
620
}
621
 
622
 
623
/* Given a single element of an equivalence list, figure out the offset
624
   from the base symbol.  For simple variables or full arrays, this is
625
   simply zero.  For an array element we have to calculate the array
626
   element number and multiply by the element size. For a substring we
627
   have to calculate the further reference.  */
628
 
629
static HOST_WIDE_INT
630
calculate_offset (gfc_expr *e)
631
{
632
  HOST_WIDE_INT n, element_size, offset;
633
  gfc_typespec *element_type;
634
  gfc_ref *reference;
635
 
636
  offset = 0;
637
  element_type = &e->symtree->n.sym->ts;
638
 
639
  for (reference = e->ref; reference; reference = reference->next)
640
    switch (reference->type)
641
      {
642
      case REF_ARRAY:
643
        switch (reference->u.ar.type)
644
          {
645
          case AR_FULL:
646
            break;
647
 
648
          case AR_ELEMENT:
649
            n = element_number (&reference->u.ar);
650
            if (element_type->type == BT_CHARACTER)
651
              gfc_conv_const_charlen (element_type->cl);
652
            element_size =
653
              int_size_in_bytes (gfc_typenode_for_spec (element_type));
654
            offset += n * element_size;
655
            break;
656
 
657
          default:
658
            gfc_error ("Bad array reference at %L", &e->where);
659
          }
660
        break;
661
      case REF_SUBSTRING:
662
        if (reference->u.ss.start != NULL)
663
          offset += mpz_get_ui (*get_mpz (reference->u.ss.start)) - 1;
664
        break;
665
      default:
666
        gfc_error ("Illegal reference type at %L as EQUIVALENCE object",
667
                   &e->where);
668
    }
669
  return offset;
670
}
671
 
672
 
673
/* Add a new segment_info structure to the current segment.  eq1 is already
674
   in the list, eq2 is not.  */
675
 
676
static void
677
new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2)
678
{
679
  HOST_WIDE_INT offset1, offset2;
680
  segment_info *a;
681
 
682
  offset1 = calculate_offset (eq1->expr);
683
  offset2 = calculate_offset (eq2->expr);
684
 
685
  a = get_segment_info (eq2->expr->symtree->n.sym,
686
                        v->offset + offset1 - offset2);
687
 
688
  current_segment = add_segments (current_segment, a);
689
}
690
 
691
 
692
/* Given two equivalence structures that are both already in the list, make
693
   sure that this new condition is not violated, generating an error if it
694
   is.  */
695
 
696
static void
697
confirm_condition (segment_info *s1, gfc_equiv *eq1, segment_info *s2,
698
                   gfc_equiv *eq2)
699
{
700
  HOST_WIDE_INT offset1, offset2;
701
 
702
  offset1 = calculate_offset (eq1->expr);
703
  offset2 = calculate_offset (eq2->expr);
704
 
705
  if (s1->offset + offset1 != s2->offset + offset2)
706
    gfc_error ("Inconsistent equivalence rules involving '%s' at %L and "
707
               "'%s' at %L", s1->sym->name, &s1->sym->declared_at,
708
               s2->sym->name, &s2->sym->declared_at);
709
}
710
 
711
 
712
/* Process a new equivalence condition. eq1 is know to be in segment f.
713
   If eq2 is also present then confirm that the condition holds.
714
   Otherwise add a new variable to the segment list.  */
715
 
716
static void
717
add_condition (segment_info *f, gfc_equiv *eq1, gfc_equiv *eq2)
718
{
719
  segment_info *n;
720
 
721
  n = find_segment_info (eq2->expr->symtree->n.sym);
722
 
723
  if (n == NULL)
724
    new_condition (f, eq1, eq2);
725
  else
726
    confirm_condition (f, eq1, n, eq2);
727
}
728
 
729
 
730
/* Given a segment element, search through the equivalence lists for unused
731
   conditions that involve the symbol.  Add these rules to the segment.  */
732
 
733
static bool
734
find_equivalence (segment_info *n)
735
{
736
  gfc_equiv *e1, *e2, *eq;
737
  bool found;
738
 
739
  found = FALSE;
740
 
741
  for (e1 = n->sym->ns->equiv; e1; e1 = e1->next)
742
    {
743
      eq = NULL;
744
 
745
      /* Search the equivalence list, including the root (first) element
746
         for the symbol that owns the segment.  */
747
      for (e2 = e1; e2; e2 = e2->eq)
748
        {
749
          if (!e2->used && e2->expr->symtree->n.sym == n->sym)
750
            {
751
              eq = e2;
752
              break;
753
            }
754
        }
755
 
756
      /* Go to the next root element.  */
757
      if (eq == NULL)
758
        continue;
759
 
760
      eq->used = 1;
761
 
762
      /* Now traverse the equivalence list matching the offsets.  */
763
      for (e2 = e1; e2; e2 = e2->eq)
764
        {
765
          if (!e2->used && e2 != eq)
766
            {
767
              add_condition (n, eq, e2);
768
              e2->used = 1;
769
              found = TRUE;
770
            }
771
        }
772
    }
773
  return found;
774
}
775
 
776
 
777
  /* Add all symbols equivalenced within a segment.  We need to scan the
778
   segment list multiple times to include indirect equivalences.  Since
779
   a new segment_info can inserted at the beginning of the segment list,
780
   depending on its offset, we have to force a final pass through the
781
   loop by demanding that completion sees a pass with no matches; ie.
782
   all symbols with equiv_built set and no new equivalences found.  */
783
 
784
static void
785
add_equivalences (bool *saw_equiv)
786
{
787
  segment_info *f;
788
  bool seen_one, more;
789
 
790
  seen_one = false;
791
  more = TRUE;
792
  while (more)
793
    {
794
      more = FALSE;
795
      for (f = current_segment; f; f = f->next)
796
        {
797
          if (!f->sym->equiv_built)
798
            {
799
              f->sym->equiv_built = 1;
800
              seen_one = find_equivalence (f);
801
              if (seen_one)
802
                {
803
                  *saw_equiv = true;
804
                  more = true;
805
                }
806
            }
807
        }
808
    }
809
 
810
  /* Add a copy of this segment list to the namespace.  */
811
  copy_equiv_list_to_ns (current_segment);
812
}
813
 
814
 
815
/* Returns the offset necessary to properly align the current equivalence.
816
   Sets *palign to the required alignment.  */
817
 
818
static HOST_WIDE_INT
819
align_segment (unsigned HOST_WIDE_INT * palign)
820
{
821
  segment_info *s;
822
  unsigned HOST_WIDE_INT offset;
823
  unsigned HOST_WIDE_INT max_align;
824
  unsigned HOST_WIDE_INT this_align;
825
  unsigned HOST_WIDE_INT this_offset;
826
 
827
  max_align = 1;
828
  offset = 0;
829
  for (s = current_segment; s; s = s->next)
830
    {
831
      this_align = TYPE_ALIGN_UNIT (s->field);
832
      if (s->offset & (this_align - 1))
833
        {
834
          /* Field is misaligned.  */
835
          this_offset = this_align - ((s->offset + offset) & (this_align - 1));
836
          if (this_offset & (max_align - 1))
837
            {
838
              /* Aligning this field would misalign a previous field.  */
839
              gfc_error ("The equivalence set for variable '%s' "
840
                         "declared at %L violates alignment requirents",
841
                         s->sym->name, &s->sym->declared_at);
842
            }
843
          offset += this_offset;
844
        }
845
      max_align = this_align;
846
    }
847
  if (palign)
848
    *palign = max_align;
849
  return offset;
850
}
851
 
852
 
853
/* Adjust segment offsets by the given amount.  */
854
 
855
static void
856
apply_segment_offset (segment_info * s, HOST_WIDE_INT offset)
857
{
858
  for (; s; s = s->next)
859
    s->offset += offset;
860
}
861
 
862
 
863
/* Lay out a symbol in a common block.  If the symbol has already been seen
864
   then check the location is consistent.  Otherwise create segments
865
   for that symbol and all the symbols equivalenced with it.  */
866
 
867
/* Translate a single common block.  */
868
 
869
static void
870
translate_common (gfc_common_head *common, gfc_symbol *var_list)
871
{
872
  gfc_symbol *sym;
873
  segment_info *s;
874
  segment_info *common_segment;
875
  HOST_WIDE_INT offset;
876
  HOST_WIDE_INT current_offset;
877
  unsigned HOST_WIDE_INT align;
878
  unsigned HOST_WIDE_INT max_align;
879
  bool saw_equiv;
880
 
881
  common_segment = NULL;
882
  current_offset = 0;
883
  max_align = 1;
884
  saw_equiv = false;
885
 
886
  /* Add symbols to the segment.  */
887
  for (sym = var_list; sym; sym = sym->common_next)
888
    {
889
      current_segment = common_segment;
890
      s = find_segment_info (sym);
891
 
892
      /* Symbol has already been added via an equivalence.  Multiple
893
         use associations of the same common block result in equiv_built
894
         being set but no information about the symbol in the segment.  */
895
      if (s && sym->equiv_built)
896
        {
897
          /* Ensure the current location is properly aligned.  */
898
          align = TYPE_ALIGN_UNIT (s->field);
899
          current_offset = (current_offset + align - 1) &~ (align - 1);
900
 
901
          /* Verify that it ended up where we expect it.  */
902
          if (s->offset != current_offset)
903
            {
904
              gfc_error ("Equivalence for '%s' does not match ordering of "
905
                         "COMMON '%s' at %L", sym->name,
906
                         common->name, &common->where);
907
            }
908
        }
909
      else
910
        {
911
          /* A symbol we haven't seen before.  */
912
          s = current_segment = get_segment_info (sym, current_offset);
913
 
914
          /* Add all objects directly or indirectly equivalenced with this
915
             symbol.  */
916
          add_equivalences (&saw_equiv);
917
 
918
          if (current_segment->offset < 0)
919
            gfc_error ("The equivalence set for '%s' cause an invalid "
920
                       "extension to COMMON '%s' at %L", sym->name,
921
                       common->name, &common->where);
922
 
923
          offset = align_segment (&align);
924
 
925
          if (offset & (max_align - 1))
926
            {
927
              /* The required offset conflicts with previous alignment
928
                 requirements.  Insert padding immediately before this
929
                 segment.  */
930
              gfc_warning ("Padding of %d bytes required before '%s' in "
931
                           "COMMON '%s' at %L", (int)offset, s->sym->name,
932
                           common->name, &common->where);
933
            }
934
          else
935
            {
936
              /* Offset the whole common block.  */
937
              apply_segment_offset (common_segment, offset);
938
            }
939
 
940
          /* Apply the offset to the new segments.  */
941
          apply_segment_offset (current_segment, offset);
942
          current_offset += offset;
943
          if (max_align < align)
944
            max_align = align;
945
 
946
          /* Add the new segments to the common block.  */
947
          common_segment = add_segments (common_segment, current_segment);
948
        }
949
 
950
      /* The offset of the next common variable.  */
951
      current_offset += s->length;
952
    }
953
 
954
  if (common_segment->offset != 0)
955
    {
956
      gfc_warning ("COMMON '%s' at %L requires %d bytes of padding at start",
957
                   common->name, &common->where, (int)common_segment->offset);
958
    }
959
 
960
  create_common (common, common_segment, saw_equiv);
961
}
962
 
963
 
964
/* Create a new block for each merged equivalence list.  */
965
 
966
static void
967
finish_equivalences (gfc_namespace *ns)
968
{
969
  gfc_equiv *z, *y;
970
  gfc_symbol *sym;
971
  gfc_common_head * c;
972
  HOST_WIDE_INT offset;
973
  unsigned HOST_WIDE_INT align;
974
  bool dummy;
975
 
976
  for (z = ns->equiv; z; z = z->next)
977
    for (y = z->eq; y; y = y->eq)
978
      {
979
        if (y->used)
980
          continue;
981
        sym = z->expr->symtree->n.sym;
982
        current_segment = get_segment_info (sym, 0);
983
 
984
        /* All objects directly or indirectly equivalenced with this symbol.  */
985
        add_equivalences (&dummy);
986
 
987
        /* Align the block.  */
988
        offset = align_segment (&align);
989
 
990
        /* Ensure all offsets are positive.  */
991
        offset -= current_segment->offset & ~(align - 1);
992
 
993
        apply_segment_offset (current_segment, offset);
994
 
995
        /* Create the decl. If this is a module equivalence, it has a unique
996
           name, pointed to by z->module. This is written to a gfc_common_header
997
           to push create_common into using build_common_decl, so that the
998
           equivalence appears as an external symbol. Otherwise, a local
999
           declaration is built using build_equiv_decl.*/
1000
        if (z->module)
1001
          {
1002
            c = gfc_get_common_head ();
1003
            /* We've lost the real location, so use the location of the
1004
             enclosing procedure.  */
1005
            c->where = ns->proc_name->declared_at;
1006
            strcpy (c->name, z->module);
1007
          }
1008
        else
1009
          c = NULL;
1010
 
1011
        create_common (c, current_segment, true);
1012
        break;
1013
      }
1014
}
1015
 
1016
 
1017
/* Work function for translating a named common block.  */
1018
 
1019
static void
1020
named_common (gfc_symtree *st)
1021
{
1022
  translate_common (st->n.common, st->n.common->head);
1023
}
1024
 
1025
 
1026
/* Translate the common blocks in a namespace. Unlike other variables,
1027
   these have to be created before code, because the backend_decl depends
1028
   on the rest of the common block.  */
1029
 
1030
void
1031
gfc_trans_common (gfc_namespace *ns)
1032
{
1033
  gfc_common_head *c;
1034
 
1035
  /* Translate the blank common block.  */
1036
  if (ns->blank_common.head != NULL)
1037
    {
1038
      c = gfc_get_common_head ();
1039
      /* We've lost the real location, so use the location of the
1040
         enclosing procedure.  */
1041
      c->where = ns->proc_name->declared_at;
1042
      strcpy (c->name, BLANK_COMMON_NAME);
1043
      translate_common (c, ns->blank_common.head);
1044
    }
1045
 
1046
  /* Translate all named common blocks.  */
1047
  gfc_traverse_symtree (ns->common_root, named_common);
1048
 
1049
  /* Translate local equivalence.  */
1050
  finish_equivalences (ns);
1051
 
1052
  /* Commit the newly created symbols for common blocks and module
1053
     equivalences.  */
1054
  gfc_commit_symbols ();
1055
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.