PIPS
hierarchize.c File Reference
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "linear.h"
#include "genC.h"
#include "ri.h"
#include "interval_graph.h"
#include "graph.h"
#include "ri-util.h"
#include "misc.h"
#include "control.h"
+ Include dependency graph for hierarchize.c:

Go to the source code of this file.

Macros

#define vertex_predecessors   vertex_successors
 
#define predecessor_vertex   successor_vertex
 
#define make_predecessor   make_successor
 
#define free_predecessor   free_successor
 
#define PREDECESSOR   SUCCESSOR
 
#define PREDECESSOR_TYPE   SUCCESSOR_TYPE
 
#define PREDECESSOR_NEWGEN_DOMAIN   (-1)
 
#define SUCCESSOR_NEWGEN_DOMAIN   (-1)
 
#define gen_SUCCESSOR_cons   gen_cons
 
#define gen_PREDECESSOR_cons   gen_cons
 
#define gen_successor_cons   gen_cons
 
#define gen_predecessor_cons   gen_cons
 

Typedefs

typedef interval_vertex_label vertex_label
 Instantiation of the interval graph: More...
 
typedef interval_vertex_label arc_label
 Since the arc are not used, just put a dummy type for arc_label. More...
 
typedef successor predecessor
 

Functions

static void remove_interval_predecessors (vertex interval)
 Remove all the predecessors of an interval: More...
 
static bool remove_interval_predecessor (vertex interval, vertex pred)
 Remove all the instances of a predecessor pred of an interval. More...
 
static void add_node_to_interval (graph intervals, vertex interval, vertex node)
 Add an interval node to an interval and remove the node. More...
 
static void __attribute__ ((unused))
 Add the interval from (node, intervals) to interval graph intervals and update selected_nodes accordingly if : More...
 
static void display_interval_graph (graph intervals)
 
static bool interval_graph (graph intervals)
 Build an interval graph from an older interval graph and put it in the older one. More...
 
static vertex create_or_get_an_interval_node (control c, graph intervals, hash_table control_to_interval_node)
 Get the interval node of a control or create it if it does not exist and add it to the interval graph. More...
 
static graph control_graph_to_interval_graph_format (control entry_node)
 Duplicate the control graph in a format suitable to deal with intervals later. More...
 
static list interval_exit_nodes (vertex interval, control exit_node)
 Return the list of control nodes exiting an interval. More...
 
static void hierarchize_control_list (vertex interval, list controls, control exit_node)
 Put all the controls in their own unstructured to hierarchize the graph and link the unstructured to the outer unstructured. More...
 
void control_graph_recursive_decomposition (unstructured u)
 Use an interval graph partitionning method to recursively decompose the control graph. More...
 

Macro Definition Documentation

◆ free_predecessor

#define free_predecessor   free_successor

Definition at line 70 of file hierarchize.c.

◆ gen_PREDECESSOR_cons

#define gen_PREDECESSOR_cons   gen_cons

Definition at line 79 of file hierarchize.c.

◆ gen_predecessor_cons

#define gen_predecessor_cons   gen_cons

Definition at line 81 of file hierarchize.c.

◆ gen_SUCCESSOR_cons

#define gen_SUCCESSOR_cons   gen_cons

Definition at line 78 of file hierarchize.c.

◆ gen_successor_cons

#define gen_successor_cons   gen_cons

Definition at line 80 of file hierarchize.c.

◆ make_predecessor

#define make_predecessor   make_successor

Definition at line 69 of file hierarchize.c.

◆ PREDECESSOR

#define PREDECESSOR   SUCCESSOR

Definition at line 71 of file hierarchize.c.

◆ PREDECESSOR_NEWGEN_DOMAIN

#define PREDECESSOR_NEWGEN_DOMAIN   (-1)

Definition at line 74 of file hierarchize.c.

◆ PREDECESSOR_TYPE

#define PREDECESSOR_TYPE   SUCCESSOR_TYPE

Definition at line 72 of file hierarchize.c.

◆ predecessor_vertex

#define predecessor_vertex   successor_vertex

Definition at line 68 of file hierarchize.c.

◆ SUCCESSOR_NEWGEN_DOMAIN

#define SUCCESSOR_NEWGEN_DOMAIN   (-1)

Definition at line 76 of file hierarchize.c.

◆ vertex_predecessors

#define vertex_predecessors   vertex_successors

Definition at line 67 of file hierarchize.c.

Typedef Documentation

◆ arc_label

Since the arc are not used, just put a dummy type for arc_label.

It will be initialized to interval_vertex_label_undefined anyway:

Definition at line 51 of file hierarchize.c.

◆ predecessor

Definition at line 82 of file hierarchize.c.

◆ vertex_label

Instantiation of the interval graph:

Definition at line 48 of file hierarchize.c.

Function Documentation

◆ __attribute__()

static void __attribute__ ( (unused)  )
static

Add the interval from (node, intervals) to interval graph intervals and update selected_nodes accordingly if :

Since we modify in place the current interval graph, do not perturbate the do/MAP loop on intervals below. Just keep the list of interval to be removed later.

The new interval will be the node itself, begin of the new interval. Just select it and keep it:

Find a candidate through all the intervals:

Test that the candidate has all its predecessors in the interval we are building:

Ok, this node belong to the new interval:

add_node_to_interval(candidate, node, intervals, selected_nodes, &intervals_to_be_removed);

Look for the next appliant:

Definition at line 181 of file hierarchize.c.

185 {
186  bool a_node_has_been_added;
187  /* Since we modify in place the current interval graph, do not
188  perturbate the do/MAP loop on intervals below. Just keep the
189  list of interval to be removed later. */
190  list intervals_to_be_removed = NIL;
191  /* The new interval will be the node itself, begin of the new
192  interval. Just select it and keep it: */
193  set_add_element(selected_nodes, selected_nodes, (char *) node);
194 
195  do {
196  a_node_has_been_added = false;
197  /* Find a candidate through all the intervals: */
198  MAP(VERTEX, candidate, {
199  if (!set_belong_p(selected_nodes, (char *) candidate)) {
200  bool all_predecessors_are_in_current_interval = true;
201  /* Test that the candidate has all its predecessors in
202  the interval we are building: */
205  all_predecessors_are_in_current_interval = false;
206  break;
207  }
208  }, vertex_predecessors(candidate));
209  if (all_predecessors_are_in_current_interval) {
210  /* Ok, this node belong to the new interval: */
211  /* add_node_to_interval(candidate,
212  node,
213  intervals,
214  selected_nodes,
215  &intervals_to_be_removed);*/
216  /* Look for the next appliant: */
217  a_node_has_been_added = true;
218  break;
219  }
220  }
221  }, graph_vertices(intervals));
222  } while(a_node_has_been_added);
223 
224  gen_full_free_list(intervals_to_be_removed);
225 }
static void node(FILE *out, string name)
Build for module name a node and link to its successors.
Definition: graph.c:56
void gen_full_free_list(list l)
Definition: genClib.c:1023
#define graph_vertices(x)
Definition: graph.h:82
#define VERTEX(x)
VERTEX.
Definition: graph.h:122
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#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
#define PREDECESSOR
Definition: hierarchize.c:71
#define predecessor_vertex
Definition: hierarchize.c:68
#define vertex_predecessors
Definition: hierarchize.c:67
bool set_belong_p(const set, const void *)
Definition: set.c:194
set set_add_element(set, const set, const void *)
Definition: set.c:152
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

References gen_full_free_list(), graph_vertices, MAP, NIL, node(), PREDECESSOR, predecessor_vertex, set_add_element(), set_belong_p(), VERTEX, and vertex_predecessors.

+ Here is the call graph for this function:

◆ add_node_to_interval()

static void add_node_to_interval ( graph  intervals,
vertex  interval,
vertex  node 
)
static

Add an interval node to an interval and remove the node.

Replace every allusion to node by interval in the interval graph.

The main issue is that the interval graph must remain a graph, that is it cannot have more than one edge from a vertex to another one:

There is at least an interval that must appear ONLY ONCE in the predecessors. Thus it is easier to delete any reference an create an unique instance of it:

I guess there is memory leak here...

Add the lacking interval in the predecessors:

Concatenate the control nodes to the interval and preserve the order to keep the entry node first:

Protect the control nodes from later deletion (useless to free the list since it is still lived via gen_nconc. Thanks to Purify... :-)

Detach the node:

Clean up the useless old node:

Definition at line 128 of file hierarchize.c.

131 {
132  /* Replace every allusion to node by interval in the interval
133  graph.
134 
135  The main issue is that the interval graph must remain a graph, that
136  is it cannot have more than one edge from a vertex to another one: */
137  MAP(VERTEX, v, {
138  list predecessors_to_change = NIL;
139  bool interval_already_in_predecessors = false;
140  MAPL(ip, {
141  if (predecessor_vertex(PREDECESSOR(CAR(ip))) == node)
142  predecessors_to_change = CONS(PREDECESSOR,
143  PREDECESSOR(CAR(ip)),
144  predecessors_to_change);
145  if (predecessor_vertex(PREDECESSOR(CAR(ip))) == interval)
146  interval_already_in_predecessors = true;
147  }, vertex_predecessors(v));
148  if (predecessors_to_change != NIL) {
149  /* There is at least an interval that must appear ONLY ONCE in
150  the predecessors. Thus it is easier to delete any reference
151  an create an unique instance of it: */
152  /* I guess there is memory leak here... */
153  gen_list_and_not(&vertex_predecessors(v), predecessors_to_change);
154  if (! interval_already_in_predecessors)
155  /* Add the lacking interval in the predecessors: */
159  }
160  }, graph_vertices(intervals));
161 
162  /* Concatenate the control nodes to the interval and preserve the
163  order to keep the entry node first: */
167  /* Protect the control nodes from later deletion (useless to free
168  the list since it is still lived via gen_nconc. Thanks to
169  Purify... :-) */
171  /* Detach the node: */
173  /* Clean up the useless old node: */
174  gen_remove(&graph_vertices(intervals), node);
175  free_vertex(node);
176 }
void free_vertex(vertex p)
Definition: graph.c:107
#define vertex_vertex_label(x)
Definition: graph.h:152
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
#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 MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
static void remove_interval_predecessors(vertex interval)
Remove all the predecessors of an interval:
Definition: hierarchize.c:87
#define make_predecessor
Definition: hierarchize.c:69
#define interval_vertex_label_controls(x)
#define interval_vertex_label_undefined

References CAR, CONS, free_vertex(), gen_list_and_not(), gen_nconc(), gen_remove(), graph_vertices, interval_vertex_label_controls, interval_vertex_label_undefined, make_predecessor, MAP, MAPL, NIL, node(), PREDECESSOR, predecessor_vertex, remove_interval_predecessors(), VERTEX, vertex_predecessors, and vertex_vertex_label.

Referenced by interval_graph().

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

◆ control_graph_recursive_decomposition()

void control_graph_recursive_decomposition ( unstructured  u)

Use an interval graph partitionning method to recursively decompose the control graph.

hierarchize.c

Have a look to paper "A Control-Flow Normalization Algorithm and Its Complexity" (1994) from Zahira Ammarguellat for a bibliography of the domain.

An interval graph is represented by a graph with interval_vertex_label decorations embedding control nodes. The first interval of the graph is the entry interval of the interval graph and the first control node of an interval is the entry control node of the interval:

The seed interval graph is indeed the control graph itself:

Apply recursively interval graph decomposition:

For all intervals of the graph:

If this interval has at most one exit it should be put in its own unstructured:

Useless to restructure the exit node...

If a single node, only useful if there is a loop inside (in order to detect these loops, hierarchize_control_list() is called before interval_graph() but then we need to add more guards...):

If an interval has at most one exit, the underlaying control graph can be hierachized by an unstructured.

Put all the controls in their own unstructured to hierarchize the graph:

Skip the entry interval

Stop if the interval graph does no longer change : it is only one node or an irreductible graph:

Construct the interval graph from the previous one:

Do not forget to detach control nodes from interval before sweeping:

Definition at line 563 of file hierarchize.c.

564 {
565  /* An interval graph is represented by a graph with
566  interval_vertex_label decorations embedding control nodes. The
567  first interval of the graph is the entry interval of the
568  interval graph and the first control node of an interval is the
569  entry control node of the interval: */
570  bool modified;
571  control entry_node, exit_node;
572  graph intervals;
573 
574  debug_on("RECURSIVE_DECOMPOSITION_DEBUG_LEVEL");
575 
576  entry_node = unstructured_control(u);
577  exit_node = unstructured_exit(u);
578 
579  /* The seed interval graph is indeed the control graph itself: */
580  intervals = control_graph_to_interval_graph_format(entry_node);
581 
582  pips_debug(3, "Entering with unstructured %p (%p, %p)\n",
583  u, entry_node, exit_node);
584  ifdebug(5) {
585  pips_debug(5, "Nodes from entry_node: ");
586  display_linked_control_nodes(entry_node);
587  pips_debug(5, "\nNodes from exit_node: ");
588  display_linked_control_nodes(exit_node);
589  }
590  ifdebug(6)
591  display_interval_graph(intervals);
592 
593  /* Apply recursively interval graph decomposition: */
594  do {
595  /* For all intervals of the graph: */
596  MAP(VERTEX, interval, {
598  control interval_entry = CONTROL(CAR(controls));
599  list interval_exits = interval_exit_nodes(interval, exit_node);
600  if (/* If this interval has at most one exit it should be put
601  in its own unstructured: */
602  gen_length(interval_exits) <= 1
603  && /* Useless to restructure the exit node... */
604  interval_entry != exit_node
605  && /* If a single node, only useful if there is a loop
606  inside (in order to detect these loops,
607  hierarchize_control_list() is called before
608  interval_graph() but then we need to add more
609  guards...): */
610  (gen_length(controls) > 1
611  || (gen_length(control_successors(interval_entry)) == 2
612  && (CONTROL(CAR(control_successors(interval_entry))) == interval_entry
613  || CONTROL(CAR(CDR(control_successors(interval_entry)))) == interval_entry)))
614  ) {
615  /* If an interval has at most one exit, the
616  underlaying control graph can be hierachized by an
617  unstructured. */
618  /* Put all the controls in their own unstructured
619  to hierarchize the graph: */
620  hierarchize_control_list(interval,
621  controls,
622  interval_exits == NIL ? control_undefined : CONTROL(CAR(interval_exits)));
623 
624  gen_free_list(interval_exits);
625  }
626  }, CDR(graph_vertices(intervals)) /* Skip the entry interval */);
627  /* Stop if the interval graph does no longer change : it is
628  only one node or an irreductible graph: */
629  /* Construct the interval graph from the previous one: */
630  modified = interval_graph(intervals);
631  pips_debug(6, "Modified = %d\n", modified);
632  ifdebug(6)
633  display_interval_graph(intervals);
634  } while (modified);
635 
636 
637  /* Do not forget to detach control nodes from interval before
638  sweeping: */
639  MAP(VERTEX, v, {
642  }, graph_vertices(intervals));
643  free_graph(intervals);
644 
645  pips_debug(3, "Exiting.\n");
646  ifdebug(5) {
647  pips_debug(5, "Nodes from entry_node: ");
648  display_linked_control_nodes(entry_node);
649  pips_debug(5, "\nNodes from exit_node: ");
650  display_linked_control_nodes(exit_node);
651  }
652  ifdebug(1)
653  pips_assert("Unstructured should be consistent here...",
655  debug_off();
656 }
void free_graph(graph p)
Definition: graph.c:23
bool unstructured_consistent_p(unstructured p)
Definition: ri.c:2751
void display_linked_control_nodes(control c)
Display all the control nodes reached or reachable from c for debugging purpose.
Definition: control.c:629
size_t gen_length(const list l)
Definition: list.c:150
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
static void hierarchize_control_list(vertex interval, list controls, control exit_node)
Put all the controls in their own unstructured to hierarchize the graph and link the unstructured to ...
Definition: hierarchize.c:428
static list interval_exit_nodes(vertex interval, control exit_node)
Return the list of control nodes exiting an interval.
Definition: hierarchize.c:384
static void display_interval_graph(graph intervals)
Definition: hierarchize.c:229
static bool interval_graph(graph intervals)
Build an interval graph from an older interval graph and put it in the older one.
Definition: hierarchize.c:261
static graph control_graph_to_interval_graph_format(control entry_node)
Duplicate the control graph in a format suitable to deal with intervals later.
Definition: hierarchize.c:335
#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_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define debug_off()
Definition: misc-local.h:160
#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(x)
CONTROL.
Definition: ri.h:910
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define ifdebug(n)
Definition: sg.c:47

References CAR, CDR, CONTROL, control_graph_to_interval_graph_format(), control_successors, control_undefined, debug_off, debug_on, display_interval_graph(), display_linked_control_nodes(), free_graph(), gen_free_list(), gen_length(), graph_vertices, hierarchize_control_list(), ifdebug, interval_exit_nodes(), interval_graph(), interval_vertex_label_controls, MAP, NIL, pips_assert, pips_debug, unstructured_consistent_p(), unstructured_control, unstructured_exit, VERTEX, and vertex_vertex_label.

Referenced by unspaghettify_or_restructure_statement().

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

◆ control_graph_to_interval_graph_format()

static graph control_graph_to_interval_graph_format ( control  entry_node)
static

Duplicate the control graph in a format suitable to deal with intervals later.

The interval graph format is the predecessor control graph in fact.

Add the predeccessor only if it is not already in the predecessor list:

Definition at line 335 of file hierarchize.c.

336 {
337  list blocs = NIL;
338  graph intervals = make_graph(NIL);
339 
340  hash_table control_to_interval_node = hash_table_make(hash_pointer, 0);
341  pips_debug(5, "Control entry node %p:\n", entry_node);
342  CONTROL_MAP(c, {
343  vertex interval =
345  intervals,
346  control_to_interval_node);
347  pips_debug(6, "\tControl %p -> interval %p\n", c, interval);
348  MAP(CONTROL, p, {
349  bool interval_already_in_predecessors = false;
350  vertex vertex_predecessor =
352  intervals,
353  control_to_interval_node);
354  /* Add the predeccessor only if it is not already in the
355  predecessor list: */
356  MAPL(ip, {
357  if (predecessor_vertex(PREDECESSOR(CAR(ip))) == vertex_predecessor) {
358  interval_already_in_predecessors = true;
359  break;
360  }
361  }, vertex_predecessors(interval));
362  if (! interval_already_in_predecessors) {
364  vertex_predecessor);
365  vertex_predecessors(interval) =
366  CONS(PREDECESSOR, v_p, vertex_predecessors(interval));
367  }
368  pips_debug(7, "\t\tControl predecessor %p -> interval %p\n",
369  p, vertex_predecessor);
370  }, control_predecessors(c));
371  }, entry_node, blocs);
372  gen_free_list(blocs);
373 
374  hash_table_free(control_to_interval_node);
375 
376  return intervals;
377 }
graph make_graph(list a)
Definition: graph.c:56
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
static vertex create_or_get_an_interval_node(control c, graph intervals, hash_table control_to_interval_node)
Get the interval node of a control or create it if it does not exist and add it to the interval graph...
Definition: hierarchize.c:305
@ hash_pointer
Definition: newgen_hash.h:32
#define control_predecessors(x)
Definition: ri.h:943

References CAR, CONS, CONTROL, CONTROL_MAP, control_predecessors, create_or_get_an_interval_node(), gen_free_list(), hash_pointer, hash_table_free(), hash_table_make(), interval_vertex_label_undefined, make_graph(), make_predecessor, MAP, MAPL, NIL, pips_debug, PREDECESSOR, predecessor_vertex, and vertex_predecessors.

Referenced by control_graph_recursive_decomposition().

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

◆ create_or_get_an_interval_node()

static vertex create_or_get_an_interval_node ( control  c,
graph  intervals,
hash_table  control_to_interval_node 
)
static

Get the interval node of a control or create it if it does not exist and add it to the interval graph.

This control has never been seen before: allocate the peering interval node with no successor:

Use gen_nconc since the entry interval must be the first one:

Definition at line 305 of file hierarchize.c.

308 {
309  vertex interval;
310  if (!hash_defined_p(control_to_interval_node, (char *) c)) {
311  /* This control has never been seen before: allocate the
312  peering interval node with no successor: */
313  interval =
315  NIL);
316  /* Use gen_nconc since the entry interval must be the first
317  one: */
318  graph_vertices(intervals) = gen_nconc(graph_vertices(intervals),
319  CONS(VERTEX, interval, NIL));
320  hash_put(control_to_interval_node, (char *) c, (char *) interval);
321  }
322  else
323  interval = (vertex) hash_get(control_to_interval_node, (char *) c);
324 
325  return interval;
326 }
vertex make_vertex(vertex_label a1, list a2)
Definition: graph.c:140
interval_vertex_label make_interval_vertex_label(list a)
struct _newgen_struct_vertex_ * vertex
Definition: dg.h:28
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
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484

References CONS, CONTROL, gen_nconc(), graph_vertices, hash_defined_p(), hash_get(), hash_put(), make_interval_vertex_label(), make_vertex(), NIL, and VERTEX.

Referenced by control_graph_to_interval_graph_format().

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

◆ display_interval_graph()

static void display_interval_graph ( graph  intervals)
static

Definition at line 229 of file hierarchize.c.

230 {
231  MAP(VERTEX, node, {
232  pips_debug(0, "Interval %p, control nodes:\n", node);
234  pips_debug(0, "Interval predecessors:\n");
235  MAP(SUCCESSOR, p, {
236  pips_debug(0, "\t%p\n", predecessor_vertex(p));
238  }, graph_vertices(intervals));
239 }
#define SUCCESSOR(x)
SUCCESSOR.
Definition: graph.h:86
void display_address_of_control_nodes(list cs)
Display the adresses a list of control nodes.
Definition: control.c:612

References display_address_of_control_nodes(), graph_vertices, interval_vertex_label_controls, MAP, node(), pips_debug, predecessor_vertex, SUCCESSOR, VERTEX, vertex_predecessors, and vertex_vertex_label.

Referenced by control_graph_recursive_decomposition().

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

◆ hierarchize_control_list()

static void hierarchize_control_list ( vertex  interval,
list  controls,
control  exit_node 
)
static

Put all the controls in their own unstructured to hierarchize the graph and link the unstructured to the outer unstructured.

The exit_node is the exit control node, either control_undefined if it there is no exit : it is a true endless loop (assume it is not the exit node).

The list of all reachable controls of the new unstructured:

Create the new control nodes with the new unstructured:

Now the hard work: replace carefully the old control nodes by new one in the spaghetti plate...

First clone the graph structure:

Add the new_exit_node in the new_controls list:

Correct the nodes to reflect the new nodes:

Detach the new unstructured from the old one:

If there was a goto from exit_node to entry_node, there is an artefact one between new_exit_node and new_entry_node. Remove it:

Detach the old unstructured from the new one:

Unlink an eventual loop around entry_node that has been captured anyway in the new unstructured:

When a single node loop has been hierarchize, this link already exist

Now the exit_node becomes a successor of the entry_node:

Update the control list of the interval that owns only entry_node after hierarchization:

ifdebug(7)

print_statement(control_statement(entry_node));

Definition at line 428 of file hierarchize.c.

431 {
432  /* The list of all reachable controls of the new unstructured: */
433  list new_controls = gen_copy_seq(controls);
434 
435  control entry_node = CONTROL(CAR(controls));
436  /* Create the new control nodes with the new unstructured: */
437  control new_entry_node = make_control(control_statement(entry_node),
438  NIL, NIL);
439  control new_exit_node = make_control(make_nop_statement(),
440  NIL, NIL);
441  unstructured new_unstructured = make_unstructured(new_entry_node,
442  new_exit_node);
443  control_statement(entry_node) =
445  new_unstructured));
446  ifdebug(6) {
447  pips_debug(6, "List of controls: ");
449  if (exit_node != control_undefined) {
450  pips_debug(6, "\nExit node %p\n", exit_node);
451  }
452  pips_debug(6, "New unstructured %p: new_entry_node = %p, new_exit_node = %p\n",
453  new_unstructured, new_entry_node, new_exit_node);
454  }
455  /* Now the hard work: replace carefully the old control nodes by
456  new one in the spaghetti plate... */
457 
458  /* First clone the graph structure: */
459  control_successors(new_entry_node) =
460  gen_copy_seq(control_successors(entry_node));
461  control_predecessors(new_entry_node) =
462  gen_copy_seq(control_predecessors(entry_node));
463  control_list_patch(new_controls, entry_node, new_entry_node);
464  if (exit_node != control_undefined) {
465  control_successors(new_exit_node) =
466  gen_copy_seq(control_successors(exit_node));
467  control_predecessors(new_exit_node) =
469  /* Add the new_exit_node in the new_controls list: */
470  new_controls = CONS(CONTROL, new_exit_node, new_controls);
471  }
472  ifdebug(6) {
473  pips_debug(6, "new_controls list: ");
474  display_address_of_control_nodes(new_controls);
475  }
476 
477  /* Correct the nodes to reflect the new nodes: */
478  MAP(CONTROL, c, {
479  control_list_patch(control_successors(c), entry_node, new_entry_node);
480  control_list_patch(control_predecessors(c), entry_node, new_entry_node);
481  if (exit_node != control_undefined) {
482  control_list_patch(control_successors(c), exit_node, new_exit_node);
483  control_list_patch(control_predecessors(c), exit_node, new_exit_node);
484  }
485  }, new_controls);
486 
487  /* Detach the new unstructured from the old one: */
488  MAP(CONTROL, c, {
489  gen_list_and(&control_successors(c), new_controls);
490  gen_list_and(&control_predecessors(c), new_controls);
491  }, new_controls);
492 
493  /* If there was a goto from exit_node to entry_node, there is an
494  artefact one between new_exit_node and new_entry_node. Remove
495  it: */
496  unlink_2_control_nodes(new_exit_node, new_entry_node);
497 
498  /* Detach the old unstructured from the new one: */
499  gen_list_and_not(&control_successors(entry_node), new_controls);
500  gen_list_and_not(&control_predecessors(entry_node), new_controls);
501 
502  /* Unlink an eventual loop around entry_node that has been
503  captured anyway in the new unstructured: */
504  unlink_2_control_nodes(entry_node, entry_node);
505 
506  if (exit_node != control_undefined) {
507  gen_list_and_not(&control_successors(exit_node), new_controls);
508  gen_list_and_not(&control_predecessors(exit_node), new_controls);
509  }
510 
511  if (exit_node != control_undefined
512  && control_successors(entry_node) == NIL /* When a single node
513  loop has been hierarchize, this link already exist */
514  ) {
515  /* Now the exit_node becomes a successor of the entry_node: */
516  link_2_control_nodes(entry_node, exit_node);
517  }
518 
519  /* Update the control list of the interval that owns only
520  entry_node after hierarchization: */
523  CONS(CONTROL, entry_node, NIL);
524 
525  gen_free_list(new_controls);
526 
527  ifdebug(5) {
528  pips_debug(6, "Nodes from entry_node: ");
529  display_linked_control_nodes(entry_node);
530  if (exit_node != control_undefined) {
531  pips_debug(6, "\nNodes from exit_node: ");
532  display_linked_control_nodes(exit_node);
533  }
534  pips_debug(6, "\nNodes from new_entry_node: ");
535  display_linked_control_nodes(new_entry_node);
536  pips_debug(6, "\nNodes from new_exit_node: ");
537  display_linked_control_nodes(new_exit_node);
538  }
539  ifdebug(1) {
540  check_control_coherency(new_entry_node);
541  check_control_coherency(new_exit_node);
542  check_control_coherency(entry_node);
543  if (exit_node != control_undefined)
544  check_control_coherency(exit_node);
545  pips_assert("Control should be consistent from entry_node)...",
546  control_consistent_p(entry_node));
547  }
548  pips_assert("new_exit_node cannot have a successor.",
549  control_successors(new_exit_node) == NIL);
550  /* ifdebug(7) */
551  /* print_statement(control_statement(entry_node)); */
552 }
unstructured make_unstructured(control a1, control a2)
Definition: ri.c:2778
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
bool control_consistent_p(control p)
Definition: ri.c:496
control make_control(statement a1, list a2, list a3)
Definition: ri.c:523
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 link_2_control_nodes(control source, control target)
Add an edge between 2 control nodes.
Definition: control.c:1193
void control_list_patch(list l, control c_old, control c_new)
Replace in a list of control nodes all the instance of a control node by another one.
Definition: control.c:336
void check_control_coherency(control c)
Test the coherency of a control node network from a control node.
Definition: control.c:487
void gen_list_and(list *a, const list b)
Compute A = A inter B: complexity in O(n2)
Definition: list.c:941
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
#define make_nop_statement
An alias for make_empty_block_statement.
@ is_instruction_unstructured
Definition: ri.h:1475
#define control_statement(x)
Definition: ri.h:941

References CAR, check_control_coherency(), CONS, CONTROL, control_consistent_p(), control_list_patch(), control_predecessors, control_statement, control_successors, control_undefined, display_address_of_control_nodes(), display_linked_control_nodes(), gen_copy_seq(), gen_free_list(), gen_list_and(), gen_list_and_not(), ifdebug, instruction_to_statement(), interval_vertex_label_controls, is_instruction_unstructured, link_2_control_nodes(), make_control(), make_instruction(), make_nop_statement, make_unstructured(), MAP, NIL, pips_assert, pips_debug, unlink_2_control_nodes(), and vertex_vertex_label.

Referenced by control_graph_recursive_decomposition().

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

◆ interval_exit_nodes()

static list interval_exit_nodes ( vertex  interval,
control  exit_node 
)
static

Return the list of control nodes exiting an interval.

Note that if a node of the control list is in fact the exit_node of an unstructured, it is really an exit node at an upper level.

A successor that is not in the interval is an exit node... Add it to the exit nodes list if not already in it:

The current exit_node of the unstructured is clearly an exit node even if it does not have any successor:

Definition at line 384 of file hierarchize.c.

385 {
386  list exit_controls = NIL;
387 
388  pips_debug(6, "Interval %p with controls ", interval);
389  ifdebug(6)
391  MAP(CONTROL, c, {
392  pips_debug(7, "\n\tControl %p:\n", c);
393  MAP(CONTROL, successor, {
394  pips_debug(7, "\t\tControl successor %p:\n", successor);
397  /* A successor that is not in the interval is an exit
398  node... Add it to the exit nodes list if not
399  already in it: */
400  if (!gen_in_list_p(successor, exit_controls))
401  exit_controls = CONS(CONTROL, successor, exit_controls);
402  }
403  }, control_successors(c));
404 
405  if (c == exit_node)
406  /* The current exit_node of the unstructured is clearly an
407  exit node even if it does not have any successor: */
408  exit_controls = CONS(CONTROL, c, exit_controls);
410 
411  ifdebug(6) {
412  pips_debug(6, "Interval exit node list: ");
413  display_address_of_control_nodes(exit_controls);
414  pips_debug(6, "\n");
415  }
416 
417  return exit_controls;
418 }
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734

References CONS, CONTROL, control_successors, display_address_of_control_nodes(), gen_in_list_p(), ifdebug, interval_vertex_label_controls, MAP, NIL, pips_debug, and vertex_vertex_label.

Referenced by control_graph_recursive_decomposition().

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

◆ interval_graph()

static bool interval_graph ( graph  intervals)
static

Build an interval graph from an older interval graph and put it in the older one.

An interval is a subgraph whose header dominate all its nodes. It can be seen as a natural loop plus an acyclic structure that dangles from the nodes of that loop.

Algorithm use the T1/T2 analysis that can be found from pages 665 to 670 of:

@book{dragon-1986, author = {Alfred V. Aho and Ravi Sethi and Jeffrey D. Ullman}, title = {Compilers Principles, Techniques and Tools}, publisher = {Addison-Wesley Publishing Company}, year = 1986 }

It looks like it is from Hecht and Ullman according to Zahira Ammarguellat.

Apply the T2 transformation, that is equivalent to my fuse_sequences_in_unstructured elsewhere. Just use a less optimized algorithm here:

The entry interval is kept untouched

Fuse a node with its only predecessor:

Let's go to find a new interval to fuse:

T1 transformation on page 668: Remove the eventual arcs to itself:

If a loop around a interval node is removed, it considered as a graph modification:

Definition at line 261 of file hierarchize.c.

262 {
263  bool a_node_has_been_fused;
264  bool the_interval_graph_has_been_modified = false;
265  vertex entry_interval = VERTEX(CAR(graph_vertices(intervals)));
266 
267  /* Apply the T2 transformation, that is equivalent to my
268  fuse_sequences_in_unstructured elsewhere. Just use a less
269  optimized algorithm here: */
270  do {
271  a_node_has_been_fused = false;
272  MAP(VERTEX, node, {
273  pips_debug(8, "vertex %p.\n", node);
274  if (node != entry_interval
275  /* The entry interval is kept untouched */
276  && gen_length(vertex_predecessors(node)) == 1) {
277  /* Fuse a node with its only predecessor: */
279  pips_debug(8, "\tonly one vertex predecessor %p.\n", p_v);
280  add_node_to_interval(intervals, p_v, node);
281  /* Let's go to find a new interval to fuse: */
282  a_node_has_been_fused = true;
283  break;
284  }
285  }, graph_vertices(intervals));
286  the_interval_graph_has_been_modified |= a_node_has_been_fused;
287  } while (a_node_has_been_fused);
288 
289  /* T1 transformation on page 668: Remove the eventual arcs to
290  itself: */
291  MAP(VERTEX, node, {
292  /* If a loop around a interval node is removed, it considered
293  as a graph modification: */
294  the_interval_graph_has_been_modified
296  }, graph_vertices(intervals));
297 
298  return the_interval_graph_has_been_modified;
299 }
static bool remove_interval_predecessor(vertex interval, vertex pred)
Remove all the instances of a predecessor pred of an interval.
Definition: hierarchize.c:103
static void add_node_to_interval(graph intervals, vertex interval, vertex node)
Add an interval node to an interval and remove the node.
Definition: hierarchize.c:128

References add_node_to_interval(), CAR, gen_length(), graph_vertices, MAP, node(), pips_debug, PREDECESSOR, predecessor_vertex, remove_interval_predecessor(), VERTEX, and vertex_predecessors.

Referenced by control_graph_recursive_decomposition().

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

◆ remove_interval_predecessor()

static bool remove_interval_predecessor ( vertex  interval,
vertex  pred 
)
static

Remove all the instances of a predecessor pred of an interval.

Return true if pred was really in the predecessor list:

Detach the predecessor vertex:

And now remove the predecessors than own pred:

Definition at line 103 of file hierarchize.c.

105 {
106  bool pred_has_been_found_p = false;
107  list predecessors_to_remove = NIL;
108  /* Detach the predecessor vertex: */
109  MAP(PREDECESSOR, p, {
110  if (predecessor_vertex(p) == pred) {
112  predecessors_to_remove = CONS(PREDECESSOR, p, predecessors_to_remove);
113  pred_has_been_found_p = true;
114  }
115  }, vertex_predecessors(interval));
116  /* And now remove the predecessors than own pred: */
117  MAP(PREDECESSOR, p, {
118  gen_remove(&vertex_predecessors(interval), p);
119  free_predecessor(p);
120  }, predecessors_to_remove);
121 
122  return pred_has_been_found_p;
123 }
#define vertex_undefined
Definition: graph.h:128
#define free_predecessor
Definition: hierarchize.c:70

References CONS, free_predecessor, gen_remove(), MAP, NIL, PREDECESSOR, predecessor_vertex, vertex_predecessors, and vertex_undefined.

Referenced by interval_graph().

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

◆ remove_interval_predecessors()

static void remove_interval_predecessors ( vertex  interval)
static

Remove all the predecessors of an interval:

Detach the predecessor vertex:

And remove all the predecessors:

Definition at line 87 of file hierarchize.c.

88 {
89  /* Detach the predecessor vertex: */
90  MAP(PREDECESSOR, p, {
92  }, vertex_predecessors(interval));
93  /* And remove all the predecessors: */
95  vertex_predecessors(interval) = NIL;
96 }

References gen_full_free_list(), MAP, NIL, PREDECESSOR, predecessor_vertex, vertex_predecessors, and vertex_undefined.

Referenced by add_node_to_interval().

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