renamed fucntions is_x*_type() to is_X*_type() to prevent name clash with EDg frontend
[libfirm] / ir / ir / irgraph.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/irgraph.c
4  * Purpose:     Entry point to the representation of procedure code.
5  * Author:      Martin Trapp, Christian Schaefer
6  * Modified by: Goetz Lindenmaier
7  * Created:
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 1998-2003 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #ifdef HAVE_STRING_H
18 # include <string.h>
19 #endif
20
21 #include <stddef.h>
22
23 # include "xmalloc.h"
24 # include "ircons.h"
25 # include "irgraph_t.h"
26 # include "irprog_t.h"
27 # include "irnode_t.h"
28 # include "iropt_t.h"
29 # include "irflag_t.h"
30 # include "array.h"
31 # include "irgmod.h"
32 # include "mangle.h"
33 # include "irouts.h"
34 # include "firmstat.h"
35 # include "irgwalk.h"
36
37 /**
38  * Indicates, whether additional data can be registered to graphs.
39  * If set to 1, this is not possible anymore.
40  */
41 static int forbid_new_data = 0;
42
43 /**
44  * The amount of additional space for custom data to be allocated upon
45  * creating a new graph.
46  */
47 static size_t additional_graph_data_size = 0;
48
49 ir_graph *current_ir_graph;
50 ir_graph *get_current_ir_graph(void) {
51   return current_ir_graph;
52 }
53 void set_current_ir_graph(ir_graph *graph) {
54   current_ir_graph = graph;
55 }
56
57
58 int __interprocedural_view = false;
59
60 int (get_interprocedural_view)(void) {
61   return _get_interprocedural_view();
62 }
63
64 void (set_interprocedural_view)(int state) {
65   __interprocedural_view = state;
66
67   /* set function vectors for faster access */
68   if (state) {
69     __get_irn_arity = __get_irn_inter_arity;
70     __get_irn_n     = __get_irn_inter_n;
71   }
72   else {
73     __get_irn_arity = __get_irn_intra_arity;
74     __get_irn_n     = __get_irn_intra_n;
75   }
76 }
77
78 static ident* frame_type_suffix = NULL;
79 void init_irgraph(void) {
80   frame_type_suffix = new_id_from_str(FRAME_TP_SUFFIX);
81         forbid_new_data = 1;
82 }
83
84 /**
85  * Allocate a new ir graph.
86  * This function respects the registered graph data. The only reason for
87  * this function is, that there are two locations, where graphs are
88  * allocated (new_r_ir_graph, new_const_code_irg).
89  * @return Memory for a new graph.
90  */
91 ir_graph *alloc_graph(void)
92 {
93         size_t size = sizeof(ir_graph) + additional_graph_data_size;
94         char *ptr = xmalloc(size);
95         memset(ptr, 0, size);
96
97         return (ir_graph *) (ptr + additional_graph_data_size);
98 }
99
100 #if USE_EXPLICIT_PHI_IN_STACK
101 /* really defined in ircons.c */
102 typedef struct Phi_in_stack Phi_in_stack;
103 Phi_in_stack *new_Phi_in_stack();
104 void free_Phi_in_stack(Phi_in_stack *s);
105 #endif
106
107 /* Allocates a list of nodes:
108     - The start block containing a start node and Proj nodes for it's four
109       results (X, M, P, Tuple).
110     - The end block containing an end node. This block is not matured after
111       new_ir_graph as predecessors need to be added to it.
112     - The current block, which is empty and also not matured.
113    Further it allocates several datastructures needed for graph construction
114    and optimization.
115 */
116 ir_graph *
117 new_r_ir_graph (entity *ent, int n_loc)
118 {
119   ir_graph *res;
120   ir_node *first_block;
121   ir_node *projX;
122
123   res = alloc_graph();
124   res->kind = k_ir_graph;
125
126   /* inform statistics here, as blocks will be already build on this graph */
127   stat_new_graph(res, ent);
128
129   current_ir_graph = res;
130
131   /*-- initialized for each graph. --*/
132   if (get_opt_precise_exc_context()) {
133     res->n_loc = n_loc + 1 + 1; /* number of local variables that are never
134                    dereferenced in this graph plus one for
135                    the store plus one for links to fragile
136                    operations.  n_loc is not the number of
137                    parameters to the procedure!  */
138   }
139   else {
140     res->n_loc = n_loc + 1;  /* number of local variables that are never
141                 dereferenced in this graph plus one for
142                 the store. This is not the number of parameters
143                 to the procedure!  */
144   }
145
146   res->visited = 0;     /* visited flag, for the ir walker */
147   res->block_visited = 0; /* visited flag, for the 'block'-walker */
148
149 #if USE_EXPLICIT_PHI_IN_STACK
150   res->Phi_in_stack = new_Phi_in_stack();  /* A stack needed for automatic Phi
151                                 generation */
152 #endif
153   res->kind = k_ir_graph;
154   res->obst      = xmalloc (sizeof(*res->obst));
155   obstack_init (res->obst);
156   res->value_table = new_identities (); /* value table for global value
157                        numbering for optimizing use in
158                        iropt.c */
159   res->outs = NULL;
160
161   res->phase_state    = phase_building;
162   res->op_pin_state_pinned = op_pin_state_pinned;
163   res->outs_state     = outs_none;
164   res->dom_state      = dom_none;
165   res->typeinfo_state = irg_typeinfo_none;
166   res->loopinfo_state = loopinfo_none;
167
168   /*-- Type information for the procedure of the graph --*/
169   res->ent = ent;
170   set_entity_irg(ent, res);
171
172   /*--  a class type so that it can contain "inner" methods as in Pascal. --*/
173   res->frame_type = new_type_class(mangle(get_entity_ident(ent), frame_type_suffix));
174
175   /* Remove type from type list.  Must be treated differently than other types. */
176   remove_irp_type_from_list(res->frame_type);
177
178   /*-- Nodes needed in every graph --*/
179   res->end_block  = new_immBlock();
180   res->end        = new_End();
181   res->end_reg    = res->end;
182   res->end_except = res->end;
183
184   res->start_block = new_immBlock();
185   res->start   = new_Start();
186   res->bad     = new_ir_node(NULL, res, res->start_block, op_Bad, mode_T, 0, NULL);
187   res->no_mem  = new_ir_node(NULL, res, res->start_block, op_NoMem, mode_M, 0, NULL);
188
189   /* Proj results of start node */
190   projX            = new_Proj (res->start, mode_X, pn_Start_X_initial_exec);
191   res->frame       = new_Proj (res->start, mode_P_mach, pn_Start_P_frame_base);
192   res->globals     = new_Proj (res->start, mode_P_mach, pn_Start_P_globals);
193   res->initial_mem = new_Proj (res->start, mode_M, pn_Start_M);
194   res->args        = new_Proj (res->start, mode_T, pn_Start_T_args);
195 #ifdef DEBUG_libfirm
196   res->graph_nr    = get_irp_new_node_nr();
197 #endif
198   res->proj_args   = NULL;
199
200   set_store(res->initial_mem);
201
202   add_immBlock_pred(res->start_block, projX);
203   /*
204    * The code generation needs it. leave it in now.
205    * Use of this edge is matter of discussion, unresolved. Also possible:
206    * add_immBlock_pred(res->start_block, res->start_block), but invalid typed.
207    */
208   mature_immBlock (res->current_block);
209
210   /*-- Make a block to start with --*/
211   first_block = new_immBlock();
212   add_immBlock_pred (first_block, projX);
213
214   return res;
215 }
216
217
218 ir_graph *
219 new_ir_graph (entity *ent, int n_loc)
220 {
221   ir_graph *res = new_r_ir_graph (ent, n_loc);
222   add_irp_irg(res);          /* remember this graph global. */
223   return res;
224 }
225
226 /* Make a rudimentary ir graph for the constant code.
227    Must look like a correct irg, spare everything else. */
228 ir_graph *new_const_code_irg(void) {
229   ir_graph *res;
230   ir_node *projX;
231
232   res = alloc_graph();
233
234   /* inform statistics here, as blocks will be already build on this graph */
235   stat_new_graph(res, NULL);
236
237   current_ir_graph = res;
238   res->n_loc = 1;       /* Only the memory. */
239   res->visited = 0;     /* visited flag, for the ir walker */
240   res->block_visited=0; /* visited flag, for the 'block'-walker */
241 #if USE_EXPLICIT_PHI_IN_STACK
242   res->Phi_in_stack = NULL;
243 #endif
244   res->kind = k_ir_graph;
245   res->obst      = xmalloc (sizeof(*res->obst));
246   obstack_init (res->obst);
247   res->phase_state = phase_building;
248   res->op_pin_state_pinned = op_pin_state_pinned;
249   res->value_table = new_identities (); /* value table for global value
250                        numbering for optimizing use in
251                        iropt.c */
252   res->ent = NULL;
253   res->frame_type  = NULL;
254
255   /* -- The end block -- */
256   res->end_block  = new_immBlock ();
257   res->end        = new_End ();
258   res->end_reg    = res->end;
259   res->end_except = res->end;
260   mature_immBlock(get_cur_block());  /* mature the end block */
261
262   /* -- The start block -- */
263   res->start_block = new_immBlock ();
264   res->bad     = new_ir_node (NULL, res, res->start_block, op_Bad, mode_T, 0, NULL);
265   res->no_mem  = new_ir_node (NULL, res, res->start_block, op_NoMem, mode_M, 0, NULL);
266   res->start   = new_Start ();
267   /* Proj results of start node */
268   res->initial_mem = new_Proj (res->start, mode_M, pn_Start_M);
269   projX            = new_Proj (res->start, mode_X, pn_Start_X_initial_exec);
270   add_immBlock_pred (res->start_block, projX);
271   mature_immBlock   (res->start_block);  /* mature the start block */
272
273   add_immBlock_pred (new_immBlock (), projX);
274   mature_immBlock   (get_cur_block());   /* mature the 'body' block for expressions */
275
276   /* Set the visited flag high enough that the blocks will never be visited. */
277   set_irn_visited(get_cur_block(), -1);
278   set_Block_block_visited(get_cur_block(), -1);
279   set_Block_block_visited(res->start_block, -1);
280   set_irn_visited(res->start_block, -1);
281   set_irn_visited(res->bad, -1);
282   set_irn_visited(res->no_mem, -1);
283
284   res->phase_state = phase_high;
285   return res;
286 }
287
288 /* Defined in iropt.c */
289 void  del_identities (pset *value_table);
290
291 /* Frees the passed irgraph.
292    Deallocates all nodes in this graph and the ir_graph structure.
293    Sets the field irgraph in the corresponding entity to NULL.
294    Does not remove the irgraph from the list in irprog (requires
295    inefficient search, call remove_irp_irg by hand).
296    Does not free types, entities or modes that are used only by this
297    graph, nor the entity standing for this graph. */
298 void free_ir_graph (ir_graph *irg) {
299
300   stat_free_graph(irg);
301   if (irg->outs_state != outs_none) free_outs(irg);
302   if (irg->frame_type)  free_type(irg->frame_type);
303   if (irg->value_table) del_identities(irg->value_table);
304   if (irg->ent) {
305     peculiarity pec = get_entity_peculiarity (irg->ent);
306     set_entity_peculiarity (irg->ent, peculiarity_description);
307     set_entity_irg(irg->ent, NULL);  /* not set in const code irg */
308     set_entity_peculiarity (irg->ent, pec);
309   }
310
311   free_End(irg->end);
312   obstack_free(irg->obst,NULL);
313   free(irg->obst);
314 #if USE_EXPLICIT_PHI_IN_STACK
315   free_Phi_in_stack(irg->Phi_in_stack);
316 #endif
317   irg->kind = k_BAD;
318   free(irg);
319 }
320
321 /* access routines for all ir_graph attributes:
322    templates:
323    {attr type} get_irg_{attribute name} (ir_graph *irg);
324    void set_irg_{attr name} (ir_graph *irg, {attr type} {attr}); */
325
326 int
327 (is_ir_graph)(const void *thing) {
328   return _is_ir_graph(thing);
329 }
330
331 /* Outputs a unique number for this node */
332
333 long
334 get_irg_graph_nr(ir_graph *irg) {
335   assert(irg);
336 #ifdef DEBUG_libfirm
337   return irg->graph_nr;
338 #else
339   return (long)irg;
340 #endif
341 }
342
343 ir_node *
344 (get_irg_start_block)(const ir_graph *irg) {
345   return _get_irg_start_block(irg);
346 }
347
348 void
349 (set_irg_start_block)(ir_graph *irg, ir_node *node) {
350   _set_irg_start_block(irg, node);
351 }
352
353 ir_node *
354 (get_irg_start)(const ir_graph *irg) {
355   return _get_irg_start(irg);
356 }
357
358 void
359 (set_irg_start)(ir_graph *irg, ir_node *node) {
360   _set_irg_start(irg, node);
361 }
362
363 ir_node *
364 (get_irg_end_block)(const ir_graph *irg) {
365   return _get_irg_end_block(irg);
366 }
367
368 void
369 (set_irg_end_block)(ir_graph *irg, ir_node *node) {
370   _set_irg_end_block(irg, node);
371 }
372
373 ir_node *
374 (get_irg_end)(const ir_graph *irg) {
375   return _get_irg_end(irg);
376 }
377
378 void
379 (set_irg_end)(ir_graph *irg, ir_node *node) {
380   _set_irg_end(irg, node);
381 }
382
383 ir_node *
384 (get_irg_end_reg)(const ir_graph *irg) {
385   return _get_irg_end_reg(irg);
386 }
387
388 void     set_irg_end_reg (ir_graph *irg, ir_node *node) {
389   assert(get_irn_op(node) == op_EndReg || get_irn_op(node) == op_End);
390   irg->end_reg = node;
391 }
392
393 ir_node *
394 (get_irg_end_except)(const ir_graph *irg) {
395   return _get_irg_end_except(irg);
396 }
397
398 void     set_irg_end_except (ir_graph *irg, ir_node *node) {
399   assert(get_irn_op(node) == op_EndExcept || get_irn_op(node) == op_End);
400   irg->end_except = node;
401 }
402
403 ir_node *
404 (get_irg_cstore)(const ir_graph *irg) {
405   return _get_irg_cstore(irg);
406 }
407
408 void
409 (set_irg_cstore)(ir_graph *irg, ir_node *node) {
410   _set_irg_cstore(irg, node);
411 }
412
413 ir_node *
414 (get_irg_frame)(const ir_graph *irg) {
415   return _get_irg_frame(irg);
416 }
417
418 void
419 (set_irg_frame)(ir_graph *irg, ir_node *node) {
420   _set_irg_frame(irg, node);
421 }
422
423 ir_node *
424 (get_irg_globals)(const ir_graph *irg) {
425   return _get_irg_globals(irg);
426 }
427
428 void
429 (set_irg_globals)(ir_graph *irg, ir_node *node) {
430   _set_irg_globals(irg, node);
431 }
432
433 ir_node *
434 (get_irg_initial_mem)(const ir_graph *irg) {
435   return _get_irg_initial_mem(irg);
436 }
437
438 void
439 (set_irg_initial_mem)(ir_graph *irg, ir_node *node) {
440   _set_irg_initial_mem(irg, node);
441 }
442
443 ir_node *
444 (get_irg_args)(const ir_graph *irg) {
445   return _get_irg_args(irg);
446 }
447
448 void
449 (set_irg_args)(ir_graph *irg, ir_node *node) {
450   _set_irg_args(irg, node);
451 }
452
453 ir_node **
454 (get_irg_proj_args) (const ir_graph *irg) {
455   return _get_irg_proj_args (irg);
456 }
457
458 void
459 (set_irg_proj_args) (ir_graph *irg, ir_node **nodes) {
460   _set_irg_proj_args (irg, nodes);
461 }
462
463 ir_node *
464 (get_irg_bad)(const ir_graph *irg) {
465   return _get_irg_bad(irg);
466 }
467
468 void
469 (set_irg_bad)(ir_graph *irg, ir_node *node) {
470   _set_irg_bad(irg, node);
471 }
472
473 ir_node *
474 (get_irg_no_mem)(const ir_graph *irg) {
475   return _get_irg_no_mem(irg);
476 }
477
478 void
479 (set_irg_no_mem)(ir_graph *irg, ir_node *node) {
480   _set_irg_no_mem(irg, node);
481 }
482
483 ir_node *
484 (get_irg_current_block)(const ir_graph *irg) {
485   return _get_irg_current_block(irg);
486 }
487
488 void
489 (set_irg_current_block)(ir_graph *irg, ir_node *node) {
490   _set_irg_current_block(irg, node);
491 }
492
493 entity *
494 (get_irg_entity)(const ir_graph *irg) {
495   return _get_irg_entity(irg);
496 }
497
498 void
499 (set_irg_entity)(ir_graph *irg, entity *ent) {
500   _set_irg_entity(irg, ent);
501 }
502
503 type *
504 (get_irg_frame_type)(const ir_graph *irg) {
505   return _get_irg_frame_type(irg);
506 }
507
508 void
509 (set_irg_frame_type)(ir_graph *irg, type *ftp) {
510   _set_irg_frame_type(irg, ftp);
511 }
512
513
514 /* To test for a frame type */
515 int
516 is_frame_type(const type *ftp) {
517   int i;
518   if (is_Class_type(ftp)) {
519     for (i = 0; i < get_irp_n_irgs(); i++) {
520       const type *frame_tp = get_irg_frame_type(get_irp_irg(i));
521       if (ftp == frame_tp) return true;
522     }
523   }
524   return false;
525 }
526
527 int
528 get_irg_n_locs (ir_graph *irg)
529 {
530   if (get_opt_precise_exc_context())
531     return irg->n_loc - 1 - 1;
532   else
533     return irg->n_loc - 1;
534 }
535
536 void
537 set_irg_n_loc (ir_graph *irg, int n_loc)
538 {
539   if (get_opt_precise_exc_context())
540     irg->n_loc = n_loc + 1 + 1;
541   else
542     irg->n_loc = n_loc + 1;
543 }
544
545
546
547 /* Returns the obstack associated with the graph. */
548 struct obstack *
549 (get_irg_obstack)(const ir_graph *irg) {
550   return _get_irg_obstack(irg);
551 }
552
553 /*
554  * Returns true if the node n is allocated on the storage of graph irg.
555  *
556  * Implementation is GLIBC specific as is uses the internal _obstack_chunk implementation.
557  */
558 int node_is_in_irgs_storage(ir_graph *irg, ir_node *n)
559 {
560   struct _obstack_chunk *p;
561
562   /*
563    * checks wheater the ir_node pointer i on the obstack.
564    * A more sophisticated check would test the "whole" ir_node
565    */
566   for (p = irg->obst->chunk; p; p = p->prev) {
567     if (((char *)p->contents <= (char *)n) && ((char *)n < (char *)p->limit))
568       return 1;
569   }
570
571   return 0;
572 }
573
574 irg_phase_state
575 (get_irg_phase_state)(const ir_graph *irg) {
576   return _get_irg_phase_state(irg);
577 }
578
579 void
580 (set_irg_phase_low)(ir_graph *irg) {
581   _set_irg_phase_low(irg);
582 }
583
584 op_pin_state
585 (get_irg_pinned)(const ir_graph *irg) {
586   return _get_irg_pinned(irg);
587 }
588
589 irg_outs_state
590 (get_irg_outs_state)(const ir_graph *irg) {
591   return _get_irg_outs_state(irg);
592 }
593
594 void
595 (set_irg_outs_inconsistent)(ir_graph *irg) {
596   _set_irg_outs_inconsistent(irg);
597 }
598
599 irg_dom_state
600 (get_irg_dom_state)(const ir_graph *irg) {
601   return _get_irg_dom_state(irg);
602 }
603
604 void
605 (set_irg_dom_inconsistent)(ir_graph *irg) {
606   _set_irg_dom_inconsistent(irg);
607 }
608
609 irg_loopinfo_state
610 (get_irg_loopinfo_state)(const ir_graph *irg) {
611   return _get_irg_loopinfo_state(irg);
612 }
613
614 void
615 (set_irg_loopinfo_state)(ir_graph *irg, irg_loopinfo_state s) {
616   _set_irg_loopinfo_state(irg, s);
617 }
618
619 void
620 set_irg_loopinfo_inconsistent(ir_graph *irg) {
621   if (irg->loopinfo_state == loopinfo_ip_consistent)
622     irg->loopinfo_state = loopinfo_ip_inconsistent;
623
624   else if (irg->loopinfo_state == loopinfo_consistent)
625     irg->loopinfo_state = loopinfo_inconsistent;
626
627   else if (irg->loopinfo_state == loopinfo_cf_ip_consistent)
628     irg->loopinfo_state = loopinfo_cf_ip_inconsistent;
629
630   else if (irg->loopinfo_state == loopinfo_cf_consistent)
631     irg->loopinfo_state = loopinfo_cf_inconsistent;
632 }
633
634 void
635 (set_irg_pinned)(ir_graph *irg, op_pin_state p) {
636   _set_irg_pinned(irg, p);
637 }
638
639 irg_callee_info_state
640 (get_irg_callee_info_state)(const ir_graph *irg) {
641   return _get_irg_callee_info_state(irg);
642 }
643
644 void
645 (set_irg_callee_info_state)(ir_graph *irg, irg_callee_info_state s) {
646   _set_irg_callee_info_state(irg, s);
647 }
648
649 irg_inline_property
650 (get_irg_inline_property)(const ir_graph *irg) {
651   return _get_irg_inline_property(irg);
652 }
653
654 void
655 (set_irg_inline_property)(ir_graph *irg, irg_inline_property s) {
656   _set_irg_inline_property(irg, s);
657 }
658
659 void
660 (set_irg_link)(ir_graph *irg, void *thing) {
661   _set_irg_link(irg, thing);
662 }
663
664 void *
665 (get_irg_link)(const ir_graph *irg) {
666   return _get_irg_link(irg);
667 }
668
669 /** maximum visited flag content of all ir_graph visited fields. */
670 static unsigned long max_irg_visited = 0;
671
672 unsigned long
673 (get_irg_visited)(const ir_graph *irg) {
674   return _get_irg_visited(irg);
675 }
676
677 void
678 set_irg_visited (ir_graph *irg, unsigned long visited)
679 {
680   irg->visited = visited;
681   if (irg->visited > max_irg_visited) {
682     max_irg_visited = irg->visited;
683   }
684 }
685
686 void
687 inc_irg_visited (ir_graph *irg)
688 {
689   if (++irg->visited > max_irg_visited) {
690     max_irg_visited = irg->visited;
691   }
692 }
693
694 unsigned long
695 get_max_irg_visited(void)
696 {
697   /*
698   int i;
699   for(i = 0; i < get_irp_n_irgs(); i++)
700   assert(max_irg_visited >= get_irg_visited(get_irp_irg(i)));
701    */
702   return max_irg_visited;
703 }
704
705 void set_max_irg_visited(int val) {
706   max_irg_visited = val;
707 }
708
709 unsigned long
710 inc_max_irg_visited(void)
711 {
712   /*
713   int i;
714   for(i = 0; i < get_irp_n_irgs(); i++)
715   assert(max_irg_visited >= get_irg_visited(get_irp_irg(i)));
716   */
717   max_irg_visited++;
718   return max_irg_visited;
719 }
720
721 unsigned long
722 (get_irg_block_visited)(const ir_graph *irg) {
723   return _get_irg_block_visited(irg);
724 }
725
726 void
727 (set_irg_block_visited)(ir_graph *irg, unsigned long visited) {
728   _set_irg_block_visited(irg, visited);
729 }
730
731 void
732 (inc_irg_block_visited)(ir_graph *irg) {
733   _inc_irg_block_visited(irg);
734 }
735
736
737 /**
738  * walker Start->End: places Proj nodes into the same block
739  * as it's predecessors
740  *
741  * @param n    the node
742  * @param env  ignored
743  */
744 static void normalize_proj_walker(ir_node *n, void *env)
745 {
746   if (is_Proj(n)) {
747     ir_node *pred  = get_Proj_pred(n);
748     ir_node *block = get_nodes_block(pred);
749
750     set_nodes_block(n, block);
751   }
752 }
753
754 /* put the proj's into the same block as its predecessors */
755 void normalize_proj_nodes(ir_graph *irg)
756 {
757   irg_walk_graph(irg, NULL, normalize_proj_walker, NULL);
758         set_irg_outs_inconsistent(irg);
759 }
760
761 size_t register_additional_graph_data(size_t size)
762 {
763         assert(!forbid_new_data && "Too late to register additional node data");
764
765         if(forbid_new_data)
766                 return 0;
767
768         return additional_graph_data_size += size;
769 }