]> gcc.gnu.org Git - gcc.git/blob - gcc/m2/gm2-gcc/m2block.c
56c88d053209742b7c2f6deb62744b8535becf2b
[gcc.git] / gcc / m2 / gm2-gcc / m2block.c
1 /* m2block.c provides an interface to maintaining block structures.
2
3 Copyright (C) 2012-2021 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius@glam.ac.uk>.
5
6 This file is part of GNU Modula-2.
7
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include "gcc-consolidation.h"
23
24 #define m2block_c
25 #include "m2assert.h"
26 #include "m2block.h"
27 #include "m2decl.h"
28 #include "m2options.h"
29 #include "m2tree.h"
30 #include "m2treelib.h"
31
32 /* For each binding contour we allocate a binding_level structure
33 which records the entities defined or declared in that contour.
34 Contours include:
35
36 the global one one for each subprogram definition
37
38 Binding contours are used to create GCC tree BLOCK nodes. */
39
40 struct GTY (()) binding_level
41 {
42 /* The function associated with the scope. This is NULL_TREE for the
43 global scope. */
44 tree fndecl;
45
46 /* A chain of _DECL nodes for all variables, constants, functions,
47 and typedef types. These are in the reverse of the order supplied. */
48 tree names;
49
50 /* A boolean to indicate whether this is binding level is a global ie
51 outer module scope. In which case fndecl will be NULL_TREE. */
52 int is_global;
53
54 /* The context of the binding level, for a function binding level
55 this will be the same as fndecl, however for a global binding level
56 this is a translation_unit. */
57 tree context;
58
59 /* The binding level below this one. This field is only used when
60 the binding level has been pushed by pushFunctionScope. */
61 struct binding_level *next;
62
63 /* All binding levels are placed onto this list. */
64 struct binding_level *list;
65
66 /* A varray of trees, which represent the list of statement
67 sequences. */
68 vec<tree, va_gc> *m2_statements;
69
70 /* A list of constants (only kept in the global binding level).
71 Constants need to be kept through the life of the compilation, as the
72 same constants can be used in any scope. */
73 tree constants;
74
75 /* A list of inner module initialisation functions. */
76 tree init_functions;
77
78 /* A list of types created by M2GCCDeclare prior to code generation
79 and those which may not be specifically declared and saved via a
80 push_decl. */
81 tree types;
82
83 /* A list of all DECL_EXPR created within this binding level. This
84 will be prepended to the statement list once the binding level (scope
85 is finished). */
86 tree decl;
87
88 /* A list of labels which have been created in this scope. */
89 tree labels;
90
91 /* The number of times this level has been pushed. */
92 int count;
93 };
94
95 /* The binding level currently in effect. */
96
97 static GTY (()) struct binding_level *current_binding_level;
98
99 /* The outermost binding level, for names of file scope. This is
100 created when the compiler is started and exists through the entire
101 run. */
102
103 static GTY (()) struct binding_level *global_binding_level;
104
105 /* The head of the binding level lists. */
106 static GTY (()) struct binding_level *head_binding_level;
107
108 /* The current statement tree. */
109
110 typedef struct stmt_tree_s *stmt_tree_t;
111
112 #undef DEBUGGING
113
114 static location_t pending_location;
115 static int pending_statement = FALSE;
116
117 /* assert_global_names - asserts that the global_binding_level->names
118 can be chained. */
119
120 static void
121 assert_global_names (void)
122 {
123 tree p = global_binding_level->names;
124
125 while (p)
126 p = TREE_CHAIN (p);
127 }
128
129 /* lookupLabel - return label tree in current scope, otherwise
130 NULL_TREE. */
131
132 static tree
133 lookupLabel (tree id)
134 {
135 tree t;
136
137 for (t = current_binding_level->labels; t != NULL_TREE; t = TREE_CHAIN (t))
138 {
139 tree l = TREE_VALUE (t);
140
141 if (id == DECL_NAME (l))
142 return l;
143 }
144 return NULL_TREE;
145 }
146
147 /* getLabel - return the label, name, or create a label, name in the
148 current scope. */
149
150 tree
151 m2block_getLabel (location_t location, char *name)
152 {
153 tree id = get_identifier (name);
154 tree label = lookupLabel (id);
155
156 if (label == NULL_TREE)
157 {
158 label = build_decl (location, LABEL_DECL, id, void_type_node);
159 current_binding_level->labels
160 = tree_cons (NULL_TREE, label, current_binding_level->labels);
161 }
162 if (DECL_CONTEXT (label) == NULL_TREE)
163 DECL_CONTEXT (label) = current_function_decl;
164 ASSERT ((DECL_CONTEXT (label) == current_function_decl),
165 current_function_decl);
166
167 DECL_MODE (label) = VOIDmode;
168 return label;
169 }
170
171 static void
172 init_binding_level (struct binding_level *l)
173 {
174 l->fndecl = NULL;
175 l->names = NULL;
176 l->is_global = 0;
177 l->context = NULL;
178 l->next = NULL;
179 l->list = NULL;
180 vec_alloc (l->m2_statements, 1);
181 l->constants = NULL;
182 l->init_functions = NULL;
183 l->types = NULL;
184 l->decl = NULL;
185 l->labels = NULL;
186 l->count = 0;
187 }
188
189 static struct binding_level *
190 newLevel (void)
191 {
192 struct binding_level *newlevel = ggc_alloc<binding_level> ();
193
194 init_binding_level (newlevel);
195
196 /* now we a push_statement_list. */
197 vec_safe_push (newlevel->m2_statements, m2block_begin_statement_list ());
198 return newlevel;
199 }
200
201 tree *
202 m2block_cur_stmt_list_addr (void)
203 {
204 ASSERT_CONDITION (current_binding_level != NULL);
205 int l = vec_safe_length (current_binding_level->m2_statements) - 1;
206
207 return &(*current_binding_level->m2_statements)[l];
208 }
209
210 tree
211 m2block_cur_stmt_list (void)
212 {
213 tree *t = m2block_cur_stmt_list_addr ();
214
215 return *t;
216 }
217
218 /* is_building_stmt_list - returns TRUE if we are building a
219 statement list. TRUE is returned if we are in a binding level and
220 a statement list is under construction. */
221
222 int
223 m2block_is_building_stmt_list (void)
224 {
225 ASSERT_CONDITION (current_binding_level != NULL);
226 return !vec_safe_is_empty (current_binding_level->m2_statements);
227 }
228
229 /* push_statement_list - pushes the statement list, t, onto the
230 current binding level. */
231
232 tree
233 m2block_push_statement_list (tree t)
234 {
235 ASSERT_CONDITION (current_binding_level != NULL);
236 vec_safe_push (current_binding_level->m2_statements, t);
237 return t;
238 }
239
240 /* pop_statement_list - pops and returns a statement list from the
241 current binding level. */
242
243 tree
244 m2block_pop_statement_list (void)
245 {
246 ASSERT_CONDITION (current_binding_level != NULL);
247 {
248 tree t = current_binding_level->m2_statements->pop ();
249
250 return t;
251 }
252 }
253
254 /* begin_statement_list - starts a tree statement. It pushes the
255 statement list and returns the list node. */
256
257 tree
258 m2block_begin_statement_list (void)
259 {
260 return alloc_stmt_list ();
261 }
262
263 /* end_statement_list - returns the current statement tree. The
264 current statement tree is popped from the statement stack and the
265 list node is returned. */
266
267 tree
268 m2block_end_statement_list (tree t)
269 {
270 /* should we do anything with, t? Specifically we may need to test
271 for the presence of a label --fixme-- check this */
272 return t;
273 }
274
275 /* findLevel - returns the binding level associated with, fndecl, one
276 is created if there is no existing one on head_binding_level. */
277
278 static struct binding_level *
279 findLevel (tree fndecl)
280 {
281 struct binding_level *b;
282
283 if (fndecl == NULL_TREE)
284 return global_binding_level;
285
286 b = head_binding_level;
287 while ((b != NULL) && (b->fndecl != fndecl))
288 b = b->list;
289
290 if (b == NULL)
291 {
292 b = newLevel ();
293 b->fndecl = fndecl;
294 b->context = fndecl;
295 b->is_global = FALSE;
296 b->list = head_binding_level;
297 b->next = NULL;
298 }
299 return b;
300 }
301
302 /* pushFunctionScope - push a binding level. */
303
304 void
305 m2block_pushFunctionScope (tree fndecl)
306 {
307 struct binding_level *n;
308 struct binding_level *b;
309
310 #if defined(DEBUGGING)
311 if (fndecl != NULL)
312 printf ("pushFunctionScope\n");
313 #endif
314
315 /* allow multiple consecutive pushes of the same scope. */
316
317 if (current_binding_level != NULL
318 && (current_binding_level->fndecl == fndecl))
319 {
320 current_binding_level->count++;
321 return;
322 }
323
324 /* firstly check to see that fndecl is not already on the binding
325 stack. */
326
327 for (b = current_binding_level; b != NULL; b = b->next)
328 /* only allowed one instance of the binding on the stack at a time. */
329 ASSERT_CONDITION (b->fndecl != fndecl);
330
331 n = findLevel (fndecl);
332
333 /* Add this level to the front of the stack. */
334 n->next = current_binding_level;
335 current_binding_level = n;
336 }
337
338 /* popFunctionScope - pops a binding level, returning the function
339 associated with the binding level. */
340
341 tree
342 m2block_popFunctionScope (void)
343 {
344 tree fndecl = current_binding_level->fndecl;
345
346 #if defined(DEBUGGING)
347 if (fndecl != NULL)
348 printf ("popFunctionScope\n");
349 #endif
350
351 if (current_binding_level->count > 0)
352 {
353 /* multiple pushes have occurred of the same function scope (and
354 ignored), pop them likewise. */
355 current_binding_level->count--;
356 return fndecl;
357 }
358 ASSERT_CONDITION (current_binding_level->fndecl
359 != NULL_TREE); /* expecting local scope. */
360
361 ASSERT_CONDITION (current_binding_level->constants
362 == NULL_TREE); /* should not be used. */
363 ASSERT_CONDITION (current_binding_level->names
364 == NULL_TREE); /* should be cleared. */
365 ASSERT_CONDITION (current_binding_level->decl
366 == NULL_TREE); /* should be cleared. */
367
368 current_binding_level = current_binding_level->next;
369 return fndecl;
370 }
371
372 /* pushGlobalScope - push the global scope onto the binding level
373 stack. There can only ever be one instance of the global binding
374 level on the stack. */
375
376 void
377 m2block_pushGlobalScope (void)
378 {
379 #if defined(DEBUGGING)
380 printf ("pushGlobalScope\n");
381 #endif
382 m2block_pushFunctionScope (NULL_TREE);
383 }
384
385 /* popGlobalScope - pops the current binding level, it expects this
386 binding level to be the global binding level. */
387
388 void
389 m2block_popGlobalScope (void)
390 {
391 ASSERT_CONDITION (
392 current_binding_level->is_global); /* expecting global scope. */
393 ASSERT_CONDITION (current_binding_level == global_binding_level);
394
395 if (current_binding_level->count > 0)
396 {
397 current_binding_level->count--;
398 return;
399 }
400
401 current_binding_level = current_binding_level->next;
402 #if defined(DEBUGGING)
403 printf ("popGlobalScope\n");
404 #endif
405
406 assert_global_names ();
407 }
408
409 /* finishFunctionDecl - removes declarations from the current binding
410 level and places them inside fndecl. The current binding level is
411 then able to be destroyed by a call to popFunctionScope.
412
413 The extra tree nodes associated with fndecl will be created such
414 as BIND_EXPR, BLOCK and the initial STATEMENT_LIST containing the
415 DECL_EXPR is also created. */
416
417 void
418 m2block_finishFunctionDecl (location_t location, tree fndecl)
419 {
420 tree context = current_binding_level->context;
421 tree block = DECL_INITIAL (fndecl);
422 tree bind_expr = DECL_SAVED_TREE (fndecl);
423 tree i;
424
425 if (block == NULL_TREE)
426 {
427 block = make_node (BLOCK);
428 DECL_INITIAL (fndecl) = block;
429 TREE_USED (block) = TRUE;
430 BLOCK_SUBBLOCKS (block) = NULL_TREE;
431 }
432 BLOCK_SUPERCONTEXT (block) = context;
433
434 BLOCK_VARS (block)
435 = chainon (BLOCK_VARS (block), current_binding_level->names);
436 TREE_USED (fndecl) = TRUE;
437
438 if (bind_expr == NULL_TREE)
439 {
440 bind_expr
441 = build3 (BIND_EXPR, void_type_node, current_binding_level->names,
442 current_binding_level->decl, block);
443 DECL_SAVED_TREE (fndecl) = bind_expr;
444 }
445 else
446 {
447 if (!chain_member (current_binding_level->names,
448 BIND_EXPR_VARS (bind_expr)))
449 {
450 BIND_EXPR_VARS (bind_expr) = chainon (BIND_EXPR_VARS (bind_expr),
451 current_binding_level->names);
452
453 if (current_binding_level->names != NULL_TREE)
454 {
455 for (i = current_binding_level->names; i != NULL_TREE;
456 i = DECL_CHAIN (i))
457 append_to_statement_list_force (i,
458 &BIND_EXPR_BODY (bind_expr));
459
460 }
461 }
462 }
463 SET_EXPR_LOCATION (bind_expr, location);
464
465 current_binding_level->names = NULL_TREE;
466 current_binding_level->decl = NULL_TREE;
467 }
468
469 /* finishFunctionCode - adds cur_stmt_list to fndecl. The current
470 binding level is then able to be destroyed by a call to
471 popFunctionScope. The cur_stmt_list is appended to the
472 STATEMENT_LIST. */
473
474 void
475 m2block_finishFunctionCode (tree fndecl)
476 {
477 tree bind_expr;
478 tree block;
479 tree statements = m2block_pop_statement_list ();
480 tree_stmt_iterator i;
481
482 statements = m2block_end_statement_list (statements);
483 ASSERT_CONDITION (DECL_SAVED_TREE (fndecl) != NULL_TREE);
484
485 bind_expr = DECL_SAVED_TREE (fndecl);
486 ASSERT_CONDITION (TREE_CODE (bind_expr) == BIND_EXPR);
487
488 block = DECL_INITIAL (fndecl);
489 ASSERT_CONDITION (TREE_CODE (block) == BLOCK);
490
491 if (current_binding_level->names != NULL_TREE)
492 {
493 BIND_EXPR_VARS (bind_expr)
494 = chainon (BIND_EXPR_VARS (bind_expr), current_binding_level->names);
495 current_binding_level->names = NULL_TREE;
496 }
497 if (current_binding_level->labels != NULL_TREE)
498 {
499 tree t;
500
501 for (t = current_binding_level->labels; t != NULL_TREE;
502 t = TREE_CHAIN (t))
503 {
504 tree l = TREE_VALUE (t);
505
506 BIND_EXPR_VARS (bind_expr) = chainon (BIND_EXPR_VARS (bind_expr), l);
507 }
508 current_binding_level->labels = NULL_TREE;
509 }
510
511 BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
512
513 if (current_binding_level->decl != NULL_TREE)
514 for (i = tsi_start (current_binding_level->decl); !tsi_end_p (i);
515 tsi_next (&i))
516 append_to_statement_list_force (*tsi_stmt_ptr (i),
517 &BIND_EXPR_BODY (bind_expr));
518
519 for (i = tsi_start (statements); !tsi_end_p (i); tsi_next (&i))
520 append_to_statement_list_force (*tsi_stmt_ptr (i),
521 &BIND_EXPR_BODY (bind_expr));
522
523 current_binding_level->decl = NULL_TREE;
524 }
525
526 void
527 m2block_finishGlobals (void)
528 {
529 tree context = global_binding_level->context;
530 tree block = make_node (BLOCK);
531 tree p = global_binding_level->names;
532
533 BLOCK_SUBBLOCKS (block) = NULL;
534 TREE_USED (block) = 1;
535
536 BLOCK_VARS (block) = p;
537
538 DECL_INITIAL (context) = block;
539 BLOCK_SUPERCONTEXT (block) = context;
540 }
541
542 /* pushDecl - pushes a declaration onto the current binding level. */
543
544 tree
545 m2block_pushDecl (tree decl)
546 {
547 /* External objects aren't nested, other objects may be. */
548
549 if (decl != current_function_decl)
550 DECL_CONTEXT (decl) = current_binding_level->context;
551
552 /* Put the declaration on the list. The list of declarations is in
553 reverse order. The list will be reversed later if necessary. This
554 needs to be this way for compatibility with the back-end. */
555
556 TREE_CHAIN (decl) = current_binding_level->names;
557 current_binding_level->names = decl;
558
559 assert_global_names ();
560
561 return decl;
562 }
563
564 /* includeDecl - pushes a declaration onto the current binding level
565 providing it is not already present. */
566
567 void
568 m2block_includeDecl (tree decl)
569 {
570 tree p = current_binding_level->names;
571
572 while (p != decl && p != NULL)
573 p = TREE_CHAIN (p);
574 if (p != decl)
575 m2block_pushDecl (decl);
576 }
577
578 /* addDeclExpr - adds the DECL_EXPR node, t, to the statement list
579 current_binding_level->decl. This allows us to order all
580 declarations at the beginning of the function. */
581
582 void
583 m2block_addDeclExpr (tree t)
584 {
585 append_to_statement_list_force (t, &current_binding_level->decl);
586 }
587
588 /* RememberType - remember the type, t, in the ggc marked list. */
589
590 tree
591 m2block_RememberType (tree t)
592 {
593 global_binding_level->types
594 = tree_cons (NULL_TREE, t, global_binding_level->types);
595 return t;
596 }
597
598 /* global_constant - returns t. It chains, t, onto the
599 global_binding_level list of constants, if it is not already
600 present. */
601
602 tree
603 m2block_global_constant (tree t)
604 {
605 tree s;
606
607 if (global_binding_level->constants != NULL_TREE)
608 for (s = global_binding_level->constants; s != NULL_TREE;
609 s = TREE_CHAIN (s))
610 {
611 tree c = TREE_VALUE (s);
612
613 if (c == t)
614 return t;
615 }
616
617 global_binding_level->constants
618 = tree_cons (NULL_TREE, t, global_binding_level->constants);
619 return t;
620 }
621
622 /* RememberConstant - adds a tree, t, onto the list of constants to
623 be marked whenever the ggc re-marks all used storage. Constants
624 live throughout the whole compilation - and they can be used by
625 many different functions if necessary. */
626
627 tree
628 m2block_RememberConstant (tree t)
629 {
630 if ((t != NULL) && (m2tree_IsAConstant (t)))
631 return m2block_global_constant (t);
632 return t;
633 }
634
635 /* DumpGlobalConstants - displays all global constants and checks
636 none are poisoned. */
637
638 tree
639 m2block_DumpGlobalConstants (void)
640 {
641 tree s;
642
643 if (global_binding_level->constants != NULL_TREE)
644 for (s = global_binding_level->constants; TREE_CHAIN (s);
645 s = TREE_CHAIN (s))
646 debug_tree (s);
647 return NULL_TREE;
648 }
649
650 /* RememberInitModuleFunction - records tree, t, in the global
651 binding level. So that it will not be garbage collected. In
652 theory the inner modules could be placed inside the
653 current_binding_level I suspect. */
654
655 tree
656 m2block_RememberInitModuleFunction (tree t)
657 {
658 global_binding_level->init_functions
659 = tree_cons (NULL_TREE, t, global_binding_level->init_functions);
660 return t;
661 }
662
663 /* toplevel - return TRUE if we are in the global scope. */
664
665 int
666 m2block_toplevel (void)
667 {
668 if (current_binding_level == NULL)
669 return TRUE;
670 if (current_binding_level->fndecl == NULL)
671 return TRUE;
672 return FALSE;
673 }
674
675 /* GetErrorNode - returns the gcc error_mark_node. */
676
677 tree
678 m2block_GetErrorNode (void)
679 {
680 return error_mark_node;
681 }
682
683 /* GetGlobals - returns a list of global variables, functions,
684 constants. */
685
686 tree
687 m2block_GetGlobals (void)
688 {
689 assert_global_names ();
690 return global_binding_level->names;
691 }
692
693 /* GetGlobalContext - returns the global context tree. */
694
695 tree
696 m2block_GetGlobalContext (void)
697 {
698 return global_binding_level->context;
699 }
700
701 /* do_add_stmt - t is a statement. Add it to the statement-tree. */
702
703 static tree
704 do_add_stmt (tree t)
705 {
706 if (current_binding_level != NULL)
707 append_to_statement_list_force (t, m2block_cur_stmt_list_addr ());
708 return t;
709 }
710
711 /* flush_pending_note - flushes a pending_statement note if
712 necessary. */
713
714 static void
715 flush_pending_note (void)
716 {
717 if (pending_statement && (M2Options_GetM2g ()))
718 {
719 #if 0
720 /* --fixme-- we need a machine independant way to generate a nop. */
721 tree instr = m2decl_BuildStringConstant ("nop", 3);
722 tree string
723 = resolve_asm_operand_names (instr, NULL_TREE, NULL_TREE, NULL_TREE);
724 tree note = build_stmt (pending_location, ASM_EXPR, string, NULL_TREE,
725 NULL_TREE, NULL_TREE, NULL_TREE);
726
727 ASM_INPUT_P (note) = FALSE;
728 ASM_VOLATILE_P (note) = FALSE;
729 #else
730 tree note = build_empty_stmt (pending_location);
731 #endif
732 pending_statement = FALSE;
733 do_add_stmt (note);
734 }
735 }
736
737 /* add_stmt - t is a statement. Add it to the statement-tree. */
738
739 tree
740 m2block_add_stmt (location_t location, tree t)
741 {
742 if ((CAN_HAVE_LOCATION_P (t)) && (!EXPR_HAS_LOCATION (t)))
743 SET_EXPR_LOCATION (t, location);
744
745 if (pending_statement && (pending_location != location))
746 flush_pending_note ();
747
748 pending_statement = FALSE;
749 return do_add_stmt (t);
750 }
751
752 /* addStmtNote - remember this location represents the start of a
753 Modula-2 statement. It is flushed if another different location
754 is generated or another tree is given to add_stmt. */
755
756 void
757 m2block_addStmtNote (location_t location)
758 {
759 if (pending_statement && (pending_location != location))
760 flush_pending_note ();
761
762 pending_statement = TRUE;
763 pending_location = location;
764 }
765
766 void
767 m2block_removeStmtNote (void)
768 {
769 pending_statement = FALSE;
770 }
771
772 /* init - initialise the data structures in this module. */
773
774 void
775 m2block_init (void)
776 {
777 global_binding_level = newLevel ();
778 global_binding_level->context = build_translation_unit_decl (NULL);
779 global_binding_level->is_global = TRUE;
780 current_binding_level = NULL;
781 }
782
783 #include "gt-m2-m2block.h"
This page took 0.066126 seconds and 4 git commands to generate.