PIPS
unspaghettify.c File Reference
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "linear.h"
#include "genC.h"
#include "ri.h"
#include "ri-util.h"
#include "workspace-util.h"
#include "text-util.h"
#include "database.h"
#include "misc.h"
#include "pipsdbm.h"
#include "resources.h"
#include "properties.h"
#include "control.h"
+ Include dependency graph for unspaghettify.c:

Go to the source code of this file.

Enumerations

enum  { N_ITER_RESTRUCTURE_FIX_POINT = 10 }
 lint More...
 
enum  structured_test_type { STRUCTURED_NULL_IF = 1901 , STRUCTURED_IF_THEN = 1966 , STRUCTURED_IF_ELSE = 1997 , STRUCTURED_IF_THEN_ELSE = 2000 }
 

Functions

static void initialize_unspaghettify_statistics ()
 
static int total_number_of_restructurations ()
 Compute the number of all the computations that have been done. More...
 
static void display_unspaghettify_statistics ()
 
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 generated by the controlizer... More...
 
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 node. More...
 
void fuse_sequences_in_unstructured (statement s)
 Try to transform each control sequence in a single statement instead of a list of control nodes: More...
 
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 predecessor. More...
 
static bool __attribute__ ((unused))
 If the unstructured begin and/or end with a sequence, move the sequence(s) out of the unstructured and return a new statement with an equivalent but more structured code. More...
 
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. More...
 
static void restructure_this_test (control c, structured_test_type t)
 
static bool restructure_if_then_else (statement s)
 Try to restructure the unstructured IF/THEN/ELSE. More...
 
static void recursively_restructure_an_unstructured (statement s)
 Try to recursively restructure the unstructured: More...
 
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 easy things after the controlizer. More...
 
static void recover_structured_while (unstructured u)
 Try to recover structured while loops in an already recursively restructured control graph. More...
 
void unspaghettify_or_restructure_statement (statement mod_stmt)
 The entry point common to unspaghettify or restructure a module: More...
 
void unspaghettify_statement (statement mod_stmt)
 The real entry point of unspaghettify: More...
 
void simple_restructure_statement (statement mod_stmt)
 A simple cleaning of the control graph without major topological restructuring. More...
 
bool unspaghettify (const string mod_name)
 Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code. More...
 
void restructure_statement (statement mod_stmt)
 The real entry point of control graph restructuring: More...
 
bool restructure_control (const string mod_name)
 Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code, etc. More...
 

Variables

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."
 Ronan Keryell, 1995. More...
 
static bool currently_apply_test_restructuring
 
static bool currently_apply_recursive_decomposition
 
static int number_of_restructured_if_then
 To print some statistics about control graph restructuration: More...
 
static int number_of_restructured_if_else
 
static int number_of_restructured_if_then_else
 
static int number_of_restructured_null_if
 
static int number_of_recovered_do_while
 
static int number_of_recovered_while
 

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

lint

Avoid infinite restructuring in some cases:

Enumerator
N_ITER_RESTRUCTURE_FIX_POINT 

Definition at line 53 of file unspaghettify.c.

@ N_ITER_RESTRUCTURE_FIX_POINT
Definition: unspaghettify.c:53

◆ structured_test_type

Enumerator
STRUCTURED_NULL_IF 
STRUCTURED_IF_THEN 
STRUCTURED_IF_ELSE 
STRUCTURED_IF_THEN_ELSE 

Definition at line 55 of file unspaghettify.c.

55  {
56  STRUCTURED_NULL_IF = 1901,
57  STRUCTURED_IF_THEN = 1966,
58  STRUCTURED_IF_ELSE = 1997,
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

Function Documentation

◆ __attribute__()

static bool __attribute__ ( (unused)  )
static

If the unstructured begin and/or end with a sequence, move the sequence(s) out of the unstructured and return a new statement with an equivalent but more structured code.

It returns true if the unstructured has disappeared and else FALSE.

If the unstructured is still here, the statement directly owning it is returned in new_unstructured_statement: Still buggy. No longer used.

no gcc warning

The entry point of the unstructured:

and its exit point:

Find the biggest sequence from the begin:

Well, we have an unstructured with one control node, it is still a sequence:

It is in fact the exit_node:

OK, there is a sequence at the beginning of the unstructured:

If there is still something in the sequence:

Find the biggest sequence from the end:

In fact, an unstructured IF is noted as a control node with 2 successors, that means that we cannot take the biggest sequence since it may move one successor of such an IF and PIPS would be out.

OK, it is actually an IF before the end sequence. Try to keep a spare node from the sequence. Since the controllizer seems to put always a continue as an IF successor, it is seems sensible.

There is one successor, that is the sequence has at least 2 control node. Keep the first node as part as IF unstructured:

There is only one node in the sequence. It remains in the unstructured:

Then there is a sequence at the end of the unstructured:

Now, restructure all the stuff only if there is something to do:

All the unstructured is a sequence, replace it with the equivalent block of statement statement:

Discard the unstructured instruction:

Warn that the unstructured no longer exist:

There is still an unstructured, but with one pre- or post-sequence:

Put the unstructured in the new statement list:

There is a pre-sequence before the unstructured:

Put the sequence before the unstructured:

Update the entry node of the unstructured:

Clean up the equivalent control sequence:

There is a post-sequence after the unstructured:

Update the exit node of the unstructured:

Clean up the equivalent control sequence:

Make the instruction of the old statement with the sequence(s) and the stripped-down unstructured:

By default the unstructured is not changed, thus return the statement owning it:

Definition at line 562 of file unspaghettify.c.

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 }
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
void discard_an_unstructured_without_its_statements(unstructured u)
Used to discard an unstructured without touching its statements.
Definition: control.c:1063
void discard_a_control_sequence_without_its_statements(control begin, control end)
Remove a control sequence without touching its statements.
Definition: control.c:1111
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
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#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
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define control_undefined
Definition: ri.h:916
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define statement_instruction(x)
Definition: ri.h:2458
#define instruction_unstructured(x)
Definition: ri.h:1532
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

References CAR, CONS, CONTROL, control_predecessors, control_successors, control_undefined, discard_a_control_sequence_without_its_statements(), discard_an_unstructured_without_its_statements(), gen_length(), gen_nconc(), generate_a_statement_list_from_a_control_sequence(), instruction_to_statement(), instruction_unstructured, make_instruction_block(), NIL, STATEMENT, statement_instruction, statement_undefined, unstructured_control, and unstructured_exit.

+ Here is the call graph for this function:

◆ clean_up_control()

static void clean_up_control ( statement  s)
static

This is the function that is applied on each statement of the code in a bottom-up way to clean up easy things after the controlizer.

Even if we deal with the control graph, that is the "unstructured" instruction, we need to deal with the statement over the unstructured since the restructuration can move some code outside of the unstructured in the statement.

fprintf(stderr, "[ The current statement : ]\n");

print_statement(s);

print_statement(s);

print_statement(s);

Definition at line 1098 of file unspaghettify.c.

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 }
bool unstructured_consistent_p(unstructured p)
Definition: ri.c:2751
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
#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_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define instruction_unstructured_p(x)
Definition: ri.h:1530
#define ifdebug(n)
Definition: sg.c:47
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 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...

References clean_up_exit_node(), display_linked_control_nodes(), ifdebug, instruction_unstructured, instruction_unstructured_p, pips_assert, pips_debug, remove_all_unreachable_controls_of_an_unstructured(), remove_useless_continue_or_empty_code_in_unstructured(), statement_instruction, unstructured_consistent_p(), unstructured_control, and unstructured_exit.

Referenced by unspaghettify_or_restructure_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ clean_up_exit_node()

static void clean_up_exit_node ( unstructured  u)
static

The controlizer of PIPS seems to have a bug: it put an empty successor node to the so-called exit node.

Correct this fact:

Remove the useless node:

Now the exit node has no longer a successor:

Definition at line 221 of file unspaghettify.c.

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 }
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
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
#define CONTROL_(x)
Definition: ri.h:913
#define control_statement(x)
Definition: ri.h:941

References CAR, CONTROL, CONTROL_, control_predecessors, control_statement, control_successors, control_undefined, empty_statement_or_continue_p(), gen_free_list(), gen_length(), NIL, pips_assert, and unstructured_exit.

Referenced by clean_up_control().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ display_unspaghettify_statistics()

static void display_unspaghettify_statistics ( )
static

Definition at line 99 of file unspaghettify.c.

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 }
void user_log(const char *format,...)
Definition: message.c:234
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
static int number_of_recovered_do_while
Definition: unspaghettify.c:71
static int number_of_restructured_if_then_else
Definition: unspaghettify.c:69
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 int number_of_restructured_if_then
To print some statistics about control graph restructuration:
Definition: unspaghettify.c:67
static int number_of_restructured_if_else
Definition: unspaghettify.c:68
static int number_of_recovered_while
Definition: unspaghettify.c:72
static bool currently_apply_test_restructuring
Definition: unspaghettify.c:63

References currently_apply_test_restructuring, get_bool_property(), number_of_recovered_do_while, number_of_recovered_while, number_of_restructured_if_else, number_of_restructured_if_then, number_of_restructured_if_then_else, number_of_restructured_null_if, total_number_of_restructurations(), and user_log().

Referenced by unspaghettify_or_restructure_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fuse_sequences_in_unstructured()

void fuse_sequences_in_unstructured ( statement  s)

Try to transform each control sequence in a single statement instead of a list of control nodes:

The entry point of the unstructured:

and its exit point:

To store the list of the controls to fuse we use a mapping since we need to keep track of eventual previous fuse on a control:

ifdebug(5)

print_statement(s);

Select a node with only one successor:

Since I use an O(n) algorithm instead of an O(n^2) all this condition must be checked again later since these topological and semantical properties may have changed during the fusion phase. I think it is true because the fused graph is included into the former graph but I am too lazy to write a proof... :-( Have a look to Validation/Control/create.f.

...Accept the exit node

Ok, we have found a node in a sequence. Note that we cannot fuse with the entry node since it must keep this role...

But if c is empty, we can fuse it with any successor without changing the semantincs, even if the successor is the entry node. Don't do this if there is a comment since it mess up the original source look-alike.

The fact we can have a cycle is considered a page below...

Put the control in the fuse list. Since no fusing occurs yet, the address of a control node is itself:

Use also a real list to remove the non-determinism of a later HASH_MAP. Note that since it follow a depth-first algorithm, the output program is more likely to be similar to the output, especially with cycles in the control graph:

Reverse the list to follow the order of appearance :

Now, since we have the list of the control nodes to fuse with their successors, do the fusion:

Find the address of a control node to fuse even if it has already been fused with predecessors through a transitive closure:

...The control node has not been moved

...or it has not been moved because it is not a control node to fuse anyway.

Ok, the node has been located:

Follow a former control movement:

ifdebug(5) {

fprintf(stderr,"Statement with label \"s" for control a_control_fo_fuse=p
",

entity_local_name(statement_label(control_statement(a_control_to_fuse))),

a_control_to_fuse);

print_statement(control_statement(a_control_to_fuse));

fprintf(stderr,"Let's print the statement a second time to see its label again:\n");

print_statement(control_statement(a_control_to_fuse));

}

ifdebug(6) {

pips_debug(5, "All the unstructured %p:\n", u);

print_statement(s);

}

Verify that the fusion is still valid:

...Accept the exit node

||entity_empty_label_p(statement_to_label(control_statement(the_successor)))

Well, it seems to be a real sequence, at most a loop with 2 control nodes...

make st with the statements of 2 following nodes:

Update the entry node if we fuse with it:

If the node "the_successor" is in the fuse list, we want to keep track of its new place, that is in fact fused in "a_control_to_fuse", so that an eventual fusion will use "a_control_to_fuse" instead of "the_successor":

Ok, "the_successor" is a node to fuse or that has been already fused (in this case the following is useless, but anyway...). Thus we keep track of its new location:

Update the potentially modified entry and exit nodes:

Definition at line 250 of file unspaghettify.c.

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 }
bool control_consistent_p(control p)
Definition: ri.c:496
if(!(yy_init))
Definition: genread_lex.c:1029
void fuse_2_control_nodes(control first, control second)
Fuse a 2 control nodes.
Definition: control.c:1391
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#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
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
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
void print_arguments(list args)
Definition: naming.c:228
@ hash_pointer
Definition: newgen_hash.h:32
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...

References CAR, CONS, CONTROL, control_consistent_p(), CONTROL_MAP, control_predecessors, control_statement, control_successors, empty_statement_or_continue_p(), empty_statement_or_continue_without_comment_p(), fprintf(), fuse_2_control_nodes(), gen_free_list(), gen_in_list_p(), gen_length(), gen_nreverse(), get_bool_property(), hash_defined_p(), hash_get(), hash_pointer, hash_put(), hash_table_free(), hash_table_make(), hash_update(), ifdebug, instruction_unstructured, MAP, NIL, pips_assert, pips_debug, print_arguments(), statement_instruction, statement_to_implicit_target_labels(), statement_to_label(), unstructured_consistent_p(), unstructured_control, and unstructured_exit.

Referenced by recursively_restructure_an_unstructured().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ initialize_unspaghettify_statistics()

◆ recover_structured_while()

static void recover_structured_while ( unstructured  u)
static

Try to recover structured while loops in an already recursively restructured control graph.

It looks like a single node unstructured. Nothing to look at, here. Anyway, it should not exist if the restructured was launched on the graph before...

There is one simple node at unstructured entry: try to detect a "do ... while();"

We have entry: ... if (cond) goto entry; exit:

We have entry: ... if (cond) goto exit; else goto entry;

Build the equivalent " do body; while(cond)". Do not save any label yet, but use the same line number as the "if" one:

Remove the test control node after having protected recycled old stuff from being discarded:

Relink the remaining nodes in sequence, to be fused later somewhere else:

we have: entry: if (cond) goto entry; exit:

so we can generate a while(cond);

we have: entry: if (cond) { body goto entry; } exit:

so we can generate a while(cond) body;

we have: entry: if (cond) goto exit; else goto entry; exit:

so we can generate a while(!cond);

we have: entry: if (cond) goto exit; else { body goto entry; } exit:

so we can generate a while(!cond) body;

Build the equivalent "while(cond) body;". Do not save any label yet, but use the same line number as the "if" one:

Other restructuring is applied afterwards to replace the unstructured by a simple statement, the entry and the exit are still linked into a lazy sequence.

Increase the statistics. Used to rerun a restrustructuring shot after a modification too:

Definition at line 1140 of file unspaghettify.c.

1140  {
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 }
void free_statement(statement p)
Definition: ri.c:2189
void unlink_2_control_nodes(control source, control target)
Remove all edged between 2 control nodes.
Definition: control.c:1276
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
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
statement make_whileloop_statement(expression, statement, int, bool)
Build a while loop statement.
Definition: statement.c:1150
statement make_continue_statement(entity)
Definition: statement.c:953
#define pips_internal_error
Definition: misc-local.h:149
#define C_NOT_OPERATOR_NAME
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 expression_undefined
Definition: ri.h:1223
#define test_condition(x)
Definition: ri.h:2833
#define instruction_test(x)
Definition: ri.h:1517
#define statement_number(x)
Definition: ri.h:2452

References C_NOT_OPERATOR_NAME, CAR, CDR, CONTROL, control_statement, control_successors, control_undefined, CreateIntrinsic(), display_linked_control_nodes(), entity_empty_label(), expression_undefined, free_statement(), gen_length(), ifdebug, instruction_test, link_2_control_nodes(), make_continue_statement(), make_whileloop_statement(), MakeUnaryCall(), number_of_recovered_do_while, number_of_recovered_while, pips_debug, pips_internal_error, remove_a_control_from_an_unstructured_without_relinking(), statement_instruction, statement_number, statement_undefined, test_condition, unlink_2_control_nodes(), unstructured_control, and unstructured_exit.

Referenced by unspaghettify_or_restructure_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recursively_restructure_an_unstructured()

static void recursively_restructure_an_unstructured ( statement  s)
static

Try to recursively restructure the unstructured:

Used to keep track of the statement that contains directly the unstructured:

Just stop, it is not or no longer an unstructured.

Replace control sequences by simple nodes:

print_statement(s);

If take_out_the_entry_node_of_the_unstructured() has not been able to discard the unstructured, go on with some other optimizations:

ifdebug(5) {

pips_debug(5,

"after take_out_the_entry_node_of_the_unstructured\n");

print_statement(s);

}

print_statement(s);

If we ask for, try to restructure the tests:

print_statement(s);

Well, some tests has been restructured, recurse:

Definition at line 1039 of file unspaghettify.c.

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 }
bool statement_consistent_p(statement p)
Definition: ri.c:2195
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.
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 bool restructure_if_then_else(statement s)
Try to restructure the unstructured IF/THEN/ELSE.
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 ...

References currently_apply_test_restructuring, fuse_sequences_in_unstructured(), ifdebug, instruction_unstructured_p, pips_assert, pips_debug, restructure_if_then_else(), statement_consistent_p(), statement_instruction, take_out_the_entry_node_of_the_unstructured(), and take_out_the_exit_node_if_not_a_continue().

Referenced by unspaghettify_or_restructure_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_useless_continue_or_empty_code_in_unstructured()

static void remove_useless_continue_or_empty_code_in_unstructured ( unstructured  u)
static

Remove a useless continue in a sequence of control since it is typically the kind of useless things generated by the controlizer...

The entry point of the unstructured:

and its exit point:

Do not remove the exit nor the entry node node since it is boring to relink the entry and exit node... That is not important since there is another pass that fuse the sequences. Dead code elimination should remove these structured CONTINUE afterward...

Do not deal with any number of predecessor since we do not want to remove the node 100 in : goto 100 100 goto 200 200 goto 100

There may be also some unreachable continues, that are without predecessors (0)... We want to remove them also.

Well with this modification, I am not sure that this procedure is still useful...

                       So only 0 or 1 predecessor: 

It is some useless code with no comment to spare: put it in the remove list:

Now we have the list of the control node to discard. Do the cleaning:

Definition at line 137 of file unspaghettify.c.

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 }
void remove_a_control_from_an_unstructured(control c)
Remove a control node from a control graph.
Definition: control.c:992
#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
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189

References CAR, CONS, CONTROL, control_consistent_p(), CONTROL_MAP, control_predecessors, control_statement, control_successors, debug(), empty_statement_or_continue_without_comment_p(), gen_free_list(), gen_length(), ifdebug, MAPL, NIL, pips_assert, pips_debug, remove_a_control_from_an_unstructured(), statement_identification(), unstructured_control, and unstructured_exit.

Referenced by clean_up_control().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ restructure_control()

bool restructure_control ( const string  mod_name)

Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code, etc.

as in unspaghettify.

Do also test restructuring and control graph recursive graph decomposition.

Get the true resource, not a copy.

Reorder the module, because new statements may have been changed.

Parameters
mod_nameod_name

Definition at line 1492 of file unspaghettify.c.

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 }
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
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
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 module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
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
char * strdup()
void restructure_statement(statement mod_stmt)
The real entry point of control graph restructuring:

References db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, local_name_to_top_level_entity(), module_reorder(), reset_current_module_entity(), reset_current_module_statement(), restructure_statement(), set_current_module_entity(), set_current_module_statement(), and strdup().

+ Here is the call graph for this function:

◆ restructure_if_then_else()

static bool restructure_if_then_else ( statement  s)
static

Try to restructure the unstructured IF/THEN/ELSE.

Assume that all the sequences has been previously fused.

The entry point of the unstructured:

To store the tests that can be restructured with their test types:

First mark the IF that can be restructured:

Only look at test nodes:

Note that if a node is the entry node, its fan in is once more! Nasty bug...

We've found a structured null if, that is with the then and else branches pointing to the same target:

We've found a structured if/then/else:

We've found a structured if/then without else:

We've found a structured if/else without then:

Then restructure if needed:

Hidden in a function to ease debugging...

The code has been modified:

Return the number of tests that has been restructured:

Definition at line 930 of file unspaghettify.c.

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 }
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
@ hash_int
Definition: newgen_hash.h:32
static void restructure_this_test(control c, structured_test_type t)

References CAR, CDR, CONTROL, control_consistent_p(), CONTROL_MAP, control_predecessors, control_successors, debug(), gen_free_list(), gen_length(), hash_int, HASH_MAP, hash_put(), hash_table_make(), instruction_unstructured, NIL, number_of_restructured_if_else, number_of_restructured_if_then, number_of_restructured_if_then_else, number_of_restructured_null_if, pips_assert, restructure_this_test(), statement_instruction, STRUCTURED_IF_ELSE, STRUCTURED_IF_THEN, STRUCTURED_IF_THEN_ELSE, STRUCTURED_NULL_IF, and unstructured_control.

Referenced by recursively_restructure_an_unstructured().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ restructure_statement()

void restructure_statement ( statement  mod_stmt)

The real entry point of control graph restructuring:

Parameters
mod_stmtod_stmt

Definition at line 1477 of file unspaghettify.c.

1478 {
1481 
1483 }
void unspaghettify_or_restructure_statement(statement mod_stmt)
The entry point common to unspaghettify or restructure a module:
static bool currently_apply_recursive_decomposition
Definition: unspaghettify.c:64

References currently_apply_recursive_decomposition, currently_apply_test_restructuring, and unspaghettify_or_restructure_statement().

Referenced by restructure_control().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ restructure_this_test()

static void restructure_this_test ( control  c,
structured_test_type  t 
)
static

print_statement(the_test_statement);

Find the exit node of the test:

Discard and unlink the then_node and else_node if any:

Now rebuild a structured test in the node c from the previous test branch contents:

print_statement(then_statement);

print_statement(else_statement);

Replace the useless CONTINUE by a NOP to improve the prettyprinted code:

Remove one of the 2 branches, since it is symetrical. In fact, since unlink_2_control_nodes() removes all the redundant branches, need to relink later:

Relink the structured test node to the successor since both pathes have been removed:

In the other case, the remaining link is just what needed.

print_statement(the_test_statement);

Definition at line 836 of file unspaghettify.c.

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 }
#define make_empty_statement
An alias for make_empty_block_statement.
#define test_false(x)
Definition: ri.h:2837
#define test_true(x)
Definition: ri.h:2835

References CAR, CDR, CONTROL, control_statement, control_successors, discard_a_control_sequence_without_its_statements(), free_statement(), ifdebug, instruction_test, link_2_control_nodes(), make_empty_statement, pips_assert, pips_debug, statement_consistent_p(), statement_instruction, STRUCTURED_IF_ELSE, STRUCTURED_IF_THEN, STRUCTURED_IF_THEN_ELSE, STRUCTURED_NULL_IF, test_false, test_true, and unlink_2_control_nodes().

Referenced by restructure_if_then_else().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ simple_restructure_statement()

void simple_restructure_statement ( statement  mod_stmt)

A simple cleaning of the control graph without major topological restructuring.

Used by example by PHRASE.

Parameters
mod_stmtod_stmt

Definition at line 1435 of file unspaghettify.c.

1436 {
1439 
1441 }

References currently_apply_recursive_decomposition, currently_apply_test_restructuring, and unspaghettify_or_restructure_statement().

Referenced by full_spaghettify(), identify_statements_to_distribute(), and safescale_distributor().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ take_out_the_entry_node_of_the_unstructured()

static bool take_out_the_entry_node_of_the_unstructured ( statement  s,
statement new_unstructured_statement 
)
static

Take the entry node out of the unstructured if it is not useful, such as not an IF or a node without predecessor.

Return true if there is still an unstructured, false if the unstructured has been replaced by a structured statement.

If the first node is taked out, then * new_unstructured_statement returns the new statement that own the unstructured, else s.

Well, this node is useful here since it is an unstructured IF or there is a GOTO on it.

In fact the unstructured has only one control node! Transform it in a structured block of statements:

Since the unstructured may have a comment on it, we cannot put the comment on the statement block but on a CONTINUE:

Remove the unstructured:

No longer unstructured:

Take out the entry node:

The entry node is now the second node:

Definition at line 495 of file unspaghettify.c.

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 }
void free_instruction(instruction p)
Definition: ri.c:1118
bool unlabelled_statement_p(statement)
Definition: statement.c:402
bool statement_with_empty_comment_p(statement)
Return true if the statement has an empty statement:
Definition: statement.c:126
#define empty_comments
Empty comments (i.e.
#define statement_label(x)
Definition: ri.h:2450
#define statement_comments(x)
Definition: ri.h:2456

References CAR, CONS, CONTROL, control_predecessors, control_statement, control_successors, discard_a_control_sequence_without_its_statements(), empty_comments, entity_empty_label(), free_instruction(), gen_length(), instruction_to_statement(), instruction_unstructured, make_continue_statement(), make_instruction_block(), NIL, pips_assert, STATEMENT, statement_comments, statement_instruction, statement_label, statement_undefined, statement_with_empty_comment_p(), unlabelled_statement_p(), and unstructured_control.

Referenced by recursively_restructure_an_unstructured().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ take_out_the_exit_node_if_not_a_continue()

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.

Parameters
sis the statement that contains an unstructured
Returns
the new restructured statement

The exit node is the landing pad of the control graph. But if it is not a continue, that means that its statement is a useful instruction at the end of the unstructured and we can take it out of the unstructured. We just return the statement directly containing the unstructured.

Right now, it does not extract a RETURN since as explained in ᅵ PIPS: Internal Representation of Fortran and C Code ᅵ about RETURN_LABEL_NAME in the Entities section, since a RETURN with a label at the exit of un unstructured is always the representation of a RETURN in Fortran unstructured code... So even for C code, a return stay inside an unstructured. RK does not think it is important anyway...

To return and keep track of the unstructured:

ifdebug(5) {

pips_debug(5,

"Statement at entry:\n");

print_statement(s);

}

First, linearize the exit statement since fuse_sequences_in_unstructured() may have gathered many statements in a messy way:

Then normalize to have only one non-sequence statement as the exit node:

Well, this should be always true if the sequence survived to clean_up_sequences_rewrite()...

Then, append the last statements at the end of the unstructured:

...followed by the last statements:

Fix the variables for the following pass:

Here the_exit_statement is not a sequence.

Put an empty exit node and keep the statement for the label:

Replace the unstructured by an unstructured followed by the out-keeped instruction:

Keep track of the statement number:

Heavily rely on a later clean_up_sequences to normalize the above...

Definition at line 734 of file unspaghettify.c.

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 }
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():
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
bool nop_statement_p(statement)
Definition: statement.c:407
bool return_statement_p(statement)
Test if a statement is a C or Fortran "return".
Definition: statement.c:172
#define instruction_sequence_p(x)
Definition: ri.h:1512
#define sequence_statements(x)
Definition: ri.h:2360
#define instruction_sequence(x)
Definition: ri.h:1514
return(s1)

References CAR, CDR, clean_up_sequences_internal(), CONS, control_statement, empty_statement_or_continue_p(), gen_free_list(), gen_length(), ifdebug, instruction_sequence, instruction_sequence_p, instruction_to_statement(), instruction_unstructured, instruction_unstructured_p, make_continue_instruction(), make_instruction_block(), NIL, nop_statement_p(), pips_assert, return_statement_p(), sequence_statements, STATEMENT, statement_consistent_p(), statement_instruction, statement_number, and unstructured_exit.

Referenced by recursively_restructure_an_unstructured().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ total_number_of_restructurations()

static int total_number_of_restructurations ( )
static

◆ unspaghettify()

bool unspaghettify ( const string  mod_name)

Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code.

Try to structure a little bit more and so on according to some properties.

Unspaguettify is now targetted to be included in the controlizer.

Get the true resource, not a copy.

Reorder the module, because new statements may have been changed.

Parameters
mod_nameod_name

Definition at line 1450 of file unspaghettify.c.

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 }
void unspaghettify_statement(statement mod_stmt)
The real entry point of unspaghettify:

References db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, local_name_to_top_level_entity(), module_reorder(), reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), strdup(), and unspaghettify_statement().

+ Here is the call graph for this function:

◆ unspaghettify_or_restructure_statement()

void unspaghettify_or_restructure_statement ( statement  mod_stmt)

The entry point common to unspaghettify or restructure a module:

Track the number of restructurations done for a fix point:

To track the number of restructuring iterations:

ifdebug(5) {

pips_debug(5, "Statement before unspaghettify_or_restructure_statement:\n");

print_statement(mod_stmt);

}

Split the recursion in three parts to fit in my brain:

First, clean up easy things done by the controlizer:

Then try to hierarchize the control flow:

Now apply some local rule, such as if/then/else restructuring and so on:

End by removing parasitic sequences:

If something changed, retry further restructuring:

ifdebug(5) {

pips_debug(5, "Statement after unspaghettify_or_restructure_statement:\n");

print_statement(mod_stmt);

}

Parameters
mod_stmtod_stmt

Definition at line 1330 of file unspaghettify.c.

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 }
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
void control_graph_recursive_decomposition(unstructured)
hierarchize.c
Definition: hierarchize.c:563
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
void put_formats_at_module_beginning(statement)
Transfer all the FORMATs at the very beginning of a module:
Definition: statement.c:2311
void put_formats_at_module_end(statement)
Transfer all the FORMATs at the very end of a module:
Definition: statement.c:2328
#define debug_on(env)
Definition: misc-local.h:157
#define pips_user_warning
Definition: misc-local.h:146
#define debug_off()
Definition: misc-local.h:160
#define unstructured_domain
newgen_type_domain_defined
Definition: ri.h:442
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
else
Definition: set.c:239
static void display_unspaghettify_statistics()
Definition: unspaghettify.c:99
static void initialize_unspaghettify_statistics()
Definition: unspaghettify.c:76
static void recover_structured_while(unstructured u)
Try to recover structured while loops in an already recursively restructured control graph.
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...

References clean_up_control(), clean_up_sequences(), control_graph_recursive_decomposition(), currently_apply_recursive_decomposition, debug_off, debug_on, display_unspaghettify_statistics(), gen_recurse, gen_true(), get_bool_property(), ifdebug, initialize_unspaghettify_statistics(), N_ITER_RESTRUCTURE_FIX_POINT, pips_assert, pips_debug, pips_user_warning, put_formats_at_module_beginning(), put_formats_at_module_end(), recover_structured_while(), recursively_restructure_an_unstructured(), statement_consistent_p(), statement_domain, total_number_of_restructurations(), and unstructured_domain.

Referenced by restructure_statement(), simple_restructure_statement(), and unspaghettify_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ unspaghettify_statement()

void unspaghettify_statement ( statement  mod_stmt)

The real entry point of unspaghettify:

Parameters
mod_stmtod_stmt

Definition at line 1421 of file unspaghettify.c.

1422 {
1424  get_bool_property("UNSPAGHETTIFY_TEST_RESTRUCTURING");
1426  get_bool_property("UNSPAGHETTIFY_RECURSIVE_DECOMPOSITION");
1427 
1429 }

Referenced by unspaghettify().

+ Here is the caller graph for this function:

Variable Documentation

◆ currently_apply_recursive_decomposition

bool currently_apply_recursive_decomposition
static

◆ currently_apply_test_restructuring

◆ number_of_recovered_do_while

◆ number_of_recovered_while

◆ number_of_restructured_if_else

◆ number_of_restructured_if_then

int number_of_restructured_if_then
static

To print some statistics about control graph restructuration:

Definition at line 67 of file unspaghettify.c.

Referenced by display_unspaghettify_statistics(), initialize_unspaghettify_statistics(), restructure_if_then_else(), and total_number_of_restructurations().

◆ number_of_restructured_if_then_else

int number_of_restructured_if_then_else
static

◆ number_of_restructured_null_if

◆ vcid_unspaghettify

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."

Ronan Keryell, 1995.

unspaghettify.c

Definition at line 30 of file unspaghettify.c.