PIPS
unspaghettify.c
Go to the documentation of this file.
1 /*
2 
3  $Id: unspaghettify.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 /* Ronan Keryell, 1995. */
28 
29 #ifndef lint
30 char vcid_unspaghettify[] = "%A% ($Date: 2004/01/23 13:55:04 $, ) version $Revision: 14223 $, got on %D%, %T% [%P%].\n Copyright (c) ï¿œcole des Mines de Paris Proprietary.";
31 #endif /* lint */
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 #include "linear.h"
38 
39 #include "genC.h"
40 #include "ri.h"
41 #include "ri-util.h"
42 #include "workspace-util.h"
43 #include "text-util.h"
44 #include "database.h"
45 #include "misc.h"
46 #include "pipsdbm.h"
47 #include "resources.h"
48 #include "properties.h"
49 #include "control.h"
50 
51 
52 /* Avoid infinite restructuring in some cases: */
54 
55 typedef enum {
61 
62 
65 
66 /* To print some statistics about control graph restructuration: */
73 
74 
75 static void
77 {
84 }
85 
86 
87 /* Compute the number of all the computations that have been done */
88 static int
96 }
97 
98 static void
100 {
102  && get_bool_property("UNSPAGHETTIFY_DISPLAY_STATISTICS")) {
103  int number_of_restructured_tests = number_of_restructured_if_then
107  user_log("Total number of restructurations: %d\n",
109 
110  if (number_of_restructured_tests != 0) {
111  user_log("%d test%s %s been restructured:\n",
112  number_of_restructured_tests,
113  number_of_restructured_tests > 1 ? "s" : "",
114  number_of_restructured_tests > 1 ? "have" : "has");
115  user_log("\t %d IF/THEN/ELSE, %d IF/THEN, %d IF/ELSE & %d null IF.\n",
120  }
122  user_log("%d structured \"do ... while()\" %s been recovered.\n",
124  number_of_recovered_do_while > 1 ? "have" : "has");
125  user_log("%d structured \"while() ...\" %s been recovered.\n",
127  number_of_recovered_while > 1 ? "have" : "has");
128  }
129  }
130 }
131 
132 
133 /* Remove a useless continue in a sequence of control since it is
134  typically the kind of useless things generated by the
135  controlizer... */
136 static void
138 {
139  list blocs = NIL;
140  list remove_continue_list = NIL;
141 
142  /* The entry point of the unstructured: */
143  control entry_node = unstructured_control(u);
144  /* and its exit point: */
145  control exit_node = unstructured_exit(u);
146 
147  pips_debug(7, "Dealing with unstructured %p (begin: %p, end: %p)\n",
148  u, entry_node, exit_node);
149 
150  CONTROL_MAP(c,
151  {
152  ifdebug (1)
153  pips_assert("control is consistent",
155 
156  /* Do not remove the exit nor the entry node node
157  since it is boring to relink the entry and exit
158  node... That is not important since there is
159  another pass that fuse the sequences. Dead code
160  elimination should remove these structured
161  CONTINUE afterward... */
162  if (c != exit_node && c != entry_node)
163  if (gen_length(control_successors(c)) == 1) {
164  /* Do not deal with any number of predecessor
165  since we do not want to remove the node 100
166  in :
167  goto 100
168  100 goto 200
169  200 goto 100
170 
171  There may be also some unreachable
172  continues, that are without predecessors
173  (0)... We want to remove them also.
174 
175 Well with this modification, I am not sure that this procedure is
176 still useful...
177 
178  So only 0 or 1 predecessor: */
179  if (gen_length(control_predecessors(c)) <= 1) {
181 
182  pips_debug(7, "\tNode %p has candidate links\n", c);
184  /* It is some useless code with no
185  comment to spare: put it in the
186  remove list: */
187  remove_continue_list = CONS(CONTROL,
188  c,
189  remove_continue_list);
190  pips_debug(7, "\tNode %p for statement %s to be removed\n", c,
192  }
193  }
194  }
195  },
196  entry_node,
197  blocs);
198  gen_free_list(blocs);
199 
200  /* Now we have the list of the control node to discard. Do the
201  cleaning: */
202  MAPL(a_control_list,
203  {
204  control c = CONTROL(CAR(a_control_list));
205 
206  debug(3, "remove_useless_continue_or_empty_code_in_unstructured",
207  "Remove control %p for statement %s\n", c,
210  },
211  remove_continue_list);
212 
213  gen_free_list(remove_continue_list);
214 }
215 
216 
217 /* The controlizer of PIPS seems to have a bug:
218  it put an empty successor node to the so-called exit node.
219  Correct this fact: */
220 static void
222 {
223  control exit_node = unstructured_exit(u);
224  list l = control_successors(exit_node);
225 
226  if (gen_length(l) >= 1) {
227  control c = CONTROL(CAR(l));
228  pips_assert("clean_up_exit_node",
229  gen_length(control_successors(exit_node)) == 1
230  && gen_length(control_successors(c)) == 0
231  && gen_length(control_predecessors(c)) == 1
233 
234  /* Remove the useless node: */
236  gen_free_list(control_successors(exit_node));
237 
238  /* Now the exit node has no longer a successor: */
239  control_successors(exit_node) = NIL;
240  }
241 
242  pips_assert("clean_up_exit_node",
243  gen_length(control_successors(exit_node)) == 0);
244 }
245 
246 
247 /* Try to transform each control sequence in a single statement instead of
248  a list of control nodes: */
249 void
251 {
252  list blocs = NIL;
253  list control_nodes_to_fuse = NIL;
256  /* The entry point of the unstructured: */
257  control entry_node = unstructured_control(u);
258  /* and its exit point: */
259  control exit_node = unstructured_exit(u);
260  /* To store the list of the controls to fuse we use a mapping since
261  we need to keep track of eventual previous fuse on a control: */
262  hash_table controls_to_fuse_with_their_successors =
264 
265  bool aggressive_restructure_p = get_bool_property("FUSE_CONTROL_NODES_WITH_COMMENTS_OR_LABEL");
266 
267  ifdebug(4) {
268  pips_debug(4, "Begin with implicit target labels:");
269  print_arguments(tl);
270  pips_debug(4, "\n");
271  }
272 
273  ifdebug (1)
274  pips_assert("unstructured is consistent",
276  pips_debug(3, "Unstructured %p\n", u);
277 
278  CONTROL_MAP(c,
279  {
281  ifdebug (1)
282  pips_assert("control is consistent",
284  pips_debug(3, "Looking for control %p...\n", c);
285  /* ifdebug(5) */
286  /* print_statement(s); */
287 
288  /* Select a node with only one successor: */
289  if (gen_length(control_successors(c)) == 1) {
290  control the_successor = CONTROL(CAR(control_successors(c)));
291 
292  size_t number_of_successors_of_the_successor = gen_length(control_successors(the_successor));
293  size_t number_of_predecessors_of_the_successor = gen_length(control_predecessors(the_successor));
294  pips_debug(3, "Control %p: (gen_length(control_successors(c)) == 1), number_of_successors_of_the_successor = %zd, number_of_predecessors_of_the_successor = %zd, the successor is the entry node: %d, empty_statement_or_continue_p(control_statement(c)) = %d\n",
295  c,
296  number_of_successors_of_the_successor,
297  number_of_predecessors_of_the_successor,
298  the_successor == entry_node,
300  /* Since I use an O(n) algorithm instead of an
301  O(n^2) all this condition must be checked
302  again later since these topological and
303  semantical properties may have changed
304  during the fusion phase. I think it is true
305  because the fused graph is included into
306  the former graph but I am too lazy to write
307  a proof... :-( Have a look to
308  Validation/Control/create.f. */
309  if ((number_of_successors_of_the_successor <= 1
310  /* ...Accept the exit node */
311  && the_successor != entry_node
312  && number_of_predecessors_of_the_successor == 1)
313  || (aggressive_restructure_p ? empty_statement_or_continue_p(s) : empty_statement_or_continue_without_comment_p(s))) {
314  /* Ok, we have found a node in a
315  sequence. Note that we cannot fuse with the
316  entry node since it must keep this
317  role... */
318  /* But if c is empty, we can fuse it with any
319  successor without changing the semantincs,
320  even if the successor is the entry
321  node. Don't do this if there is a comment
322  since it mess up the original source
323  look-alike. */
324  /* The fact we can have a cycle is considered
325  a page below... */
326  /* Put the control in the fuse
327  list. Since no fusing occurs yet, the
328  address of a control node is itself: */
329  hash_put(controls_to_fuse_with_their_successors,
330  (char *) c,
331  (char *) c);
332  /* Use also a real list to remove the
333  non-determinism of a later
334  HASH_MAP. Note that since it follow a
335  depth-first algorithm, the output
336  program is more likely to be similar to
337  the output, especially with cycles in
338  the control graph: */
339  control_nodes_to_fuse = CONS(CONTROL,
340  c,
341  control_nodes_to_fuse);
342  }
343  }
344  else {
345  pips_debug(3, "(gen_length(control_successors(c)) == %zd)\n",
347  }
348  },
349  entry_node,
350  blocs);
351  gen_free_list(blocs);
352 
353  /* Reverse the list to follow the order of appearance : */
354  control_nodes_to_fuse = gen_nreverse(control_nodes_to_fuse);
355 
356  /* Now, since we have the list of the control nodes to fuse with
357  their successors, do the fusion: */
358  MAP(CONTROL, the_original_control, {
359  control a_control_to_fuse;
360  control the_successor;
361  char * its_address_now;
362  char * old_address;
363 
364  its_address_now = hash_get(controls_to_fuse_with_their_successors,
365  (char *) the_original_control);
366  /* Find the address of a control node to fuse even if
367  it has already been fused with predecessors through
368  a transitive closure: */
369  for(old_address = (char *) the_original_control;;) {
370  pips_debug(3, "Control %p (originally %p):\n",
371  its_address_now, the_original_control);
372  if (old_address == its_address_now
373  /* ...The control node has not been moved */
374  || !hash_defined_p(controls_to_fuse_with_their_successors,
375  (char *) its_address_now)
376  /* ...or it has not been moved because it is
377  not a control node to fuse anyway. */
378  )
379  /* Ok, the node has been located: */
380  break;
381  else {
382  /* Follow a former control movement: */
383  old_address = its_address_now;
384  its_address_now
385  = hash_get(controls_to_fuse_with_their_successors,
386  (char *) its_address_now);
387  }
388  }
389  a_control_to_fuse = (control) its_address_now;
390 
391  /* ifdebug(5) { */
392  /* fprintf(stderr,"Statement with label \"%s\" for control a_control_fo_fuse=%p\n", */
393  /* entity_local_name(statement_label(control_statement(a_control_to_fuse))), */
394  /* a_control_to_fuse); */
395  /* print_statement(control_statement(a_control_to_fuse)); */
396  /* fprintf(stderr,"Let's print the statement a second time to see its label again:\n"); */
397  /* print_statement(control_statement(a_control_to_fuse)); */
398  /* } */
399  /* ifdebug(6) { */
400  /* pips_debug(5, "All the unstructured %p:\n", u); */
401  /* print_statement(s); */
402  /* } */
403  ifdebug (3)
404  fprintf(stderr, "Want to fuse control %p\n", a_control_to_fuse);
405  ifdebug (1)
406  pips_assert("control a_control_to_fuse is consistent",
407  control_consistent_p(a_control_to_fuse));
408 
409  the_successor = CONTROL(CAR(control_successors(a_control_to_fuse)));
410  ifdebug (3)
411  fprintf(stderr, " with control %p\n", the_successor);
412  ifdebug (1)
413  pips_assert("control the_successor is consistent",
414  control_consistent_p(the_successor));
415 
416  if (a_control_to_fuse == the_successor) {
417  pips_debug(3, "\tA loop of control has been found... Do not fuse the control %p\n", a_control_to_fuse);
418  }
419  else {
420  int number_of_successors_of_the_successor =
421  gen_length(control_successors(the_successor));
422  int number_of_predecessors_of_the_successor =
423  gen_length(control_predecessors(the_successor));
424  /* Verify that the fusion is still valid: */
425  if ((number_of_successors_of_the_successor <= 1
426  /* ...Accept the exit node */
427  && the_successor != entry_node
428  && number_of_predecessors_of_the_successor == 1)
429  ||
431  && (!gen_in_list_p(statement_to_label(control_statement(a_control_to_fuse)), tl)
432  /* ||entity_empty_label_p(statement_to_label(control_statement(the_successor)))*/)
433  /*
434  (entity_empty_label_p(statement_to_label(control_statement(a_control_to_fuse)))
435  || entity_empty_label_p(statement_to_label(control_statement(the_successor))))
436  */
437  )) {
438  /* Well, it seems to be a real sequence, at most a
439  loop with 2 control nodes... */
440  pips_debug(3, "\tOk fuse them.\n");
441 
442  fuse_2_control_nodes(a_control_to_fuse, the_successor);
443  /* make st with the statements of 2 following nodes: */
444 
445  if (the_successor == entry_node)
446  /* Update the entry node if we fuse with it: */
447  entry_node = a_control_to_fuse;
448  if (the_successor == exit_node)
449  exit_node = a_control_to_fuse;
450 
451  /* If the node "the_successor" is in the fuse list, we
452  want to keep track of its new place, that is in
453  fact fused in "a_control_to_fuse", so that an
454  eventual fusion will use "a_control_to_fuse"
455  instead of "the_successor": */
456  if (hash_defined_p(controls_to_fuse_with_their_successors,
457  (char *) the_successor)) {
458  /* Ok, "the_successor" is a node to fuse or that
459  has been already fused (in this case the
460  following is useless, but anyway...). Thus we
461  keep track of its new location: */
462  hash_update(controls_to_fuse_with_their_successors,
463  (char *) the_successor,
464  (char *) a_control_to_fuse);
465  }
466  }
467  else
468  pips_debug(3, "\tDo not fuse them because the semantics have changed.\n");
469  }
470  ifdebug (1)
471  pips_assert("control after fuse is consistent",
472  control_consistent_p(a_control_to_fuse));
473 
474  },
475  control_nodes_to_fuse);
476 
477  /* Update the potentially modified entry and exit nodes: */
478  unstructured_control(u)= entry_node;
479  unstructured_exit(u)= exit_node;
480 
481  gen_free_list(tl);
482  hash_table_free(controls_to_fuse_with_their_successors);
483 }
484 
485 
486 /* Take the entry node out of the unstructured if it is not useful, such
487  as not an IF or a node without predecessor.
488 
489  Return true if there is still an unstructured, false if the
490  unstructured has been replaced by a structured statement.
491 
492  If the first node is taked out, then * new_unstructured_statement
493  returns the new statement that own the unstructured, else s. */
494 static bool
496  statement * new_unstructured_statement)
497 {
500  control entry_node = unstructured_control(u);
501  list entry_node_successors = control_successors(entry_node);
502  int entry_node_successors_length = gen_length(entry_node_successors);
503  *new_unstructured_statement = s;
504 
505  if (entry_node_successors_length == 2
506  || gen_length(control_predecessors(entry_node)) > 0)
507  /* Well, this node is useful here since it is an unstructured IF
508  or there is a GOTO on it. */
509  return true;
510 
511  if (entry_node_successors_length == 0) {
512  /* In fact the unstructured has only one control node! Transform
513  it in a structured block of statements: */
514  list l = CONS(STATEMENT, control_statement(entry_node), NIL);
515  /* Since the unstructured may have a comment on it, we cannot
516  put the comment on the statement block but on a CONTINUE: */
518  ! unlabelled_statement_p(s)) {
523  l = CONS(STATEMENT, cs, l);
524  }
526  /* Remove the unstructured: */
528  free_instruction(i);
529  /* No longer unstructured: */
530  return false;
531  }
532  else {
533  /* Take out the entry node: */
534  *new_unstructured_statement = instruction_to_statement(i);
537  control_statement(entry_node),
538  CONS(STATEMENT,
539  *new_unstructured_statement,
540  NIL)));
541  /* The entry node is now the second node: */
542  pips_assert("take_out_the_entry_node_of_the_unstructured",
543  entry_node_successors_length == 1);
544  unstructured_control(u) = CONTROL(CAR(entry_node_successors));
545 
547  entry_node);
548  return true;
549  }
550 }
551 
552 
553 /* If the unstructured begin and/or end with a sequence, move the
554  sequence(s) out of the unstructured and return a new statement with
555  an equivalent but more structured code. It returns true if the
556  unstructured has disappeared and else FALSE.
557 
558  If the unstructured is still here, the statement directly owning it
559  is returned in new_unstructured_statement: */
560 
561 /* Still buggy. No longer used. */
562 static bool __attribute__ ((unused))
563 try_to_structure_the_unstructured(statement s,
564  statement * new_unstructured_statement)
565 {
566  control end_of_first_sequence, c;
567  list the_successors, the_predecessors;
568  list begin_statement_list = NIL;
569  list end_statement_list = NIL;
570  control begin_of_last_sequence = control_undefined /* no gcc warning */;
573 
574  /* The entry point of the unstructured: */
575  control entry_node = unstructured_control(u);
576  /* and its exit point: */
577  control exit_node = unstructured_exit(u);
578 
579  /* Find the biggest sequence from the begin: */
580  if (entry_node == exit_node)
581  /* Well, we have an unstructured with one control node, it is
582  still a sequence: */
583  end_of_first_sequence = entry_node;
584  else {
585  end_of_first_sequence = control_undefined;
586  for(c = entry_node;
587  gen_length(the_successors = control_successors(c)) <= 1
588  && gen_length(control_predecessors(c)) <= 1;
589  c = CONTROL(CAR(the_successors))) {
590  end_of_first_sequence = c;
591  if (the_successors == NIL)
592  /* It is in fact the exit_node: */
593  break;
594  }
595  }
596 
597  if (end_of_first_sequence != control_undefined)
598  /* OK, there is a sequence at the beginning of the unstructured: */
599  begin_statement_list =
601  end_of_first_sequence);
602 
603  /* If there is still something in the sequence: */
604  if (end_of_first_sequence != exit_node) {
605  /* Find the biggest sequence from the end: */
606  begin_of_last_sequence = control_undefined;
607  for(c = exit_node;
608  gen_length(the_predecessors = control_predecessors(c)) == 1
609  && gen_length(control_successors(c)) <= 1;
610  c = CONTROL(CAR(the_predecessors)))
611  begin_of_last_sequence = c;
612 
613  /* In fact, an unstructured IF is noted as a control node with 2
614  successors, that means that we cannot take the biggest
615  sequence since it may move one successor of such an IF and
616  PIPS would be out. */
617  if (begin_of_last_sequence != control_undefined
618  && gen_length(control_successors(c)) == 2) {
619  /* OK, it is actually an IF before the end sequence. Try to
620  keep a spare node from the sequence. Since the
621  controllizer seems to put always a continue as an IF
622  successor, it is *seems* sensible. */
623  the_successors = control_successors(begin_of_last_sequence);
624 
625  if (the_successors != NIL)
626  /* There is one successor, that is the sequence has at
627  least 2 control node. Keep the first node as part as IF
628  unstructured: */
629  begin_of_last_sequence = CONTROL(CAR(the_successors));
630  else
631  /* There is only one node in the sequence. It remains in
632  the unstructured: */
633  begin_of_last_sequence = control_undefined;
634  }
635 
636  if (begin_of_last_sequence != control_undefined)
637  /* Then there is a sequence at the end of the unstructured: */
638  end_statement_list =
640  exit_node);
641  }
642 
643  /* Now, restructure all the stuff only if there is something to do: */
644  if (begin_statement_list != NIL || end_statement_list != NIL) {
645  if (end_of_first_sequence == exit_node) {
646  /* All the unstructured is a sequence, replace it with the
647  equivalent block of statement statement: */
649  make_instruction_block(begin_statement_list);
650 
651  /* Discard the unstructured instruction: */
653 
654  /* Warn that the unstructured no longer exist: */
655  *new_unstructured_statement = statement_undefined;
656  return true;
657  }
658  else {
659  /* There is still an unstructured, but with one pre- or
660  post-sequence: */
661  list list_of_the_new_statements;
662  /* Put the unstructured in the new statement list: */
663  *new_unstructured_statement = instruction_to_statement(i);
664 
665  list_of_the_new_statements = CONS(STATEMENT,
666  *new_unstructured_statement,
667  NIL);
668 
669  if (begin_statement_list != NIL) {
670  /* There is a pre-sequence before the unstructured: */
671 
672  /* Put the sequence before the unstructured: */
673  list_of_the_new_statements = gen_nconc(begin_statement_list,
674  list_of_the_new_statements);
675 
676  /* Update the entry node of the unstructured: */
678  CONTROL(CAR(control_successors(end_of_first_sequence)));
679 
680  /* Clean up the equivalent control sequence: */
682  end_of_first_sequence);
683  }
684 
685  if (end_statement_list != NIL) {
686  /* There is a post-sequence after the unstructured: */
687  list_of_the_new_statements = gen_nconc(list_of_the_new_statements,
688  end_statement_list);
689 
690  /* Update the exit node of the unstructured: */
691  unstructured_exit(u) =
692  CONTROL(CAR(control_predecessors(begin_of_last_sequence)));
693 
694  /* Clean up the equivalent control sequence: */
695  discard_a_control_sequence_without_its_statements(begin_of_last_sequence, exit_node);
696  }
697 
698  /* Make the instruction of the old statement with the
699  sequence(s) and the stripped-down unstructured: */
701  make_instruction_block(list_of_the_new_statements);
702 
703  return false;
704  }
705  }
706  /* By default the unstructured is not changed, thus return the
707  statement owning it: */
708  *new_unstructured_statement = s;
709 
710  return false;
711 }
712 
713 
714 /* Extract the statement from an exit node of an unstructured statement if
715  it is a useful statement
716 
717  @param s is the statement that contains an unstructured
718  @return the new restructured statement
719 
720  The exit node is the landing pad of the control graph. But if it is not
721  a continue, that means that its statement is a useful instruction at
722  the end of the unstructured and we can take it out of the
723  unstructured. We just return the statement directly containing the
724  unstructured.
725 
726  Right now, it does not extract a RETURN since as explained in ï¿œ PIPS:
727  Internal Representation of Fortran and C Code ï¿œ about RETURN_LABEL_NAME
728  in the Entities section, since a RETURN with a label at the exit of un
729  unstructured is always the representation of a RETURN in Fortran
730  unstructured code... So even for C code, a return stay inside an
731  unstructured. RK does not think it is important anyway...
732 */
733 statement
735 {
737 
738  pips_assert("take_out_the_exit_node_if_not_a_continue :"
739  "The statement must be an unstructured",
741 
742  /* To return and keep track of the unstructured: */
743  statement the_unstructured = s;
745  control exit_node = unstructured_exit(u);
746  statement the_exit_statement = control_statement(exit_node);
747  instruction the_exit_instruction;
748 
749  /* ifdebug(5) { */
750  /* pips_debug(5, */
751  /* "Statement at entry:\n"); */
752  /* print_statement(s); */
753  /* } */
754 
755  /* First, linearize the exit statement since
756  fuse_sequences_in_unstructured() may have gathered many
757  statements in a messy way: */
758  clean_up_sequences_internal(the_exit_statement);
759  the_exit_instruction =
760  statement_instruction(the_exit_statement);
761 
762  /* Then normalize to have only one non-sequence statement as the
763  exit node: */
764  if (instruction_sequence_p(the_exit_instruction)
765  && !nop_statement_p(the_exit_statement)) {
766  list first_statement_list;
767  statement first_statement, last_statements;
768 
769  list the_statements =
770  sequence_statements(instruction_sequence(the_exit_instruction));
771  pips_assert("the_statements must be a true sequence",
772  gen_length(the_statements) >= 2);
773 
774  /* Well, this should be always true if the sequence
775  survived to clean_up_sequences_rewrite()... */
776  first_statement_list = the_statements;
777  first_statement = STATEMENT(CAR(first_statement_list));
778  the_statements = CDR(the_statements);
779  CDR(first_statement_list) = NIL;
780  gen_free_list(first_statement_list);
781 
782  last_statements = the_exit_statement;
783  sequence_statements(instruction_sequence(the_exit_instruction)) =
784  the_statements;
785 
786  control_statement(exit_node) = first_statement;
787  /* Then, append the last statements at the end of the
788  unstructured: */
789  the_unstructured = instruction_to_statement(i);
792  the_unstructured,
793  /* ...followed by the last
794  statements: */
795  CONS(STATEMENT,
796  last_statements,
797  NIL)));
798  /* Fix the variables for the following pass: */
799  the_exit_statement = first_statement;
800  the_exit_instruction = statement_instruction(the_exit_statement);
801  }
802  /* Here the_exit_statement is not a sequence. */
803  if (! empty_statement_or_continue_p(the_exit_statement)
804  && ! return_statement_p(the_exit_statement)) {
805  statement new_statement;
806  statement out_keeping;
807  /* Put an empty exit node and keep the statement for the
808  label: */
809  statement_instruction(the_exit_statement) =
811  ifdebug (1)
812  pips_assert("Statement is consistent", statement_consistent_p(the_exit_statement));
813  /* Replace the unstructured by an unstructured followed by the
814  out-keeped instruction: */
815  new_statement = instruction_to_statement(i);
816  out_keeping = instruction_to_statement(the_exit_instruction);
817  /* Keep track of the statement number: */
818  statement_number(out_keeping) = statement_number(the_exit_statement);
819  statement_instruction(the_unstructured) =
821  new_statement,
822  CONS(STATEMENT, out_keeping, NIL)));
823  the_unstructured = new_statement;
824  }
825  /* Heavily rely on a later clean_up_sequences to normalize the
826  above... */
827 
828  ifdebug (1)
829  pips_assert("Statement is consistent", statement_consistent_p(s));
830 
831  return the_unstructured;
832 }
833 
834 
835 static void
838 {
839  statement the_test_statement = control_statement(c);
840  test the_test = instruction_test(statement_instruction(the_test_statement));
841  control then_node = CONTROL(CAR(control_successors(c)));
842  control else_node = CONTROL(CAR(CDR(control_successors(c))));
843  statement then_statement = control_statement(then_node);
844  statement else_statement = control_statement(else_node);
845  control test_exit;
846 
847  ifdebug(9) {
848  pips_debug(9, "the test statement:\n");
849  /* print_statement(the_test_statement); */
850  pips_assert("Statement is consistent",
851  statement_consistent_p(the_test_statement));
852  }
853 
854  /* Find the exit node of the test: */
855  if (t == STRUCTURED_NULL_IF)
856  test_exit = then_node;
857  else if (t == STRUCTURED_IF_THEN || t == STRUCTURED_IF_THEN_ELSE)
858  test_exit = CONTROL(CAR(control_successors(then_node)));
859  else
860  test_exit = CONTROL(CAR(control_successors(else_node)));
861  pips_debug(9, "exit node=%p\n", test_exit);
862 
863  /* Discard and unlink the then_node and else_node if any: */
866  then_node);
869  else_node);
870 
871  /* Now rebuild a structured test in the node c from the previous
872  test branch contents: */
873  if (t == STRUCTURED_IF_THEN || t == STRUCTURED_IF_THEN_ELSE) {
874  free_statement(test_true(the_test));
875  test_true(the_test) = then_statement;
876  ifdebug(9) {
877  pips_debug(9, "then statement:\n");
878  /* print_statement(then_statement); */
879  pips_assert("Statement is consistent",
880  statement_consistent_p(then_statement));
881  }
882  }
883  if (t == STRUCTURED_IF_ELSE || t == STRUCTURED_IF_THEN_ELSE) {
884  free_statement(test_false(the_test));
885  test_false(the_test) = else_statement;
886  ifdebug(9) {
887  pips_debug(9, "else statement:\n");
888  /* print_statement(else_statement); */
889  pips_assert("Statement is consistent",
890  statement_consistent_p(else_statement));
891  }
892  }
893 
894  /* Replace the useless CONTINUE by a NOP to improve the
895  prettyprinted code: */
896  if (t == STRUCTURED_IF_THEN || t == STRUCTURED_NULL_IF) {
897  free_statement(test_false(the_test));
898  test_false(the_test) = make_empty_statement();
899  }
900  if (t == STRUCTURED_IF_ELSE || t == STRUCTURED_NULL_IF) {
901  free_statement(test_true(the_test));
902  test_true(the_test) = make_empty_statement();
903  }
904 
905  if (t == STRUCTURED_NULL_IF)
906  /* Remove one of the 2 branches, since it is symetrical. In
907  fact, since unlink_2_control_nodes() removes all the
908  redundant branches, need to relink later: */
909  unlink_2_control_nodes(c, test_exit);
910  if (t == STRUCTURED_IF_THEN_ELSE || t == STRUCTURED_NULL_IF) {
911  /* Relink the structured test node to the successor since both
912  pathes have been removed: */
913  link_2_control_nodes(c, test_exit);
914  }
915  /* In the other case, the remaining link is just what needed. */
916 
917  ifdebug(9) {
918  pips_debug(9, "the test statement:\n");
919  /* print_statement(the_test_statement); */
920  pips_assert("Statement is consistent",
921  statement_consistent_p(the_test_statement));
922  }
923 }
924 
925 
926 /* Try to restructure the unstructured IF/THEN/ELSE.
927  Assume that all the sequences has been previously fused.
928  */
929 static bool
931 {
932  list blocs = NIL;
933  bool code_modified_p = false;
935  /* The entry point of the unstructured: */
936  control entry_node = unstructured_control(u);
937 
938  /* To store the tests that can be restructured with their test
939  types: */
940  hash_table structured_tests = hash_table_make(hash_int, 0);
941 
942  pips_assert("Control is consistent", control_consistent_p(entry_node));
943 
944  /* First mark the IF that can be restructured: */
945  CONTROL_MAP(c,
946  {
947  /* Only look at test nodes: */
948  if (gen_length(control_successors(c)) == 2) {
949  control then_node =
951  control else_node =
953  int then_node_fan_out =
954  gen_length(control_successors(then_node));
955  /* Note that if a node is the entry node, its
956  fan in is once more! Nasty bug... */
957  int then_node_fan_in =
958  gen_length(control_predecessors(then_node))
959  + (then_node == entry_node);
960  int else_node_fan_out =
961  gen_length(control_successors(else_node));
962  int else_node_fan_in =
963  gen_length(control_predecessors(else_node))
964  + (else_node == entry_node);
965 
966  if (then_node == else_node) {
967  /* We've found a structured null if, that
968  is with the then and else branches
969  pointing to the same target: */
970  hash_put(structured_tests,
971  (char *) c,
972  (char *) STRUCTURED_NULL_IF);
974  }
975  else if (then_node_fan_out == 1
976  && else_node_fan_out == 1
977  && then_node_fan_in == 1
978  && else_node_fan_in == 1
979  && CONTROL(CAR(control_successors(then_node))) == CONTROL(CAR(control_successors(else_node)))) {
980  /* We've found a structured if/then/else: */
981  hash_put(structured_tests,
982  (char *) c,
983  (char *) STRUCTURED_IF_THEN_ELSE);
985  }
986  else if (then_node_fan_out == 1
987  && then_node_fan_in == 1
988  && CONTROL(CAR(control_successors(then_node))) == else_node) {
989  /* We've found a structured if/then
990  without else: */
991  hash_put(structured_tests,
992  (char *) c,
993  (char *) STRUCTURED_IF_THEN);
995  }
996  else if (else_node_fan_out == 1
997  && else_node_fan_in == 1
998  && CONTROL(CAR(control_successors(else_node))) == then_node) {
999  /* We've found a structured if/else
1000  without then: */
1001  hash_put(structured_tests,
1002  (char *) c,
1003  (char *) STRUCTURED_IF_ELSE);
1005  }
1006  }
1007  },
1008  entry_node,
1009  blocs);
1010  gen_free_list(blocs);
1011 
1012  debug(5, "restructure_if_then_else",
1013  "%d if/then, %d if/else, %d if/then/else, %d null if\n",
1018 
1019  /* Then restructure if needed: */
1020 
1021  HASH_MAP(key, value,
1022  {
1023  control c = (control) key;
1025  /* Hidden in a function to ease debugging... */
1026  restructure_this_test(c, t);
1027  /* The code has been modified: */
1028  code_modified_p = true;
1029  },
1030  structured_tests);
1031 
1032  /* Return the number of tests that has been restructured: */
1033  return code_modified_p;
1034 }
1035 
1036 
1037 /* Try to recursively restructure the unstructured: */
1038 static void
1040 {
1041  /* Used to keep track of the statement that contains directly the
1042  unstructured: */
1043  statement new_unstructured_statement;
1046  /* Just stop, it is not or no longer an unstructured. */
1047  return;
1048 
1049  /* Replace control sequences by simple nodes: */
1051  ifdebug(5) {
1052  pips_debug(5, "after fuse_sequences_in_unstructured\n");
1053  /* print_statement(s); */
1054  pips_assert("Statement is consistent", statement_consistent_p(s));
1055  }
1056 
1057  if (take_out_the_entry_node_of_the_unstructured(s, &new_unstructured_statement)) {
1058  /* If take_out_the_entry_node_of_the_unstructured() has not been
1059  able to discard the unstructured, go on with some other
1060  optimizations: */
1061  /* ifdebug(5) { */
1062  /* pips_debug(5, */
1063  /* "after take_out_the_entry_node_of_the_unstructured\n"); */
1064  /* print_statement(s); */
1065  /* } */
1066 
1067  new_unstructured_statement =
1068  take_out_the_exit_node_if_not_a_continue(new_unstructured_statement);
1069 
1070  ifdebug(5) {
1071  pips_debug(5, "after take_out_the_exit_node_if_not_a_continue\n");
1072  /* print_statement(s); */
1073  pips_assert("Statement is consistent", statement_consistent_p(s));
1074  }
1075 
1076  /* If we ask for, try to restructure the tests: */
1078  && restructure_if_then_else(new_unstructured_statement)) {
1079  ifdebug(5) {
1080  pips_debug(5, "after restructure_if_then_else\n");
1081  /* print_statement(s); */
1082  pips_assert("Statement is consistent", statement_consistent_p(s));
1083  }
1084  /* Well, some tests has been restructured, recurse: */
1085  recursively_restructure_an_unstructured(new_unstructured_statement);
1086  }
1087  }
1088 }
1089 
1090 
1091 /* This is the function that is applied on each statement of the code
1092  in a bottom-up way to clean up easy things after the
1093  controlizer. Even if we deal with the control graph, that is the
1094  "unstructured" instruction, we need to deal with the statement over
1095  the unstructured since the restructuration can move some code
1096  outside of the unstructured in the statement. */
1097 static void
1099 {
1101 
1102  if (instruction_unstructured_p(i)) {
1104 
1105  pips_debug(2, "enter\n");
1106  ifdebug (3) {
1108  /* fprintf(stderr, "[ The current statement : ]\n"); */
1109  /* print_statement(s); */
1110  }
1111  clean_up_exit_node(u);
1112 
1114 
1115  ifdebug(5) {
1116  pips_assert("Consistent unstructured", unstructured_consistent_p(u));
1117  pips_debug(5, "after remove_the_unreachable_controls_of_an_unstructured\n");
1118  pips_debug(5, "Accessible nodes from entry:\n");
1120  pips_debug(5, "Accessible nodes from exit:\n");
1122  /* print_statement(s); */
1123  }
1124 
1126 
1127  ifdebug(5) {
1128  pips_assert("Consistent unstructured", unstructured_consistent_p(u));
1129  pips_debug(5, "after remove_useless_continue_or_empty_code_in_unstructured\n");
1130  /* print_statement(s); */
1131  }
1132  pips_debug(2, "exit\n");
1133  }
1134 }
1135 
1136 
1137 /* Try to recover structured while loops in an already recursively
1138  restructured control graph */
1139 static void
1141  control entry_node = unstructured_control(u);
1142  control next = CONTROL(CAR(control_successors(entry_node)));
1143  size_t arity = gen_length(control_successors(entry_node));
1144  control exit_node = unstructured_exit(u);
1145  int line_number;
1146 
1147  ifdebug (3) {
1148  pips_debug(2, "At entry, from the entry node:\n");
1149  display_linked_control_nodes(entry_node);
1150  }
1151 
1152  switch(arity) {
1153  case 0:
1154  /* It looks like a single node unstructured. Nothing to look at,
1155  here. Anyway, it should not exist if the restructured was launched
1156  on the graph before... */
1157  return;
1158 
1159  case 1:
1160  /* There is one simple node at unstructured entry:
1161  try to detect a "do ... while();" */
1162  if (gen_length(control_successors(next)) != 2)
1163  // next is not a test, so no while to be expected here...
1164  return;
1165 
1166  line_number = statement_number(control_statement(next));
1168  expression cond = test_condition(t);
1169  control then_c = CONTROL(CAR(control_successors(next)));
1170  control else_c = CONTROL(CAR(CDR(control_successors(next))));
1171 
1172  if (then_c == entry_node && else_c == exit_node) {
1173  /* We have
1174  entry:
1175  ...
1176  if (cond) goto entry;
1177  exit:
1178  */
1179  // See afterwards to generate the "do ... while(cond)"
1180  }
1181  else if (then_c == exit_node && else_c == entry_node) {
1182  /* We have
1183  entry:
1184  ...
1185  if (cond)
1186  goto exit;
1187  else goto entry;
1188  */
1189  // We need to negate the condition to generate a "do ... while(!cond)"
1191  }
1192  else
1193  // No "while" detected here:
1194  return;
1195 
1196  /* Build the equivalent " do body; while(cond)". Do not save any
1197  label yet, but use the same line number as the "if" one: */
1198  statement body = control_statement(entry_node);
1200  body,
1201  line_number,
1202  false);
1203  control_statement(entry_node) = w;
1204  /* Remove the test control node after having protected recycled old
1205  stuff from being discarded: */
1208 
1209  /* Relink the remaining nodes in sequence, to be fused later somewhere
1210  else: */
1211  link_2_control_nodes(entry_node, exit_node);
1213  break;
1214 
1215  case 2: {
1216  // The entry node is a test. Try to detect a "while() ...;"
1217  line_number = statement_number(control_statement(next));
1219  expression cond = test_condition(t);
1220  control then_c = CONTROL(CAR(control_successors(entry_node)));
1221  control else_c = CONTROL(CAR(CDR(control_successors(entry_node))));
1222  control body_control = control_undefined;
1224 
1225  if (else_c == exit_node) {
1226  if (then_c == entry_node) {
1227  /* we have:
1228  entry: if (cond) goto entry;
1229  exit:
1230 
1231  so we can generate a while(cond);
1232  */
1233  }
1234  else if (gen_length(control_successors(then_c)) == 1
1235  && CONTROL(CAR(control_successors(then_c))) == entry_node) {
1236  /* we have:
1237  entry: if (cond) {
1238  body
1239  goto entry;
1240  }
1241  exit:
1242 
1243  so we can generate a while(cond) body;
1244  */
1245  body_control = then_c;
1246  }
1247  else
1248  // No while() recognized here...
1249  return;
1250  }
1251  else if (then_c == exit_node) {
1252  if (else_c == entry_node) {
1253  /* we have:
1254  entry: if (cond) goto exit;
1255  else goto entry;
1256  exit:
1257 
1258  so we can generate a while(!cond);
1259  */
1261  }
1262  else if (gen_length(control_successors(else_c)) == 1
1263  && CONTROL(CAR(control_successors(else_c))) == entry_node) {
1264  /* we have:
1265  entry: if (cond) goto exit;
1266  else {
1267  body
1268  goto entry;
1269  }
1270  exit:
1271 
1272  so we can generate a while(!cond) body;
1273  */
1274  body_control = else_c;
1276  }
1277  else
1278  // No while() recognized here...
1279  return;
1280  }
1281  else
1282  // No while() recognized here...
1283  return;
1284 
1285  if (body_control != control_undefined) {
1286  // Keep the body to put it in the while later:
1287  body = control_statement(body_control);
1288  // Remove the control node of the body:
1289  control_statement(body_control) = statement_undefined;
1291  }
1292  else {
1293  // Make an empty body for the loop:
1295  // Remove the arc from the "if" to itself:
1296  unlink_2_control_nodes(entry_node, entry_node);
1297  }
1298 
1299  /* Build the equivalent "while(cond) body;". Do not save any label
1300  yet, but use the same line number as the "if" one: */
1302  body,
1303  line_number,
1304  true);
1305  // Remove the test node and replace it by the "while":
1307  free_statement(control_statement(entry_node));
1308  control_statement(entry_node) = w;
1309  /* Other restructuring is applied afterwards to replace the
1310  unstructured by a simple statement, the entry and the exit are
1311  still linked into a lazy sequence. */
1313  break;
1314  }
1315  default:
1316  // This case is not expected in the RI!
1317  pips_internal_error("A node cannot have %zd successors!", arity);
1318  }
1319  // If we land here, the restructuring has taken place above...
1320  /* Increase the statistics. Used to rerun a restrustructuring shot after
1321  a modification too: */
1322  ifdebug (3) {
1323  pips_debug(2, "After while recovering, from the entry node:\n");
1325  }
1326 }
1327 
1328 /* The entry point common to unspaghettify or restructure a module: */
1329 void
1331 {
1332  /* Track the number of restructurations done for a fix point: */
1333  int nr = 0;
1334  int old_nr;
1335  /* To track the number of restructuring iterations: */
1336  int iter = 0;
1337 
1338  // Note that this debug is not controlled by "UNSPAGHETTIFY_DEBUG_LEVEL":
1339  /* ifdebug(5) { */
1340  /* pips_debug(5, "Statement before unspaghettify_or_restructure_statement:\n"); */
1341  /* print_statement(mod_stmt); */
1342  /* } */
1343 
1344  debug_on("UNSPAGHETTIFY_DEBUG_LEVEL");
1345 
1346  ifdebug (1)
1347  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1348 
1349  if (get_bool_property("GATHER_FORMATS_AT_BEGINNING"))
1351  else if (get_bool_property("GATHER_FORMATS_AT_END"))
1352  put_formats_at_module_end(mod_stmt);
1353 
1354  ifdebug (1)
1355  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1356 
1358 
1359  do {
1360  old_nr = nr;
1361  /* Split the recursion in three parts to fit in my brain: */
1362  /* First, clean up easy things done by the controlizer: */
1363  gen_recurse(mod_stmt, statement_domain,
1365 
1366  ifdebug (1)
1367  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1368 
1370  /* Then try to hierarchize the control flow: */
1371  gen_recurse(mod_stmt, unstructured_domain,
1373 
1374  ifdebug (1)
1375  pips_assert("Statement is consistent",
1376  statement_consistent_p(mod_stmt));
1377  }
1378 
1379  /* Now apply some local rule, such as if/then/else restructuring
1380  and so on: */
1381  gen_recurse(mod_stmt, statement_domain,
1383 
1384  ifdebug (1)
1385  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1386 
1387  if (get_bool_property("UNSPAGHETTIFY_WHILE_RECOVER"))
1388  gen_recurse(mod_stmt, unstructured_domain,
1390 
1391  /* End by removing parasitic sequences: */
1392  clean_up_sequences(mod_stmt);
1393 
1394  ifdebug (1)
1395  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1396 
1397  /* If something changed, retry further restructuring: */
1399  ifdebug(2)
1401  } while (nr != old_nr && ++iter < N_ITER_RESTRUCTURE_FIX_POINT);
1402 
1403  if (nr != old_nr)
1404  pips_user_warning("Possible infinite loop restructuring found.\n");
1405 
1406  pips_debug(2, "done\n");
1407 
1409 
1410  debug_off();
1411  // Note that this debug is not controlled by "UNSPAGHETTIFY_DEBUG_LEVEL":
1412  /* ifdebug(5) { */
1413  /* pips_debug(5, "Statement after unspaghettify_or_restructure_statement:\n"); */
1414  /* print_statement(mod_stmt); */
1415  /* } */
1416 }
1417 
1418 
1419 /* The real entry point of unspaghettify: */
1420 void
1422 {
1424  get_bool_property("UNSPAGHETTIFY_TEST_RESTRUCTURING");
1426  get_bool_property("UNSPAGHETTIFY_RECURSIVE_DECOMPOSITION");
1427 
1429 }
1430 
1431 
1432 /* A simple cleaning of the control graph without major topological
1433  restructuring. Used by example by PHRASE. */
1434 void
1436 {
1439 
1441 }
1442 
1443 
1444 /* Try to simplify the control graph of a module by removing useless
1445  CONTINUEs, unreachable code. Try to structure a little bit more and
1446  so on according to some properties.
1447 
1448  Unspaguettify is now targetted to be included in the controlizer.
1449  */
1450 bool unspaghettify(const string mod_name)
1451 {
1452  statement mod_stmt;
1453 
1454  /* Get the true resource, not a copy. */
1455  mod_stmt = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
1456  set_current_module_statement(mod_stmt);
1457 
1459 
1460  unspaghettify_statement(mod_stmt);
1461 
1462  /* Reorder the module, because new statements may have been
1463  changed. */
1464  module_reorder(mod_stmt);
1465 
1466  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(mod_name), mod_stmt);
1467 
1470 
1471  return true;
1472 }
1473 
1474 
1475 /* The real entry point of control graph restructuring: */
1476 void
1478 {
1481 
1483 }
1484 
1485 
1486 /* Try to simplify the control graph of a module by removing useless
1487  CONTINUEs, unreachable code, etc. as in unspaghettify.
1488 
1489  Do also test restructuring and control graph recursive graph
1490  decomposition.
1491  */
1492 bool restructure_control(const string mod_name)
1493 {
1494  statement mod_stmt;
1495 
1496  /* Get the true resource, not a copy. */
1497  mod_stmt = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
1498  set_current_module_statement(mod_stmt);
1499 
1501 
1502  restructure_statement(mod_stmt);
1503 
1504  /* Reorder the module, because new statements may have been
1505  changed. */
1506  module_reorder(mod_stmt);
1507 
1508  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(mod_name), mod_stmt);
1509 
1512 
1513  return true;
1514 }
void user_log(const char *format,...)
Definition: message.c:234
bool unstructured_consistent_p(unstructured p)
Definition: ri.c:2751
bool statement_consistent_p(statement p)
Definition: ri.c:2195
void free_instruction(instruction p)
Definition: ri.c:1118
bool control_consistent_p(control p)
Definition: ri.c:496
void free_statement(statement p)
Definition: ri.c:2189
bool clean_up_sequences_internal(statement s)
An entry point for internal usage, such as from take_out_the_exit_node_if_not_a_continue():
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
void control_graph_recursive_decomposition(unstructured)
hierarchize.c
Definition: hierarchize.c:563
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
void unlink_2_control_nodes(control source, control target)
Remove all edged between 2 control nodes.
Definition: control.c:1276
void remove_all_unreachable_controls_of_an_unstructured(unstructured u)
Remove all control nodes that are not forward reachable from the entry node.
Definition: control.c:812
void display_linked_control_nodes(control c)
Display all the control nodes reached or reachable from c for debugging purpose.
Definition: control.c:629
void link_2_control_nodes(control source, control target)
Add an edge between 2 control nodes.
Definition: control.c:1193
void remove_a_control_from_an_unstructured_without_relinking(control c)
It removes a control node from its successor and predecessor.
Definition: control.c:1031
void discard_an_unstructured_without_its_statements(unstructured u)
Used to discard an unstructured without touching its statements.
Definition: control.c:1063
void remove_a_control_from_an_unstructured(control c)
Remove a control node from a control graph.
Definition: control.c:992
void discard_a_control_sequence_without_its_statements(control begin, control end)
Remove a control sequence without touching its statements.
Definition: control.c:1111
void fuse_2_control_nodes(control first, control second)
Fuse a 2 control nodes.
Definition: control.c:1391
list generate_a_statement_list_from_a_control_sequence(control begin, control end)
Take a control sequence and return a list of all the statements in the sequence (in the same order....
Definition: control.c:1156
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
instruction make_continue_instruction()
Creates a CONTINUE instruction, that is the FORTRAN nop, the ";" in C or the "pass" in Python for exa...
Definition: instruction.c:79
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
bool unlabelled_statement_p(statement)
Definition: statement.c:402
bool nop_statement_p(statement)
Definition: statement.c:407
bool empty_statement_or_continue_p(statement)
Return true if the statement is an empty instruction block or a continue or a recursive combination o...
Definition: statement.c:474
bool empty_statement_or_continue_without_comment_p(statement)
Return true if the statement is an empty instruction block or a continue without comments or without ...
Definition: statement.c:497
list statement_to_implicit_target_labels(statement)
Look for labels appearing in END= or ERR= IO clauses and allocate a label list.
Definition: statement.c:3145
entity statement_to_label(statement)
See if statement s is labelled and can be reached by a GO TO.
Definition: statement.c:2090
statement make_whileloop_statement(expression, statement, int, bool)
Build a while loop statement.
Definition: statement.c:1150
void put_formats_at_module_beginning(statement)
Transfer all the FORMATs at the very beginning of a module:
Definition: statement.c:2311
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700
bool return_statement_p(statement)
Test if a statement is a C or Fortran "return".
Definition: statement.c:172
void put_formats_at_module_end(statement)
Transfer all the FORMATs at the very end of a module:
Definition: statement.c:2328
statement make_continue_statement(entity)
Definition: statement.c:953
bool statement_with_empty_comment_p(statement)
Return true if the statement has an empty statement:
Definition: statement.c:126
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
struct _newgen_struct_control_ * control
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
void print_arguments(list args)
Definition: naming.c:228
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
@ hash_int
Definition: newgen_hash.h:32
@ hash_pointer
Definition: newgen_hash.h:32
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define C_NOT_OPERATOR_NAME
#define empty_comments
Empty comments (i.e.
#define make_empty_statement
An alias for make_empty_block_statement.
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
entity entity_empty_label(void)
Definition: entity.c:1105
entity CreateIntrinsic(string name)
this function does not create an intrinsic function because they must all be created beforehand by th...
Definition: entity.c:1311
expression MakeUnaryCall(entity f, expression a)
Creates a call expression to a function with one argument.
Definition: expression.c:342
#define control_undefined
Definition: ri.h:916
#define instruction_sequence_p(x)
Definition: ri.h:1512
#define unstructured_domain
newgen_type_domain_defined
Definition: ri.h:442
#define CONTROL_(x)
Definition: ri.h:913
#define control_predecessors(x)
Definition: ri.h:943
#define test_false(x)
Definition: ri.h:2837
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define statement_label(x)
Definition: ri.h:2450
#define expression_undefined
Definition: ri.h:1223
#define test_true(x)
Definition: ri.h:2835
#define sequence_statements(x)
Definition: ri.h:2360
#define instruction_sequence(x)
Definition: ri.h:1514
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define instruction_unstructured_p(x)
Definition: ri.h:1530
#define test_condition(x)
Definition: ri.h:2833
#define statement_instruction(x)
Definition: ri.h:2458
#define statement_comments(x)
Definition: ri.h:2456
#define control_statement(x)
Definition: ri.h:941
#define instruction_test(x)
Definition: ri.h:1517
#define statement_number(x)
Definition: ri.h:2452
#define instruction_unstructured(x)
Definition: ri.h:1532
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
@ N_ITER_RESTRUCTURE_FIX_POINT
Definition: unspaghettify.c:53
static int number_of_recovered_do_while
Definition: unspaghettify.c:71
static void display_unspaghettify_statistics()
Definition: unspaghettify.c:99
static int number_of_restructured_if_then_else
Definition: unspaghettify.c:69
bool unspaghettify(const string mod_name)
Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code.
bool restructure_control(const string mod_name)
Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code,...
static int number_of_restructured_null_if
Definition: unspaghettify.c:70
static int total_number_of_restructurations()
Compute the number of all the computations that have been done.
Definition: unspaghettify.c:89
static void clean_up_exit_node(unstructured u)
The controlizer of PIPS seems to have a bug: it put an empty successor node to the so-called exit nod...
static void initialize_unspaghettify_statistics()
Definition: unspaghettify.c:76
static int number_of_restructured_if_then
To print some statistics about control graph restructuration:
Definition: unspaghettify.c:67
void unspaghettify_or_restructure_statement(statement mod_stmt)
The entry point common to unspaghettify or restructure a module:
void simple_restructure_statement(statement mod_stmt)
A simple cleaning of the control graph without major topological restructuring.
static void recursively_restructure_an_unstructured(statement s)
Try to recursively restructure the unstructured:
statement take_out_the_exit_node_if_not_a_continue(statement s)
Extract the statement from an exit node of an unstructured statement if it is a useful statement.
static void remove_useless_continue_or_empty_code_in_unstructured(unstructured u)
Remove a useless continue in a sequence of control since it is typically the kind of useless things g...
void restructure_statement(statement mod_stmt)
The real entry point of control graph restructuring:
static void recover_structured_while(unstructured u)
Try to recover structured while loops in an already recursively restructured control graph.
void fuse_sequences_in_unstructured(statement s)
Try to transform each control sequence in a single statement instead of a list of control nodes:
static int number_of_restructured_if_else
Definition: unspaghettify.c:68
void unspaghettify_statement(statement mod_stmt)
The real entry point of unspaghettify:
static bool restructure_if_then_else(statement s)
Try to restructure the unstructured IF/THEN/ELSE.
static void restructure_this_test(control c, structured_test_type t)
static bool take_out_the_entry_node_of_the_unstructured(statement s, statement *new_unstructured_statement)
Take the entry node out of the unstructured if it is not useful, such as not an IF or a node without ...
static int number_of_recovered_while
Definition: unspaghettify.c:72
static void clean_up_control(statement s)
This is the function that is applied on each statement of the code in a bottom-up way to clean up eas...
char vcid_unspaghettify[]
Ronan Keryell, 1995.
Definition: unspaghettify.c:30
static bool __attribute__((unused))
If the unstructured begin and/or end with a sequence, move the sequence(s) out of the unstructured an...
static bool currently_apply_recursive_decomposition
Definition: unspaghettify.c:64
structured_test_type
Definition: unspaghettify.c:55
@ STRUCTURED_IF_THEN_ELSE
Definition: unspaghettify.c:59
@ STRUCTURED_NULL_IF
Definition: unspaghettify.c:56
@ STRUCTURED_IF_ELSE
Definition: unspaghettify.c:58
@ STRUCTURED_IF_THEN
Definition: unspaghettify.c:57
static bool currently_apply_test_restructuring
Definition: unspaghettify.c:63