PIPS
bourdoncle.c File Reference
#include <stdio.h>
#include <strings.h>
#include "linear.h"
#include "genC.h"
#include "ri.h"
#include "ri-util.h"
#include "control.h"
#include "properties.h"
#include "pipsdbm.h"
#include "misc.h"
+ Include dependency graph for bourdoncle.c:

Go to the source code of this file.

Functions

static void reset_dfn (control c)
 
static void copy_dfn (control new_c, control old_c)
 
static _int get_dfn (control c)
 
static void update_dfn (control c, _int d)
 
static control make_meaningless_control (list preds, list succs)
 With non-deterministic graph, the outcome of a test may be known in advance. More...
 
bool meaningless_control_p (control c)
 Is exported to exploit non-deterministic control flow graphs. More...
 
static void free_meaningless_control (control c)
 
bool control_test_p (control c)
 Check that a node is used as a test in a CFG. More...
 
static void print_control_node_without_check (control)
 Code partly replicated from semantics/unstructured.c to be able to taylor it to the exact needs. More...
 
static bool check_control_statement (control c)
 
static void print_and_check_control_node (control c, bool check_p)
 
static void print_control_node_b (control c)
 
static void print_control_nodes_without_check (list l)
 Was moved into ri-util/control, minus the check_control_statement() More...
 
static void print_unstructured (unstructured u)
 
static void davinci_print_control_node (control c, FILE *f, bool entry_p, bool exit_p, bool fix_point_p)
 Output CFG in daVinci format. More...
 
static int control_cons_compare (list l1, list l2)
 
static void set_davinci_count ()
 
static void davinci_print_control_nodes (list l, string msg)
 
static void davinci_print_non_deterministic_unstructured (unstructured u, string msg, hash_table scc_map, hash_table ancestor_map)
 
void add_control_to_embedding_control_list (control c)
 
static void print_embedding_graph (control c, string msg)
 
static list node_to_linked_nodes (control c)
 Allocate a list of control nodes transitively linked to control c. More...
 
static int clean_up_control_test (control c)
 Take care of two problems: meaningless control nodes may end up shared by effective nodes and they may end up uselessly numerous. More...
 
static void clean_up_embedding_graph (control c)
 
static void print_control_to_control_mapping (string message, hash_table map)
 
static bool ancestor_control_p (hash_table ancestor_map, control c)
 Functions to deal with the ancestor_map. More...
 
control control_to_ancestor (control vertex, hash_table ancestor_map)
 If vertex is an ancestor control node from the input control graph, return vertex, else return its ancestor. More...
 
static bool registered_controls_p (hash_table ancestor_map, list l)
 
static bool ancestor_map_consistent_p (hash_table ancestor_map)
 No control can be an ancestor and a child. More...
 
static void add_child_parent_pair (hash_table ancestor_map, control child, control parent)
 
static void print_replicate_map ()
 
control control_shallow_copy (control c)
 
static void control_translate_arcs (control c)
 
static control control_to_replicate (control old_c)
 
unstructured unstructured_shallow_copy (unstructured u, hash_table ancestor_map)
 
unstructured partition_to_unstructured (control vertex, list partition)
 Build a new unstructured (CFG) for partition. More...
 
static bool entry_or_exit_control_p (control c, list partition, bool check_entry)
 
static bool entry_control_p (control c, list partition)
 
static bool exit_control_p (control c, list partition)
 
void intersect_successors_with_partition_or_complement (control c, list partition, bool complement_p)
 If complement_p, preserve successors in the complement of partition. More...
 
void intersect_successors_with_partition (control c, list partition)
 
void intersect_successors_with_partition_complement (control c, list partition)
 
static void __attribute__ ((unused))
 
static void update_successors_of_predecessor (control pred, control new_c, control old_c)
 new_c is not consistent on entry and might not be on exit because it is called from within a loop More...
 
static void update_predecessors_of_successor (control succ, control new_c, control old_c)
 
static void add_test_successor (control t, control new_s, bool is_true_successor)
 Called from within a loop where neither t nor new_s are consistent. More...
 
static void update_successor_in_copy (control new_pred, control pred, control c, control new_c)
 Make new_c a successor of new_pred, the same way c is a successor of pred. More...
 
static unstructured scc_to_dag (control root, list partition, hash_table ancestor_map)
 The nodes in scc partition but root must be removed. More...
 
static void replicate_cycles (unstructured u_main, hash_table scc_map, hash_table ancestor_map)
 
list bourdoncle_partition (unstructured u, unstructured *p_ndu, hash_table *p_ancestor_map, hash_table *p_scc_map)
 
static bool partition_successor_p (control b, control e, list partition)
 FUNCTIONS FOR BOURDONCLE_COMPONENT() More...
 
static void update_partition (control root, list partition, hash_table ancestor_map)
 
list bourdoncle_component (control vertex, hash_table ancestor_map, hash_table scc_map)
 
int bourdoncle_visit (control vertex, list *ppartition, hash_table ancestor_map, hash_table scc_map)
 
unstructured ancestor_cycle_head_to_scc (control a, hash_table scc_map)
 scc_map maps either the ancestor node to its scc if the transformers are computed without context, or the call site node to its scc if cycles are replicated to compute transformers within their context. More...
 
unstructured proper_cycle_head_to_scc (control h, hash_table scc_map)
 Retrieve a scc_u from its head. More...
 
bool cycle_head_p (control c, hash_table ancestor_map, hash_table scc_map)
 This node is a cycle call site. More...
 
bool proper_cycle_head_p (control c, hash_table scc_map)
 This node is really the head of a cycle (red on daVinci pictures). More...
 
bool direct_cycle_head_p (control c, hash_table scc_map)
 This node is directly associated to a specific cycle. More...
 
unstructured cycle_head_to_scc (control c, hash_table ancestor_map, hash_table scc_map)
 The ancestor of this node is associated to a specific cycle. More...
 
bool one_successor_kind_only_p (control c, bool true_p)
 useful for non-deterministic control flow graph only More...
 
bool true_successors_only_p (control c)
 
bool false_successors_only_p (control c)
 
static void suppress_statement_reference (control c)
 
static void bourdoncle_unstructured_free (unstructured u)
 
void bourdoncle_free (unstructured ndu, hash_table ancestor_map, hash_table scc_map)
 

Variables

static hash_table dfn = hash_table_undefined
 bourdoncle.c More...
 
static int num = 0
 
static int davinci_count = 0
 This counter is pre-incremented each time a new graph is stored to generate a new file name. More...
 
static list embedding_control_list = NIL
 
static hash_table replicate_map = hash_table_undefined
 Replication of unstructured (i.e. More...
 

Function Documentation

◆ __attribute__()

static void __attribute__ ( (unused)  )
static

Can we do without a extra-node?

Definition at line 1236 of file bourdoncle.c.

1241 {
1242  if(false) {
1243  /* Can we do without a extra-node? */
1244  }
1245  else{
1246  /* */
1248  control cnop = make_control(nop,
1249  CONS(CONTROL, pred, NIL),
1250  CONS(CONTROL, new_c, CONS(CONTROL, old_c, NIL)));
1251  pips_assert("succs points to old_c", CONTROL(CAR(succs))==old_c);
1252  pips_debug(2, "Allocate new control node %p as CONTINUE for test control node %p"
1253  " with two successors, a new one, %p, and an old one %p\n",
1254  cnop, pred, new_c, old_c);
1255  CONTROL_(CAR(succs)) = cnop;
1256  gen_list_patch(control_predecessors(old_c), pred, cnop);
1257  gen_list_patch(control_predecessors(new_c), pred, cnop);
1258  }
1259 }
control make_control(statement a1, list a2, list a3)
Definition: ri.c:523
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_list_patch(list l, const void *x, const void *y)
Replace all the reference to x in list l by a reference to y:
Definition: list.c:985
statement make_continue_statement(entity)
Definition: statement.c:953
#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
entity entity_empty_label(void)
Definition: entity.c:1105
#define CONTROL_(x)
Definition: ri.h:913
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROL(x)
CONTROL.
Definition: ri.h:910

References CAR, CONS, CONTROL, CONTROL_, control_predecessors, entity_empty_label(), gen_list_patch(), make_continue_statement(), make_control(), NIL, pips_assert, and pips_debug.

+ Here is the call graph for this function:

◆ add_child_parent_pair()

static void add_child_parent_pair ( hash_table  ancestor_map,
control  child,
control  parent 
)
static

The child will inherit the parent's ancestor, if any

The child should not already be in ancestor_map

The child cannot be an ancestor

Definition at line 934 of file bourdoncle.c.

937 {
938  control ancestor = control_undefined;
939 
940  /* The child will inherit the parent's ancestor, if any */
941  if((ancestor = (control) hash_get(ancestor_map, parent))==(control) HASH_UNDEFINED_VALUE) {
942  ancestor = parent;
943  }
944  ifdebug(2) {
945  /* The child should not already be in ancestor_map */
946  pips_assert("The child should not already be in ancestor_map",
947  hash_get(ancestor_map, child)==HASH_UNDEFINED_VALUE);
948  /* The child cannot be an ancestor */
949  pips_assert("The child is not an ancestor", !ancestor_control_p(ancestor_map, child));
950  }
951  hash_put(ancestor_map, (void *) child, (void *) ancestor);
952 }
static bool ancestor_control_p(hash_table ancestor_map, control c)
Functions to deal with the ancestor_map.
Definition: bourdoncle.c:837
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
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
#define control_undefined
Definition: ri.h:916
#define ifdebug(n)
Definition: sg.c:47

References ancestor_control_p(), control_undefined, hash_get(), hash_put(), HASH_UNDEFINED_VALUE, ifdebug, and pips_assert.

Referenced by scc_to_dag(), and unstructured_shallow_copy().

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

◆ add_control_to_embedding_control_list()

void add_control_to_embedding_control_list ( control  c)

Definition at line 535 of file bourdoncle.c.

536 {
538 }
static list embedding_control_list
Definition: bourdoncle.c:533

References CONS, CONTROL, and embedding_control_list.

Referenced by node_to_linked_nodes(), and print_embedding_graph().

+ Here is the caller graph for this function:

◆ add_test_successor()

static void add_test_successor ( control  t,
control  new_s,
bool  is_true_successor 
)
static

Called from within a loop where neither t nor new_s are consistent.

Allocate a meaningless control

t may not be consistent because of the caller ifdebug(1) { pips_assert("t is consistent", check_control_statement(t)); }

Definition at line 1318 of file bourdoncle.c.

1319 {
1320  bool slot_found = false;
1321  size_t rank = 0;
1322  size_t pos = 0;
1323 
1324  pips_debug(8, "Begin with t=%p, new_s=%p and is_true_successor=%d",
1325  t, new_s, is_true_successor);
1326 
1327  pips_assert("t is a control with a test", control_test_p(t));
1328  pips_assert("is_true_successor is 0 or 1",
1329  is_true_successor==0 || is_true_successor==1);
1330 
1331  MAPL(s_c, {
1332  control s = CONTROL(CAR(s_c));
1333 
1334  rank = 1 - rank;
1335  pos++;
1336 
1337  if(rank==(size_t) is_true_successor && meaningless_control_p(s)) {
1338  pips_debug(2, "Free meaningless control node %p\n", s);
1340  CONTROL_(CAR(s_c)) = new_s;
1341  slot_found = true;
1342  break;
1343  }
1344  } , control_successors(t));
1345 
1346  if(!slot_found) {
1347  if( ((bool)gen_length(control_successors(t))%2) == is_true_successor) {
1348  /* Allocate a meaningless control */
1350 
1352  CONS(CONTROL,
1353  mlc,
1354  CONS(CONTROL, new_s, NIL)));
1355  pos += 2;
1356  }
1357  else {
1359  CONS(CONTROL, new_s, NIL));
1360  pos++;
1361  }
1362  }
1363 
1364  pips_debug(8, "End with slot_found=%s, rank=%zd and pos=%zd\n",
1365  bool_to_string(slot_found), rank, pos);
1366 
1367  pips_assert("The position is consistent with is_true_successor",
1368  (bool)pos%2 == is_true_successor);
1369 
1370  /* t may not be consistent because of the caller
1371  ifdebug(1) {
1372  pips_assert("t is consistent", check_control_statement(t));
1373  }
1374  */
1375 }
static control make_meaningless_control(list preds, list succs)
With non-deterministic graph, the outcome of a test may be known in advance.
Definition: bourdoncle.c:146
bool meaningless_control_p(control c)
Is exported to exploit non-deterministic control flow graphs.
Definition: bourdoncle.c:154
bool control_test_p(control c)
Check that a node is used as a test in a CFG.
Definition: bourdoncle.c:175
static void free_meaningless_control(control c)
Definition: bourdoncle.c:159
size_t gen_length(const list l)
Definition: list.c:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#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 entity rank
string bool_to_string(bool)
Definition: string.c:243
#define control_successors(x)
Definition: ri.h:945

References bool_to_string(), CAR, CONS, CONTROL, CONTROL_, control_successors, control_test_p(), free_meaningless_control(), gen_length(), gen_nconc(), make_meaningless_control(), MAPL, meaningless_control_p(), NIL, pips_assert, pips_debug, and rank.

Referenced by update_successor_in_copy().

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

◆ ancestor_control_p()

static bool ancestor_control_p ( hash_table  ancestor_map,
control  c 
)
static

Functions to deal with the ancestor_map.

Definition at line 837 of file bourdoncle.c.

838 {
839  bool ancestor_p = false;
840 
841  HASH_MAP(c_new, c_old,
842  {
843  if(c_old==(void *) c) {
844  ancestor_p = true;
845  break;
846  }
847  }
848  , ancestor_map);
849  return ancestor_p;
850 }
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60

References HASH_MAP.

Referenced by add_child_parent_pair(), control_to_ancestor(), and registered_controls_p().

+ Here is the caller graph for this function:

◆ ancestor_cycle_head_to_scc()

unstructured ancestor_cycle_head_to_scc ( control  a,
hash_table  scc_map 
)

scc_map maps either the ancestor node to its scc if the transformers are computed without context, or the call site node to its scc if cycles are replicated to compute transformers within their context.

In spite of the name, this function can be call with ANY control, ancestor or not. An ancestor or a call site are mapped to a defined value.

Parameters
scc_mapcc_map

Definition at line 2356 of file bourdoncle.c.

2357 {
2359 
2360  if((scc_u = (unstructured) hash_get(scc_map, (void *) a))
2362  scc_u = unstructured_undefined;
2363 
2364  return scc_u;
2365 }
#define unstructured_undefined
Definition: ri.h:2980

References hash_get(), HASH_UNDEFINED_VALUE, and unstructured_undefined.

Referenced by cycle_head_p(), cycle_head_to_scc(), cycle_to_flow_sensitive_preconditions(), dag_to_flow_sensitive_preconditions(), direct_cycle_head_p(), load_control_fix_point(), and replicate_cycles().

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

◆ ancestor_map_consistent_p()

static bool ancestor_map_consistent_p ( hash_table  ancestor_map)
static

No control can be an ancestor and a child.

Definition at line 905 of file bourdoncle.c.

906 {
907  bool check_p = true;
908  list ancestors = NIL;
909  list children = NIL;
910 
911  HASH_MAP(c_new, c_old,
912  {
913  ancestors = gen_once((control) c_old, ancestors);
914  children = CONS(CONTROL, (control) c_new, children);
915  }
916  , ancestor_map);
917  gen_list_and(&ancestors, children);
918  check_p = ENDP(ancestors);
919 
920  ifdebug(2) {
921  if(!ENDP(ancestors)) {
922  pips_debug(2, "Bug some control are children and ancestors:\n");
923  print_control_nodes(ancestors);
924  print_control_to_control_mapping("Child to ancestor map:", ancestor_map);
925  }
926  }
927 
928  gen_free_list(ancestors);
929  gen_free_list(children);
930 
931  return check_p;
932 }
static void print_control_to_control_mapping(string message, hash_table map)
Definition: bourdoncle.c:823
void print_control_nodes(list l)
Display identification of a list of control nodes.
Definition: control.c:589
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
void gen_list_and(list *a, const list b)
Compute A = A inter B: complexity in O(n2)
Definition: list.c:941
list gen_once(const void *vo, list l)
Prepend an item to a list only if it is not already in the list.
Definition: list.c:722
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

References CONS, CONTROL, ENDP, gen_free_list(), gen_list_and(), gen_once(), HASH_MAP, ifdebug, NIL, pips_debug, print_control_nodes(), and print_control_to_control_mapping().

Referenced by scc_to_dag().

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

◆ bourdoncle_component()

list bourdoncle_component ( control  vertex,
hash_table  ancestor_map,
hash_table  scc_map 
)

bourdoncle partition

Build sub-unstructured associated to vertex and partition

Re-use copying performed in scc_to_dag() instead u = partition_to_unstructured(vertex, partition); vertex_ancestor = control_to_ancestor(vertex, ancestor_map); hash_put(scc_map, vertex_ancestor, u);

The partition may have to be refreshed because of the previous recursive descent and its graph restructuring action. It is assumed that vertex is still good because heads are not: however vertex is not an ancestor because the input unstructured is copied right away by bourdoncle_partition().

It might be better to recompute the smallest scc including vertex...

Update parent unstructured containing vertex and partition, remove partition and return a new unstructured with the partition inside, except for the initial vertex node which is left in the embedding graph

Build sub-unstructured associated to vertex and partition

u = unlink_partition_and build_unstructured(vertex, partition);

Do not go down into nested unstructured

Parameters
vertexertex
ancestor_mapncestor_map
scc_mapcc_map

Definition at line 2218 of file bourdoncle.c.

2221 {
2222  list partition = NIL;
2223  list b_partition = list_undefined; /* bourdoncle partition */
2225  control vertex_ancestor = control_undefined;
2226 
2227  ifdebug(2) {
2228  pips_debug(2, "Begin for node: \n");
2230  }
2231 
2232  MAP(CONTROL, c,
2233  {
2234  if(get_dfn(c)==0) {
2235  (void) bourdoncle_visit(c, &partition, ancestor_map, scc_map);
2236  }
2237  }
2239 
2240  partition = CONS(CONTROL, vertex, partition);
2241 
2242  /* Build sub-unstructured associated to vertex and partition */
2243  /* Re-use copying performed in scc_to_dag() instead
2244  u = partition_to_unstructured(vertex, partition);
2245  vertex_ancestor = control_to_ancestor(vertex, ancestor_map);
2246  hash_put(scc_map, vertex_ancestor, u);
2247  */
2248 
2249  /* The partition may have to be refreshed because of the previous
2250  recursive descent and its graph restructuring action. It is assumed
2251  that vertex is still good because heads are not: however vertex is
2252  not an ancestor because the input unstructured is copied right away
2253  by bourdoncle_partition().
2254 
2255  It might be better to recompute the smallest scc including
2256  vertex... */
2257  b_partition = gen_copy_seq(partition);
2258 
2259  update_partition(vertex, partition, ancestor_map);
2260 
2261  /* Update parent unstructured containing vertex and partition, remove
2262  partition and return a new unstructured with the partition inside,
2263  except for the initial vertex node which is left in the embedding
2264  graph */
2265  u = scc_to_dag(vertex, partition, ancestor_map);
2266 
2267  /* Build sub-unstructured associated to vertex and partition */
2268  /* u = unlink_partition_and build_unstructured(vertex, partition); */
2269  vertex_ancestor = control_to_ancestor(vertex, ancestor_map);
2270  hash_put(scc_map, vertex_ancestor, u);
2271 
2272  ifdebug(2) {
2273  pips_debug(2, "End with internal partition: ");
2274  print_control_nodes(partition);
2275  pips_debug(2, "End with Bourdoncle partition: ");
2276  print_control_nodes(b_partition);
2277  pips_debug(2, "End with new nodes:\n");
2278  /* Do not go down into nested unstructured */
2281  pips_debug(2, "With entry nodes\n");
2283  pips_debug(2, "And exit node\n");
2285  pips_debug(2, "End.\n");
2286  }
2287 
2288  gen_free_list(partition);
2289  return b_partition;
2290 }
static _int get_dfn(control c)
Definition: bourdoncle.c:121
control control_to_ancestor(control vertex, hash_table ancestor_map)
If vertex is an ancestor control node from the input control graph, return vertex,...
Definition: bourdoncle.c:854
static void update_partition(control root, list partition, hash_table ancestor_map)
Definition: bourdoncle.c:2066
static unstructured scc_to_dag(control root, list partition, hash_table ancestor_map)
The nodes in scc partition but root must be removed.
Definition: bourdoncle.c:1465
static void print_control_node_b(control c)
Definition: bourdoncle.c:299
int bourdoncle_visit(control vertex, list *ppartition, hash_table ancestor_map, hash_table scc_map)
Definition: bourdoncle.c:2293
void gen_multi_recurse(void *o,...)
Multi recursion visitor function.
Definition: genClib.c:3428
bool gen_false(__attribute__((unused)) gen_chunk *unused)
Return false and ignore the argument.
Definition: genClib.c:2796
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#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 unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
#define unstructured_exit(x)
Definition: ri.h:3006

References bourdoncle_visit(), CONS, CONTROL, control_domain, control_successors, control_to_ancestor(), control_undefined, gen_copy_seq(), gen_false(), gen_free_list(), gen_multi_recurse(), gen_null(), gen_true(), get_dfn(), hash_put(), ifdebug, list_undefined, MAP, NIL, pips_debug, print_control_node_b(), print_control_nodes(), scc_to_dag(), statement_domain, unstructured_control, unstructured_exit, unstructured_undefined, and update_partition().

Referenced by bourdoncle_visit().

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

◆ bourdoncle_free()

void bourdoncle_free ( unstructured  ndu,
hash_table  ancestor_map,
hash_table  scc_map 
)

Do not free the statements pointed by the nodes in ndu or in the scc

Parameters
ndudu
ancestor_mapncestor_map
scc_mapcc_map

Definition at line 2506 of file bourdoncle.c.

2509 {
2510  /* Do not free the statements pointed by the nodes in ndu or in the scc */
2512  HASH_MAP(k, v, {
2514  }, scc_map);
2515  hash_table_free(ancestor_map);
2516  hash_table_free(scc_map);
2517 }
static void bourdoncle_unstructured_free(unstructured u)
Definition: bourdoncle.c:2495
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327

References bourdoncle_unstructured_free(), HASH_MAP, and hash_table_free().

Referenced by unstructured_to_flow_sensitive_postconditions_or_transformers().

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

◆ bourdoncle_partition()

list bourdoncle_partition ( unstructured  u,
unstructured p_ndu,
hash_table p_ancestor_map,
hash_table p_scc_map 
)

DAG derived from u by elimination all cycles

mapping from nodes in the new unstructured to the node in the input unstructured

mapping from nodes in u, used as cycle breakers, to the corresponding scc represented as an unstructured

Initialize dfn to 0

Start from the entry point

Should the partition be translated?

Should the cycles be replicated to refine the analyses? If yes, replicate them.

Control nodes associated to a fix point

The hierarchy of fix points is/seems to be lost by scc_map...

We also need the final embedding graph... which might be lost? Or hanging from the first node in partition, the entry point, and hence from new_u.

Parameters
p_ndu_ndu
p_ancestor_map_ancestor_map
p_scc_map_scc_map

Definition at line 1902 of file bourdoncle.c.

1906 {
1907  list partition = NIL;
1908  control root = control_undefined;
1909  /* DAG derived from u by elimination all cycles */
1911  /* mapping from nodes in the new unstructured to the node in the input unstructured */
1912  hash_table ancestor_map = hash_table_make(hash_pointer, 0);
1913  /* mapping from nodes in u, used as cycle breakers, to the corresponding
1914  scc represented as an unstructured */
1915  hash_table scc_map = hash_table_make(hash_pointer, 0);
1916 
1918 
1919  ifdebug(2) {
1920  pips_debug(2, "Begin with unstructured:\n");
1921  print_unstructured(u);
1922  davinci_print_non_deterministic_unstructured(u, "Initial unstructured", scc_map, ancestor_map);
1923  }
1924 
1925  make_vertex_stack();
1926  num = 0;
1928 
1929  new_u = unstructured_shallow_copy(u, ancestor_map);
1930 
1931  ifdebug(8) {
1932  pips_debug(3, "Copied unstructured new_u:\n");
1933  print_unstructured(new_u);
1934  davinci_print_non_deterministic_unstructured(u, "Copy of initial unstructured",
1935  scc_map, ancestor_map);
1936  }
1937 
1938 
1939  /* Initialize dfn to 0 */
1942 
1943  /* Start from the entry point */
1944  root = unstructured_control(new_u);
1945  (void) bourdoncle_visit(root, &partition, ancestor_map, scc_map);
1946 
1947  /* Should the partition be translated? */
1948 
1949  free_vertex_stack();
1951 
1952  /* Should the cycles be replicated to refine the analyses? If yes, replicate them. */
1953  if(get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1954  replicate_cycles(new_u, scc_map, ancestor_map);
1955  }
1956 
1957  ifdebug(2) {
1958  int number_of_fix_points = 0;
1959 
1960  pips_debug(2, "End with partition:");
1961  print_control_nodes(partition);
1962 
1963  pips_debug(2, "End with scc_map:\n");
1964  HASH_MAP(h, uc, {
1965  number_of_fix_points++;
1966  fprintf(stderr, "head=%p with unstructured=%p\n", h, uc);
1967  } , scc_map);
1968  pips_debug(2, "End with %d fix points\n", number_of_fix_points);
1969 
1970  /* Control nodes associated to a fix point */
1971  pips_debug(2, "\nControl nodes associated to a fix point via a sub-unstructured:\n");
1972  HASH_MAP(c_n, c_o, {
1973  void * su;
1974  if((su=hash_get(scc_map, c_o))!=HASH_UNDEFINED_VALUE) {
1975  fprintf(stderr, "head=%p copy of %p with unstructured=%p\n", c_n, c_o, su);
1976  }
1977  }, ancestor_map);
1978 
1979  /* The hierarchy of fix points is/seems to be lost by scc_map... */
1980  pips_debug(2, "End with %d sets of cycles:\n", number_of_fix_points);
1981  number_of_fix_points = 0;
1982  HASH_MAP(h, uc, {
1983  char msg[256];
1984 
1985  number_of_fix_points++;
1986  fprintf(stderr, "Cycles associated to head=%p with unstructured=%p (fix point %d)\n",
1987  h, uc, number_of_fix_points);
1988  sprintf(msg, "Cycles associated to head=%p\\n with unstructured=%p (fix point %d)",
1989  h, uc, number_of_fix_points);
1991  davinci_print_non_deterministic_unstructured((unstructured) uc, msg, scc_map, ancestor_map);
1992  fprintf(stderr, "\n");
1993  } , scc_map);
1994 
1995  /* We also need the final embedding graph... which might be lost? Or
1996  hanging from the first node in partition, the entry point, and hence from new_u. */
1997  pips_debug(2, "Final embedding graph %p:\n", new_u);
1998  print_unstructured(new_u);
1999  davinci_print_non_deterministic_unstructured(new_u, "Final embedding graph", scc_map, ancestor_map);
2000 
2001  pips_debug(2, "End. \n");
2002  }
2003 
2004  *p_ndu = new_u;
2005  *p_ancestor_map = ancestor_map;
2006  *p_scc_map = scc_map;
2007 
2008  return partition;
2009 }
static void reset_dfn(control c)
Definition: bourdoncle.c:106
static hash_table dfn
bourdoncle.c
Definition: bourdoncle.c:104
static void replicate_cycles(unstructured u_main, hash_table scc_map, hash_table ancestor_map)
Definition: bourdoncle.c:1803
unstructured unstructured_shallow_copy(unstructured u, hash_table ancestor_map)
Definition: bourdoncle.c:1009
static int num
Definition: bourdoncle.c:137
static void davinci_print_non_deterministic_unstructured(unstructured u, string msg, hash_table scc_map, hash_table ancestor_map)
Definition: bourdoncle.c:473
static void set_davinci_count()
Definition: bourdoncle.c:427
static void print_unstructured(unstructured u)
Definition: bourdoncle.c:331
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
@ hash_pointer
Definition: newgen_hash.h:32
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...

References bourdoncle_visit(), control_domain, control_undefined, davinci_print_non_deterministic_unstructured(), dfn, fprintf(), gen_false(), gen_multi_recurse(), gen_null(), gen_true(), get_bool_property(), hash_get(), HASH_MAP, hash_pointer, hash_table_free(), hash_table_make(), HASH_UNDEFINED_VALUE, ifdebug, NIL, num, pips_debug, print_control_nodes(), print_unstructured(), replicate_cycles(), reset_dfn(), set_davinci_count(), statement_domain, unstructured_control, unstructured_shallow_copy(), and unstructured_undefined.

Referenced by unstructured_to_flow_sensitive_postconditions_or_transformers().

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

◆ bourdoncle_unstructured_free()

static void bourdoncle_unstructured_free ( unstructured  u)
static

Suppress references to statements, but do not go down recursively into nested unstructured.

Definition at line 2495 of file bourdoncle.c.

2496 {
2497  /* Suppress references to statements, but do not go down recursively
2498  into nested unstructured. */
2502 
2503  free_unstructured(u);
2504 }
void free_unstructured(unstructured p)
Definition: ri.c:2745
static void suppress_statement_reference(control c)
Definition: bourdoncle.c:2488

References control_domain, free_unstructured(), gen_false(), gen_multi_recurse(), gen_null(), gen_true(), statement_domain, and suppress_statement_reference().

Referenced by bourdoncle_free().

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

◆ bourdoncle_visit()

int bourdoncle_visit ( control  vertex,
list ppartition,
hash_table  ancestor_map,
hash_table  scc_map 
)
Parameters
vertexertex
ppartitionpartition
ancestor_mapncestor_map
scc_mapcc_map

Definition at line 2293 of file bourdoncle.c.

2297 {
2298  _int min = 0;
2299  _int head = 0;
2300  bool loop = false;
2301 
2302  vertex_push(vertex);
2303  num = num+1;
2304  head = num;
2305  update_dfn(vertex, num);
2306 
2307  MAP(CONTROL, succ,
2308  {
2309  if(get_dfn(succ)==0) {
2310  min = bourdoncle_visit(succ, ppartition, ancestor_map, scc_map);
2311  }
2312  else {
2313  min = get_dfn(succ);
2314  }
2315  if(min<=head) {
2316  head = min;
2317  loop = true;
2318  }
2319  }
2321 
2322  if (head==get_dfn(vertex)) {
2323  control e = vertex_pop();
2324 
2325  update_dfn(vertex, LONG_MAX);
2326 
2327  if(loop) {
2328  while(e!=vertex) {
2329  update_dfn(e, 0);
2330  e = vertex_pop();
2331  }
2332  *ppartition = gen_nconc(bourdoncle_component(vertex, ancestor_map, scc_map),
2333  *ppartition);
2334  }
2335  else {
2336  *ppartition = CONS(CONTROL, vertex, *ppartition);
2337  }
2338 
2339  }
2340 
2341  return head;
2342 }
static void update_dfn(control c, _int d)
Definition: bourdoncle.c:131
list bourdoncle_component(control vertex, hash_table ancestor_map, hash_table scc_map)
Definition: bourdoncle.c:2218
#define min(a, b)
intptr_t _int
_INT
Definition: newgen_types.h:53

References bourdoncle_component(), CONS, CONTROL, control_successors, gen_nconc(), get_dfn(), MAP, min, num, and update_dfn().

Referenced by bourdoncle_component(), and bourdoncle_partition().

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

◆ check_control_statement()

static bool check_control_statement ( control  c)
static

The true and false branches should be empty most of the time. But a structured test used a non-deterministic node might very well have two successors or more. The assert below is too strong.

Since some test statements are left structured and since structure and unstructured test statements may be non-deterministic here, nothing can be said.

Non-deterministic environment

Non-deterministic environment

A meaningless control can be shared in intermediate states

It should not be shared, not only because memory management would be impossible locally but also because gen_recurse() would follow forbidden paths.

Definition at line 198 of file bourdoncle.c.

199 {
200  if(!meaningless_control_p(c)) {
202  if(gen_length(control_successors(c))==2) {
203  /* The true and false branches should be empty most of the
204  time. But a structured test used a non-deterministic node might
205  very well have two successors or more. The assert below is too
206  strong. */
207  /*
208  test t = statement_test(control_statement(c));
209  statement ts = test_true(t);
210  statement fs = test_false(t);
211  */
212  /* Since some test statements are left structured and since
213  structure and unstructured test statements may be
214  non-deterministic here, nothing can be said. */
215  /*
216  pips_assert("The true and false branches must be empty",
217  empty_statement_or_labelless_continue_p(ts)
218  && empty_statement_or_labelless_continue_p(fs));
219  */
220  ;
221  }
222  else {
223  /* Non-deterministic environment */
224  /*
225  pips_assert("A structured test has one successor at most",
226  gen_length(control_successors(c))<2);
227  */
228  ;
229  }
230  }
231  else {
232  /* Non-deterministic environment */
233  /*
234  pips_assert("A non-test has at most one successor",
235  gen_length(control_successors(c))<2);
236  */
237  ;
238  }
239  }
240  else {
241  ifdebug(4) {
242  /* A meaningless control can be shared in intermediate states */
243  }
244  else ifdebug(1){
245  /* It should not be shared, not only because memory management would
246  be impossible locally but also because gen_recurse() would follow
247  forbidden paths. */
248  pips_assert("A meaningless control has one and ony one predecessor",
250  pips_assert("A meaningless control has no successor",
252  }
253 
254  }
255 
256  MAP(CONTROL, pred,
257  {
258  if(!gen_in_list_p(c, control_successors(pred))) {
260  pips_assert("c is a successor of each of its predecessors", false);
261  }
262  }
263  , control_predecessors(c));
264 
265  MAP(CONTROL, succ,
266  {
267  if(!gen_in_list_p(c, control_predecessors(succ))) {
269  pips_assert("c is a predecessor of each of its successors", false);
270  }
271  }
272  , control_successors(c));
273  return true;
274 }
static void print_control_node_without_check(control)
Code partly replicated from semantics/unstructured.c to be able to taylor it to the exact needs.
Definition: bourdoncle.c:304
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
bool statement_test_p(statement)
Definition: statement.c:343
#define control_statement(x)
Definition: ri.h:941

References CONTROL, control_predecessors, control_statement, control_successors, gen_in_list_p(), gen_length(), ifdebug, MAP, meaningless_control_p(), pips_assert, print_control_node_without_check(), and statement_test_p().

Referenced by davinci_print_control_node(), print_and_check_control_node(), print_embedding_graph(), and scc_to_dag().

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

◆ clean_up_control_test()

static int clean_up_control_test ( control  c)
static

Take care of two problems: meaningless control nodes may end up shared by effective nodes and they may end up uselessly numerous.

FI: Two more problems could be tackled. The same node should not be twice a true or twice a false successor, although a given node can be a true and a false successor. gen_once() should be used to build t_succs and f_succs but the assertions and the memory management should then be updated. Duplicate could be chained to the u_succs(), the useless successors

true branch successors

false branch successors

empty successors

Number of eliminations

Partition the successors

Rebuild the successor list if it can be useful

new successor list

FI: I do not see why you are sure not to need all meaningless controls... There might be no meaningless control at all. The next two assertions seem too strong.

Courageously, free the remaining meaningless successors

Update the successor list of c

Free the partition lists

Definition at line 655 of file bourdoncle.c.

656 {
657  list succs = control_successors(c);
658  list t_succs = NIL; /* true branch successors */
659  list f_succs = NIL; /* false branch successors */
660  list e_succs = NIL; /* empty successors */
661  int ns = gen_length(succs);
662  int nts = 0;
663  int nfs = 0;
664  int nes = 0;
665  int nel = 0; /* Number of eliminations */
666  int rank = 0;
667 
668  pips_assert("A control test has at least two successors", ns>=2);
669 
670  /* Partition the successors */
671  MAP(CONTROL, s,
672  {
673  rank++;
674  if(meaningless_control_p(s)) {
675  e_succs = CONS(CONTROL, s, e_succs);
676  }
677  else if(rank%2==1) {
678  t_succs = CONS(CONTROL, s, t_succs);
679  }
680  else {
681  f_succs = CONS(CONTROL, s, f_succs);
682  }
683  }
684  , succs);
685 
686  nts = gen_length(t_succs);
687  nfs = gen_length(f_succs);
688  nes = gen_length(e_succs);
689  pips_assert("The rank of the last successors is the number of successors", rank==ns);
690  pips_assert("true, false and empty successors are a partition", ns==nts+nfs+nes);
691 
692  /* Rebuild the successor list if it can be useful */
693  if(nes > nts-nfs && nes > nfs-nts) {
694  list n_succs = NIL; /* new successor list */
695  list c_t_succs = t_succs;
696  list c_f_succs = f_succs;
697  list c_e_succs = e_succs;
698 
699  for(rank=1; rank <= nts || rank <= nfs; rank++) {
700  if(!ENDP(c_t_succs)) {
701  n_succs = gen_nconc(n_succs, CONS(CONTROL, CONTROL(CAR(c_t_succs)), NIL));
702  POP(c_t_succs);
703  }
704  else {
705  pips_assert("The empty successor list is not empty", !ENDP(c_e_succs));
706  n_succs = gen_nconc(n_succs, CONS(CONTROL, CONTROL(CAR(c_e_succs)), NIL));
707  POP(c_e_succs);
708  }
709  if(!ENDP(c_f_succs)) {
710  n_succs = gen_nconc(n_succs, CONS(CONTROL, CONTROL(CAR(c_f_succs)), NIL));
711  POP(c_f_succs);
712  }
713  else {
714  pips_assert("The empty successor list is not empty", !ENDP(c_e_succs));
715  n_succs = gen_nconc(n_succs, CONS(CONTROL, CONTROL(CAR(c_e_succs)), NIL));
716  POP(c_e_succs);
717  }
718  }
719  pips_assert("No more true successors", ENDP(c_t_succs));
720  pips_assert("No more false successors", ENDP(c_f_succs));
721  /* FI: I do not see why you are sure not to need all meaningless
722  controls... There might be no meaningless control at all. The next
723  two assertions seem too strong. */
724  pips_assert("More empty successors", !ENDP(c_e_succs));
725 
726  nel = ns - gen_length(n_succs);
727  pips_assert("The successor list is reduced", nel>0);
728 
729  /* Courageously, free the remaining meaningless successors */
730  MAP(CONTROL, e, {
731  ifdebug(9) fprintf(stderr,"control %p is consistent and is going to be freed\n", e);
733  }, c_e_succs);
734 
735  /* Update the successor list of c */
737  control_successors(c) = n_succs;
738  }
739  /* Free the partition lists */
740  gen_free_list(t_succs);
741  gen_free_list(f_succs);
742  gen_free_list(e_succs);
743 
744  return nel;
745 }
static hash_table nts
Definition: prettyprint.c:63
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
return(s1)

References CAR, CONS, CONTROL, control_successors, ENDP, fprintf(), free_meaningless_control(), gen_free_list(), gen_length(), gen_nconc(), ifdebug, MAP, meaningless_control_p(), NIL, nts, pips_assert, POP, and rank.

Referenced by clean_up_embedding_graph().

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

◆ clean_up_embedding_graph()

static void clean_up_embedding_graph ( control  c)
static

number of replications

number of eliminations

FI: A level of 1 makes more sense, but it is very slow on large graphs. The same nodes are checked several times because the cache managed by control_consistent_p() is lost between iterations.

ifdebug(1) {

A meaningless control must have only one predecessor and no successor.

A non-deterministic test does not need too many meaningless successors. A new list must be built first because clean_up_control_test() destroys elements of el, which cannot be scanned any longer.

Definition at line 747 of file bourdoncle.c.

748 {
749  list el = node_to_linked_nodes(c);
750  list tl = NIL;
751  int nor = 0; /* number of replications */
752  int nel = 0; /* number of eliminations */
753 
754  /* FI: A level of 1 makes more sense, but it is very slow on large
755  graphs. The same nodes are checked several times because the cache
756  managed by control_consistent_p() is lost between iterations. */
757  /* ifdebug(1) { */
758  ifdebug(8) {
759  pips_assert("c is consistent", control_consistent_p(c));
760  MAP(CONTROL, ec, {
761  pips_assert("ec is consistent first", control_consistent_p(ec));
762  ifdebug(10) fprintf(stderr,"control %p is consistent first\n", ec);
763  }
764  , el);
765  }
766 
767  /* A meaningless control must have only one predecessor and no
768  successor. */
769  MAP(CONTROL, ec, {
770  if(meaningless_control_p(ec)) {
771  pips_assert("No successor", ENDP(control_successors(ec)));
772 
773  if(gen_length(control_predecessors(ec))>1) {
774  list c_pred = list_undefined;
775 
776  for(c_pred=CDR(control_predecessors(ec)); !ENDP(c_pred); POP(c_pred)) {
777  control pred = CONTROL(CAR(c_pred));
778  control new_ec = make_meaningless_control(CONS(CONTROL, pred, NIL), NIL);
779  gen_list_patch(control_successors(pred), ec, new_ec);
780  nor++;
781  }
784  }
785  }
786  }
787  , el);
788 
789  ifdebug(1) {
790  MAP(CONTROL, ec, {
791  pips_assert("ec is consistent second", control_consistent_p(ec));
792  ifdebug(9) fprintf(stderr,"control %p is consistent second\n", ec);
793  }
794  , el);
795  }
796 
797  /* A non-deterministic test does not need too many meaningless
798  successors. A new list must be built first because
799  clean_up_control_test() destroys elements of el, which cannot be
800  scanned any longer. */
801  MAP(CONTROL, ec, {
802  ifdebug(10) fprintf(stderr,"is control %p is consistent?\n", ec);
803  ifdebug(1) pips_assert("ec is consistent third", control_consistent_p(ec));
804  if(control_test_p(ec)) {
805  tl = CONS(CONTROL, ec, tl);
806  }
807  }
808  , el);
809 
810  MAP(CONTROL, ec, {
811  ifdebug(10) fprintf(stderr,"is control %p is consistent?\n", ec);
812  ifdebug(1) pips_assert("ec is consistent fourth", control_consistent_p(ec));
813  nel += clean_up_control_test(ec);
814  }
815  , tl);
816 
817  gen_free_list(el);
818  gen_free_list(tl);
819 
820  pips_debug(2, "End: %d useless successors destroyed\n", nel);
821 }
bool control_consistent_p(control p)
Definition: ri.c:496
static int clean_up_control_test(control c)
Take care of two problems: meaningless control nodes may end up shared by effective nodes and they ma...
Definition: bourdoncle.c:655
static list node_to_linked_nodes(control c)
Allocate a list of control nodes transitively linked to control c.
Definition: bourdoncle.c:626
static list successors(list l)
if(!(yy_init))
Definition: genread_lex.c:1029
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
static int useless(Pproblem XX, int i)
Definition: isolve.c:521

References CAR, CDR, clean_up_control_test(), CONS, CONTROL, control_consistent_p(), control_predecessors, control_successors, control_test_p(), ENDP, fprintf(), gen_free_list(), gen_length(), gen_list_patch(), ifdebug, list_undefined, make_meaningless_control(), MAP, meaningless_control_p(), NIL, node_to_linked_nodes(), pips_assert, pips_debug, and POP.

Referenced by scc_to_dag().

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

◆ control_cons_compare()

static int control_cons_compare ( list  l1,
list  l2 
)
static

Definition at line 402 of file bourdoncle.c.

403 {
404  int diff = 0;
405  control c1 = CONTROL(CAR(l1));
406  control c2 = CONTROL(CAR(l2));
407 
408  if(meaningless_control_p(c1)) {
409  diff = 0;
410  }
411  else if(meaningless_control_p(c2)) {
412  diff = 0;
413  }
414  else {
416  statement s2 = control_statement(c2);
417 
419  }
420  return diff;
421 }
#define statement_ordering(x)
Definition: ri.h:2454
s1
Definition: set.c:247

References CAR, CONTROL, control_statement, meaningless_control_p(), s1, and statement_ordering.

Referenced by davinci_print_control_nodes(), and davinci_print_non_deterministic_unstructured().

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

◆ control_shallow_copy()

control control_shallow_copy ( control  c)

Definition at line 970 of file bourdoncle.c.

971 {
972  control new_c = control_undefined;
973 
974  new_c = make_control(control_statement(c),
977  hash_put(replicate_map, (void *) c, (void *) new_c);
978 
979  return new_c;
980 }
static hash_table replicate_map
Replication of unstructured (i.e.
Definition: bourdoncle.c:957

References control_predecessors, control_statement, control_successors, control_undefined, gen_copy_seq(), hash_put(), make_control(), and replicate_map.

Referenced by partition_to_unstructured(), and unstructured_shallow_copy().

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

◆ control_test_p()

bool control_test_p ( control  c)

Check that a node is used as a test in a CFG.

The associated statement must be a test, the number of successors must be two and the true and false branches must be empty. Exported for user of ND CFG's.

Definition at line 175 of file bourdoncle.c.

176 {
177  bool test_p = false;
178  if(!meaningless_control_p(c)) {
180  if(gen_length(control_successors(c))>=2) {
182  statement ts = test_true(t);
183  statement fs = test_false(t);
186  }
187  }
188  }
189  return test_p;
190 }
test statement_test(statement)
Get the test of a statement.
Definition: statement.c:1348
bool empty_statement_or_labelless_continue_p(statement)
Return true if the statement is an empty instruction block without label or a continue without label ...
Definition: statement.c:446
#define test_false(x)
Definition: ri.h:2837
#define test_true(x)
Definition: ri.h:2835

References control_statement, control_successors, empty_statement_or_labelless_continue_p(), gen_length(), meaningless_control_p(), statement_test(), statement_test_p(), test_false, and test_true.

Referenced by add_test_successor(), clean_up_embedding_graph(), dag_to_flow_sensitive_preconditions(), davinci_print_control_node(), intersect_successors_with_partition_or_complement(), load_arc_precondition(), one_successor_kind_only_p(), process_ready_node(), update_successor_in_copy(), and update_successors_of_predecessor().

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

◆ control_to_ancestor()

control control_to_ancestor ( control  vertex,
hash_table  ancestor_map 
)

If vertex is an ancestor control node from the input control graph, return vertex, else return its ancestor.

Is used in other libraries.

This assert may be too strong, but all control nodes are copied when just after entering bourdoncle_partition which should make it correct.

Theoretically only useful when HASH_UNDEFINED_VALUE has been returned, i.e. when ancestor==vertex

Parameters
vertexertex
ancestor_mapncestor_map

Definition at line 854 of file bourdoncle.c.

855 {
856  control ancestor = control_undefined;
857 
858  if((ancestor = hash_get(ancestor_map, vertex))==HASH_UNDEFINED_VALUE)
859  ancestor = vertex;
860  ifdebug(2) {
861  /* This assert may be too strong, but all control nodes are copied
862  when just after entering bourdoncle_partition which should make it
863  correct. */
864  /* Theoretically only useful when HASH_UNDEFINED_VALUE has been
865  returned, i.e. when ancestor==vertex */
866  if(!ancestor_control_p(ancestor_map, ancestor)) {
868  statement as = control_statement(ancestor);
869 
870  pips_debug(2, "vertex=%p with statement %s\n",
872  pips_debug(2, "ancestor=%p with statement %s\n",
873  ancestor, statement_identification(as));
874  pips_assert("ancestor really is an ancestor",
875  ancestor_control_p(ancestor_map, ancestor));
876  }
877  }
878 
879  return ancestor;
880 }
struct _newgen_struct_vertex_ * vertex
Definition: dg.h:28
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700

References ancestor_control_p(), control_statement, control_undefined, hash_get(), HASH_UNDEFINED_VALUE, ifdebug, pips_assert, pips_debug, and statement_identification().

Referenced by bourdoncle_component(), cycle_head_p(), cycle_head_to_scc(), cycle_to_flow_sensitive_preconditions(), dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), dag_to_flow_sensitive_preconditions(), load_control_fix_point(), load_cycle_temporary_precondition(), replicate_cycles(), and update_partition().

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

◆ control_to_replicate()

static control control_to_replicate ( control  old_c)
static

Definition at line 1002 of file bourdoncle.c.

1003 {
1004  control new_c = hash_get(replicate_map, (void *) old_c);
1005  pips_assert("new_c is defined", new_c!=(control) HASH_UNDEFINED_VALUE);
1006  return new_c;
1007 }

References hash_get(), HASH_UNDEFINED_VALUE, pips_assert, and replicate_map.

Referenced by partition_to_unstructured(), and unstructured_shallow_copy().

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

◆ control_translate_arcs()

static void control_translate_arcs ( control  c)
static

Definition at line 982 of file bourdoncle.c.

983 {
984  MAPL(c_c,
985  {
986  control old_c = CONTROL(CAR(c_c));
987  control new_c = hash_get(replicate_map, (void *) old_c);
988  pips_assert("new_c is defined", new_c!=(control) HASH_UNDEFINED_VALUE);
989  CONTROL_(CAR(c_c)) = new_c;
990  }
991  , control_predecessors(c));
992  MAPL(c_c,
993  {
994  control old_c = CONTROL(CAR(c_c));
995  control new_c = hash_get(replicate_map, (void *) old_c);
996  pips_assert("new_c is defined", new_c!=(control) HASH_UNDEFINED_VALUE);
997  CONTROL_(CAR(c_c)) = new_c;
998  }
999  , control_successors(c));
1000 }

References CAR, CONTROL, CONTROL_, control_predecessors, control_successors, hash_get(), HASH_UNDEFINED_VALUE, MAPL, pips_assert, and replicate_map.

Referenced by unstructured_shallow_copy().

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

◆ copy_dfn()

static void copy_dfn ( control  new_c,
control  old_c 
)
static

Definition at line 111 of file bourdoncle.c.

112 {
113  _int d = 0;
114 
115  if((d = (_int) hash_get(dfn, (void *) old_c)) == (_int) (HASH_UNDEFINED_VALUE))
116  pips_internal_error("No dfn value for control %p", old_c);
117 
118  hash_put(dfn, (void *) new_c, (void *) d);
119 }
#define pips_internal_error
Definition: misc-local.h:149

References dfn, hash_get(), hash_put(), HASH_UNDEFINED_VALUE, and pips_internal_error.

Referenced by scc_to_dag().

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

◆ cycle_head_p()

bool cycle_head_p ( control  c,
hash_table  ancestor_map,
hash_table  scc_map 
)

This node is a cycle call site.

This is correct whether the actual scc associated to c is scc_u or not. If a copy of a control is associated to a scc, its ancestors and all the others copies also are associated to a scc.

we may be in the context sensitive transformer mode

Parameters
ancestor_mapncestor_map
scc_mapcc_map

Definition at line 2385 of file bourdoncle.c.

2386 {
2387  /* This is correct whether the actual scc associated to c is scc_u or
2388  not. If a copy of a control is associated to a scc, its ancestors and
2389  all the others copies also are associated to a scc. */
2390  bool is_cycle = false;
2391  control a = control_to_ancestor(c, ancestor_map);
2392  unstructured scc_u = ancestor_cycle_head_to_scc(a, scc_map);
2393 
2394  if(unstructured_undefined_p(scc_u)) {
2395  /* we may be in the context sensitive transformer mode */
2396  scc_u = ancestor_cycle_head_to_scc(c, scc_map);
2397  }
2398 
2399  is_cycle = !unstructured_undefined_p(scc_u);
2400 
2401  return is_cycle;
2402 }
unstructured ancestor_cycle_head_to_scc(control a, hash_table scc_map)
scc_map maps either the ancestor node to its scc if the transformers are computed without context,...
Definition: bourdoncle.c:2356
#define unstructured_undefined_p(x)
Definition: ri.h:2981

References ancestor_cycle_head_to_scc(), control_to_ancestor(), and unstructured_undefined_p.

Referenced by cycle_to_flow_sensitive_preconditions(), dag_to_flow_sensitive_preconditions(), davinci_print_non_deterministic_unstructured(), process_ready_node(), replicate_cycles(), and unstructured_to_effects().

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

◆ cycle_head_to_scc()

unstructured cycle_head_to_scc ( control  c,
hash_table  ancestor_map,
hash_table  scc_map 
)

The ancestor of this node is associated to a specific cycle.

either we have a direct connection, or we need to go thru the ancestor node

Parameters
ancestor_mapncestor_map
scc_mapcc_map

Definition at line 2433 of file bourdoncle.c.

2434 {
2435  /* either we have a direct connection, or we need to go thru the
2436  ancestor node */
2437 
2438  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
2439 
2440  if(unstructured_undefined_p(scc_u)) {
2441  control a = control_to_ancestor(c, ancestor_map);
2442  scc_u = ancestor_cycle_head_to_scc(a, scc_map);
2443  }
2444  return scc_u;
2445 }

References ancestor_cycle_head_to_scc(), control_to_ancestor(), and unstructured_undefined_p.

Referenced by dag_to_flow_sensitive_preconditions(), process_ready_node(), and unstructured_to_effects().

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

◆ davinci_print_control_node()

static void davinci_print_control_node ( control  c,
FILE *  f,
bool  entry_p,
bool  exit_p,
bool  fix_point_p 
)
static

Output CFG in daVinci format.

The same node can be an entry and an exit node.

Declare arcs

Definition at line 344 of file bourdoncle.c.

348 {
349  char attributes[256];
350  bool arc_kind = true;
351 
352  /* The same node can be an entry and an exit node. */
353  attributes[0] = '\000';
354  if(entry_p) {
355  (void) strcpy(&attributes[0], ",a(\"BORDER\",\"double\")");
356  }
357  if(exit_p){
358  (void) strcat(&attributes[0], ",a(\"COLOR\",\"red\")");
359  }
360  if(fix_point_p){
361  (void) strcat(&attributes[0], ",a(\"FONTSTYLE\",\"bold_italic\")");
362  }
363 
364  if(meaningless_control_p(c)) {
365  fprintf(f, "l(\"%p\",n(\"\",[a(\"_GO\",\"text\"),a(\"OBJECT\",\"%p\")],\n\t[\n", c, c);
366  }
367  else if(control_test_p(c)) {
369  fprintf(f,
370  "l(\"%p\",n(\"\",[a(\"_GO\",\"rhombus\"),a(\"OBJECT\",\"%p\\n(%d,%d)\")%s],\n\t[\n",
371  c, c,
372  ORDERING_NUMBER(so), ORDERING_STATEMENT(so), attributes);
373  }
374  else {
376  fprintf(f, "l(\"%p\",n(\"\",[a(\"OBJECT\",\"%p\\n(%d,%d)\")%s],\n\t[\n", c, c,
377  ORDERING_NUMBER(so), ORDERING_STATEMENT(so), attributes);
378  }
379 
380  /* Declare arcs */
381  MAPL(c_s, {
382  control s = CONTROL(CAR(c_s));
383 
384  if(control_test_p(c)) {
385  (void) strcpy(&attributes[0], arc_kind? "green":"red");
386  fprintf(f, "\tl(\"%p->%p\",e(\"\",[a(\"EDGECOLOR\",\"%s\")],r(\"%p\")))",
387  c, s, attributes, s);
388  }
389  else {
390  fprintf(f, "\tl(\"%p->%p\",e(\"\",[],r(\"%p\")))", c, s, s);
391  }
392 
393  fprintf(f, "%s\n", ENDP(CDR(c_s))? "" : ",");
394  arc_kind = !arc_kind;
395  }, control_successors(c));
396 
397  fprintf(f,"\t]))");
398 
399  (void) check_control_statement(c);
400 }
static bool check_control_statement(control c)
Definition: bourdoncle.c:198
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
#define ORDERING_NUMBER(o)
#define ORDERING_STATEMENT(o)

References CAR, CDR, check_control_statement(), CONTROL, control_statement, control_successors, control_test_p(), ENDP, f(), fprintf(), MAPL, meaningless_control_p(), ORDERING_NUMBER, ORDERING_STATEMENT, and statement_ordering.

Referenced by davinci_print_control_nodes(), and davinci_print_non_deterministic_unstructured().

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

◆ davinci_print_control_nodes()

static void davinci_print_control_nodes ( list  l,
string  msg 
)
static

Definition at line 433 of file bourdoncle.c.

434 {
436  FILE * f = safe_fopen(concatenate(dn, "/",
439  "-",
440  i2a(++davinci_count),
441  ".daVinci", NULL),
442  "w");
443  list sl = gen_copy_seq(l);
444 
445  free(dn);
447 
448  fprintf(f, "[\n");
449  fprintf(f, "l(\"%s\",n(\"\",[a(\"_GO\",\"text\"),a(\"OBJECT\",\"%s\\nSerial number for module %s: %d\\nEntry node: double border\\nExit node: red\\nCycles: bold italic\\nTrue arc: green\\nFalse arc: red\")],\n\t[])),\n",
451  /*
452  fprintf(f, "l(\"%d\",n(\"\",[a(\"_GO\",\"text\"),a(\"OBJECT\",\"serial number: %d\")],\n\t[])),\n",
453  davinci_count, davinci_count);
454  */
455 
456  MAPL(c_c, {
457  control c = CONTROL(CAR(c_c));
458 
459  davinci_print_control_node(c, f, c==CONTROL(CAR(l)), false, false);
460  fprintf(f, "%s\n", ENDP(CDR(c_c))? "" : ",");
461  }, sl);
462 
463  fprintf(f, "]\n");
464  gen_free_list(sl);
466  "-",
468  ".daVinci", NULL));
469 
470 }
static int control_cons_compare(list l1, list l2)
Definition: bourdoncle.c:402
static int davinci_count
This counter is pre-incremented each time a new graph is stored to generate a new file name.
Definition: bourdoncle.c:425
static void davinci_print_control_node(control c, FILE *f, bool entry_p, bool exit_p, bool fix_point_p)
Output CFG in daVinci format.
Definition: bourdoncle.c:344
FILE * safe_fopen(const char *filename, const char *what)
Definition: file.c:67
int safe_fclose(FILE *stream, const char *filename)
Definition: file.c:77
void free(void *)
const char * get_current_module_name(void)
Get the name of the current module.
Definition: static.c:121
void gen_sort_list(list l, gen_cmp_func_t compare)
Sorts a list of gen_chunks in place, to avoid allocations...
Definition: list.c:796
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
int(* gen_cmp_func_t)(const void *, const void *)
Definition: newgen_types.h:114
string db_get_current_workspace_directory(void)
Definition: workspace.c:96

References CAR, CDR, concatenate(), CONTROL, control_cons_compare(), davinci_count, davinci_print_control_node(), db_get_current_workspace_directory(), ENDP, f(), fprintf(), free(), gen_copy_seq(), gen_free_list(), gen_sort_list(), get_current_module_name(), i2a(), MAPL, safe_fclose(), and safe_fopen().

Referenced by print_embedding_graph().

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

◆ davinci_print_non_deterministic_unstructured()

static void davinci_print_non_deterministic_unstructured ( unstructured  u,
string  msg,
hash_table  scc_map,
hash_table  ancestor_map 
)
static

It may be called with an empty ancestor and scc maps.

Definition at line 472 of file bourdoncle.c.

474 {
476  FILE * f = safe_fopen(concatenate(dn, "/",
479  "-",
480  i2a(++davinci_count),
481  ".daVinci", NULL),
482  "w");
483  control entry_c = unstructured_control(u);
484  control exit_c = unstructured_exit(u);
485  list l = NIL;
486  list sl = list_undefined;
487 
488  free(dn);
489  forward_control_map_get_blocs(entry_c, &l);
490 
491  if(!gen_in_list_p(exit_c, l)) {
492  pips_debug(1, "Exit node %p in unstructured %p is not reachable\n", exit_c, u);
493  }
494 
495  sl = gen_copy_seq(l);
496 
498 
499  fprintf(f, "[\n");
500  fprintf(f, "l(\"%s\",n(\"\",[a(\"_GO\",\"text\"),a(\"OBJECT\",\"%s\\nSerial number for module %s: %d\\nEntry node: double border\\nExit node: red\\nCycles: bold italic\\nTrue arc: green\\nFalse arc: red\")],\n\t[])),\n",
502  /*
503  fprintf(f, "l(\"%d\",n(\"\",[a(\"_GO\",\"text\"),a(\"OBJECT\",\"serial number: %d\")],\n\t[])),\n",
504  davinci_count, davinci_count);
505  */
506 
507  MAPL(c_c, {
508  control c = CONTROL(CAR(c_c));
510 
511  if((a = hash_get(ancestor_map, c))==HASH_UNDEFINED_VALUE)
512  a = c;
513 
514  /* It may be called with an empty ancestor and scc maps. */
516  c==entry_c,
517  c==exit_c,
518  hash_table_entry_count(ancestor_map)!=0
519  && !meaningless_control_p(c)
520  && cycle_head_p(c, ancestor_map, scc_map));
521  fprintf(f, "%s\n", ENDP(CDR(c_c))? "" : ",");
522  }, sl);
523 
524  fprintf(f, "]\n");
525  gen_free_list(sl);
527  "-",
529  ".daVinci", NULL));
530 
531 }
bool cycle_head_p(control c, hash_table ancestor_map, hash_table scc_map)
This node is a cycle call site.
Definition: bourdoncle.c:2385
void forward_control_map_get_blocs(c, l)
Build recursively the list of all controls forward-reachable from a control of an unstructured.
Definition: control.c:208
int hash_table_entry_count(hash_table htp)
now we define observers in order to hide the hash_table type...
Definition: hash.c:818

References CAR, CDR, concatenate(), CONTROL, control_cons_compare(), control_undefined, cycle_head_p(), davinci_count, davinci_print_control_node(), db_get_current_workspace_directory(), ENDP, f(), forward_control_map_get_blocs(), fprintf(), free(), gen_copy_seq(), gen_free_list(), gen_in_list_p(), gen_sort_list(), get_current_module_name(), hash_get(), hash_table_entry_count(), HASH_UNDEFINED_VALUE, i2a(), list_undefined, MAPL, meaningless_control_p(), NIL, pips_debug, safe_fclose(), safe_fopen(), unstructured_control, and unstructured_exit.

Referenced by bourdoncle_partition().

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

◆ direct_cycle_head_p()

bool direct_cycle_head_p ( control  c,
hash_table  scc_map 
)

This node is directly associated to a specific cycle.

Parameters
scc_mapcc_map

Definition at line 2422 of file bourdoncle.c.

2423 {
2424  bool is_cycle = false;
2425  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
2426 
2427  is_cycle = !unstructured_undefined_p(scc_u);
2428 
2429  return is_cycle;
2430 }

References ancestor_cycle_head_to_scc(), and unstructured_undefined_p.

Referenced by replicate_cycles().

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

◆ entry_control_p()

static bool entry_control_p ( control  c,
list  partition 
)
static

Definition at line 1167 of file bourdoncle.c.

1168 {
1169  return entry_or_exit_control_p(c, partition, true);
1170 }
static bool entry_or_exit_control_p(control c, list partition, bool check_entry)
Definition: bourdoncle.c:1149

References entry_or_exit_control_p().

Referenced by scc_to_dag().

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

◆ entry_or_exit_control_p()

static bool entry_or_exit_control_p ( control  c,
list  partition,
bool  check_entry 
)
static

Definition at line 1149 of file bourdoncle.c.

1152 {
1153  bool is_entry_or_exit_p = false;
1154  list nodes = check_entry?control_predecessors(c):control_successors(c);
1155 
1156  MAP(CONTROL, pred,
1157  {
1158  if(!meaningless_control_p(pred) && !gen_in_list_p(pred, partition)) {
1159  is_entry_or_exit_p = true;
1160  break;
1161  }
1162  }
1163  , nodes);
1164 
1165  return is_entry_or_exit_p;
1166 }

References CONTROL, control_predecessors, control_successors, gen_in_list_p(), MAP, and meaningless_control_p().

Referenced by entry_control_p(), and exit_control_p().

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

◆ exit_control_p()

static bool exit_control_p ( control  c,
list  partition 
)
static

Definition at line 1172 of file bourdoncle.c.

1173 {
1174  return entry_or_exit_control_p(c, partition, false);
1175 }

References entry_or_exit_control_p().

Referenced by scc_to_dag().

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

◆ false_successors_only_p()

bool false_successors_only_p ( control  c)

Definition at line 2481 of file bourdoncle.c.

2482 {
2483  bool true_only_p = false;
2484  true_only_p = one_successor_kind_only_p(c, true);
2485  return true_only_p;
2486 }
bool one_successor_kind_only_p(control c, bool true_p)
useful for non-deterministic control flow graph only
Definition: bourdoncle.c:2451

References one_successor_kind_only_p().

Referenced by dag_to_flow_sensitive_preconditions(), and process_ready_node().

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

◆ free_meaningless_control()

static void free_meaningless_control ( control  c)
static

free_control() cannot be used because you do not want to free the successors and the predecessors

Definition at line 159 of file bourdoncle.c.

160 {
161  /* free_control() cannot be used because you do not want to free the
162  successors and the predecessors */
163  pips_assert("No statement is associated", statement_undefined_p(control_statement(c)));
168  free_control(c);
169 }
void free_control(control p)
Definition: ri.c:490
#define statement_undefined_p(x)
Definition: ri.h:2420

References control_predecessors, control_statement, control_successors, free_control(), gen_free_list(), list_undefined, pips_assert, and statement_undefined_p.

Referenced by add_test_successor(), and clean_up_control_test().

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

◆ get_dfn()

static _int get_dfn ( control  c)
static

Definition at line 121 of file bourdoncle.c.

122 {
123  _int d = 0;
124 
125  if((d = (_int) hash_get(dfn, (void *) c)) == (_int) (HASH_UNDEFINED_VALUE))
126  pips_internal_error("No dfn value for control %p", c);
127 
128  return d;
129 }

References dfn, hash_get(), HASH_UNDEFINED_VALUE, and pips_internal_error.

Referenced by bourdoncle_component(), bourdoncle_visit(), and scc_to_dag().

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

◆ intersect_successors_with_partition()

void intersect_successors_with_partition ( control  c,
list  partition 
)
Parameters
partitionartition

Definition at line 1224 of file bourdoncle.c.

1226 {
1228 }
void intersect_successors_with_partition_or_complement(control c, list partition, bool complement_p)
If complement_p, preserve successors in the complement of partition.
Definition: bourdoncle.c:1181

References intersect_successors_with_partition_or_complement().

Referenced by scc_to_dag().

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

◆ intersect_successors_with_partition_complement()

void intersect_successors_with_partition_complement ( control  c,
list  partition 
)
Parameters
partitionartition

Definition at line 1230 of file bourdoncle.c.

1232 {
1234 }

References intersect_successors_with_partition_or_complement().

Referenced by scc_to_dag().

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

◆ intersect_successors_with_partition_or_complement()

void intersect_successors_with_partition_or_complement ( control  c,
list  partition,
bool  complement_p 
)

If complement_p, preserve successors in the complement of partition.

Else preserve successors in partition. Take care of test nodes wich must keep two successors no matter what.

The CFG may not be connexe or the exit path may be hidden by a STOP statement

Let's boldy assume the parent control node is used as a CFG test statement and preserve the number of successors.

It is not a CFG test node: get rid of useless

Not true: you may have non-connexe CFG and loops with no exit.

pips_assert("We still have at least one successor", gen_length(*succs)>0);

Parameters
partitionartition
complement_pomplement_p

Definition at line 1181 of file bourdoncle.c.

1184 {
1185  list * succs = &control_successors(c);
1186 
1187  pips_assert("We have at least one successor", gen_length(*succs)>0);
1188 
1189  if(gen_length(*succs)==1) {
1190  control c = CONTROL(CAR(*succs));
1191  /* The CFG may not be connexe or the exit path may be hidden by a STOP statement */
1192  /*
1193  pips_assert("The unique successor must be in partition",
1194  gen_in_list_p(c, partition)==!complement_p);
1195  */
1196  if(gen_in_list_p(c, partition)==complement_p) {
1197  if(complement_p)
1198  gen_list_and_not(succs, partition);
1199  else
1200  gen_list_and(succs, partition);
1201  }
1202  }
1203  else if (control_test_p(c)) {
1204  /* Let's boldy assume the parent control node is used as a CFG test
1205  statement and preserve the number of successors. */
1206  MAPL(succ_c, {
1207  control succ = CONTROL(CAR(succ_c));
1208 
1209  if(gen_in_list_p(succ, partition)==complement_p)
1211  } , *succs);
1212  }
1213  else {
1214  /* It is not a CFG test node: get rid of useless */
1215  if(complement_p)
1216  gen_list_and_not(succs, partition);
1217  else
1218  gen_list_and(succs, partition);
1219  }
1220  /* Not true: you may have non-connexe CFG and loops with no exit. */
1221  /* pips_assert("We still have at least one successor", gen_length(*succs)>0); */
1222 }
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963

References CAR, CONS, CONTROL, CONTROL_, control_successors, control_test_p(), gen_in_list_p(), gen_length(), gen_list_and(), gen_list_and_not(), make_meaningless_control(), MAPL, NIL, and pips_assert.

Referenced by intersect_successors_with_partition(), and intersect_successors_with_partition_complement().

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

◆ make_meaningless_control()

static control make_meaningless_control ( list  preds,
list  succs 
)
static

With non-deterministic graph, the outcome of a test may be known in advance.

Never taken branches are filled in with meaningless nodes.

Definition at line 146 of file bourdoncle.c.

147 {
148  control c = make_control(statement_undefined, preds, succs);
149  pips_assert("A meaningless control has no successors", ENDP(succs));
150  return c;
151 }
#define statement_undefined
Definition: ri.h:2419

References ENDP, make_control(), pips_assert, and statement_undefined.

Referenced by add_test_successor(), clean_up_embedding_graph(), intersect_successors_with_partition_or_complement(), partition_to_unstructured(), and update_successors_of_predecessor().

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

◆ meaningless_control_p()

◆ node_to_linked_nodes()

static list node_to_linked_nodes ( control  c)
static

Allocate a list of control nodes transitively linked to control c.

Definition at line 626 of file bourdoncle.c.

627 {
628  list l = list_undefined;
629 
630  pips_debug(8, "Linked nodes for vertex %p:\n", c);
631  pips_assert("The embedding control list is NIL", embedding_control_list == NIL);
632 
637 
638  ifdebug(8) {
639  pips_debug(8, "End with list:\n");
641  }
642 
643  return l;
644 }
void add_control_to_embedding_control_list(control c)
Definition: bourdoncle.c:535

References add_control_to_embedding_control_list(), control_domain, embedding_control_list, gen_false(), gen_multi_recurse(), gen_null(), gen_true(), ifdebug, list_undefined, NIL, pips_assert, pips_debug, print_control_nodes(), and statement_domain.

Referenced by clean_up_embedding_graph(), scc_to_dag(), and update_partition().

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

◆ one_successor_kind_only_p()

bool one_successor_kind_only_p ( control  c,
bool  true_p 
)

useful for non-deterministic control flow graph only

There exists at least one real successor of the requested kind and only meaningless successors of the other kind.

Parameters
true_prue_p

Definition at line 2451 of file bourdoncle.c.

2452 {
2453  bool one_kind_only_p = false;
2454  bool is_true_successor_p = true;
2455  bool real_successor_found_p = false;
2456  list succs = control_successors(c);
2457 
2458  pips_assert("c is a test", control_test_p(c));
2459 
2460  MAP(CONTROL, s, {
2461  if(is_true_successor_p && true_p) {
2462  real_successor_found_p |= !meaningless_control_p(s);
2463  }
2464  else {
2465  one_kind_only_p &= meaningless_control_p(s);
2466  }
2467  }, succs);
2468 
2469  one_kind_only_p &= real_successor_found_p;
2470 
2471  return one_kind_only_p;
2472 }

References CONTROL, control_successors, control_test_p(), MAP, meaningless_control_p(), and pips_assert.

Referenced by false_successors_only_p(), and true_successors_only_p().

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

◆ partition_successor_p()

static bool partition_successor_p ( control  b,
control  e,
list  partition 
)
static

FUNCTIONS FOR BOURDONCLE_COMPONENT()

Check the existence of a path from b to e with all its element in partition

You might be interested in the existence of a cycle from b to b

pips_assert("b is not e", b!=e);

Definition at line 2015 of file bourdoncle.c.

2016 {
2017  bool path_p = false;
2018  list preds = CONS(CONTROL, b, NIL);
2019  list succs = NIL;
2020  list not_seen = gen_copy_seq(partition);
2021  int length = 0;
2022 
2023  pips_debug(3, "Begin with b=%p abd e=%p\n", b, e);
2024 
2025  ifdebug(3) {
2026  pips_assert("b is in partition", gen_in_list_p(b, partition));
2027  pips_assert("e is in partition", gen_in_list_p(e, partition));
2028  /* You might be interested in the existence of a cycle from b to b */
2029  /* pips_assert("b is not e", b!=e); */
2030  }
2031 
2032  gen_remove(&not_seen, b);
2033 
2034  while(!ENDP(preds)){
2035  length++;
2036  pips_debug(3, "Iteration %d\n", length);
2037  MAP(CONTROL, pred, {
2038  pips_debug(3, "\tpred=%p\n", pred);
2039  MAP(CONTROL, succ, {
2040  pips_debug(3, "\t\tsucc=%p\n", succ);
2041  if(succ==e) {
2042  path_p = true;
2043  goto end;
2044  }
2045  else if(gen_in_list_p(succ, not_seen)) {
2046  gen_remove(&not_seen, succ);
2047  succs = CONS(CONTROL, succ, succs);
2048  }
2049  } , control_successors(pred));
2050  } , preds);
2051  gen_free_list(preds);
2052  preds = succs;
2053  succs = NIL;
2054  }
2055 
2056  end:
2057  gen_free_list(not_seen);
2058  gen_free_list(preds);
2059  gen_free_list(succs);
2060 
2061  pips_debug(3, "End: path_p=%s\n", bool_to_string(path_p));
2062 
2063  return path_p;
2064 }
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
char end
Definition: gtk_status.c:82

References bool_to_string(), CONS, CONTROL, control_successors, end, ENDP, gen_copy_seq(), gen_free_list(), gen_in_list_p(), gen_remove(), ifdebug, MAP, NIL, pips_assert, and pips_debug.

Referenced by update_partition().

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

◆ partition_to_unstructured()

unstructured partition_to_unstructured ( control  vertex,
list  partition 
)

Build a new unstructured (CFG) for partition.

vertex is the entry and exit point. New nodes must be allocated because the parent graph is untouched. vertex is supposed to be included into partition.

Create the translation table replicate_map

Generate new unstructured with relevant entry and exit node vertex

Update arcs

Update predecessors

The only predecessors that are useful are in partition

This predecessor is irrelevant

Handle successors

This successor is irrelevant but irrelevant true branches must be preserved

A second irrelevant successor is not needed. But are we ready to have IF nodes with only one successor?

useless = CONS(CONTROL, old_c, useless);

Parameters
vertexertex
partitionartition

Definition at line 1053 of file bourdoncle.c.

1054 {
1056  list useless = NIL;
1057 
1059 
1060  /* Create the translation table replicate_map */
1061  MAP(CONTROL, c,
1062  {
1063  (void) control_shallow_copy(c);
1064  }
1065  , partition);
1066 
1067  /* Generate new unstructured with relevant entry and exit node vertex */
1070 
1071  /* Update arcs */
1072 
1073  /* Update predecessors */
1074  MAP(CONTROL, c,
1075  {
1076  control c_new = control_to_replicate(c);
1077 
1078  /* The only predecessors that are useful are in partition */
1079  MAPL(c_c,
1080  {
1081  control old_c = CONTROL(CAR(c_c));
1082  control new_c = control_undefined;
1083 
1084  if(gen_in_list_p(old_c, partition)) {
1085  new_c = hash_get(replicate_map, (void *) old_c);
1086  pips_assert("new_c is defined", new_c!=(control) HASH_UNDEFINED_VALUE);
1087  CONTROL_(CAR(c_c)) = new_c;
1088  }
1089  else {
1090  /* This predecessor is irrelevant */
1091  useless = CONS(CONTROL, old_c, useless);
1092  }
1093  }
1094  , control_predecessors(c_new));
1095 
1098  useless = NIL;
1099 
1100  /* Handle successors */
1101  MAPL(c_c,
1102  {
1103  control old_c = CONTROL(CAR(c_c));
1104  control new_c = control_undefined;
1105 
1106  if(gen_in_list_p(old_c, partition)) {
1107  new_c = hash_get(replicate_map, (void *) old_c);
1108  pips_assert("new_c is defined",
1109  new_c!=(control) HASH_UNDEFINED_VALUE);
1110  }
1111  else {
1112  pips_assert("If a successor is not in partition,"
1113  " then there must be two successors",
1114  gen_length(control_successors(c_new))==2);
1115  /* This successor is irrelevant but irrelevant true branches must
1116  be preserved */
1117  if(c_c==control_successors(c_new)) {
1118  pips_assert("The second successor is in partition and has been copied",
1119  gen_in_list_p(CONTROL(CAR(CDR(c_c))),partition) );
1120  new_c = make_meaningless_control(CONS(CONTROL, c_new, NIL), NIL);
1121  }
1122  else {
1123  /* A second irrelevant successor is not needed. But are we ready
1124  to have IF nodes with only one successor? */
1125  /* useless = CONS(CONTROL, old_c, useless); */
1126  new_c = make_meaningless_control(CONS(CONTROL, c_new, NIL), NIL);
1127  }
1128  }
1129 
1130  if(!control_undefined_p(new_c))
1131  CONTROL_(CAR(c_c)) = new_c;
1132  }
1133  , control_successors(c_new));
1134  }
1135  , partition);
1136 
1137  /*
1138  control_predecessors(c_new) = gen_list_and_not(control_predecessors(c_new), useless);
1139  gen_free_list(useless);
1140  useless = NIL;
1141  */
1142 
1145 
1146  return new_u;
1147 }
unstructured make_unstructured(control a1, control a2)
Definition: ri.c:2778
static control control_to_replicate(control old_c)
Definition: bourdoncle.c:1002
control control_shallow_copy(control c)
Definition: bourdoncle.c:970
#define hash_table_undefined
Value of an undefined hash_table.
Definition: newgen_hash.h:49
#define control_undefined_p(x)
Definition: ri.h:917

References CAR, CDR, CONS, CONTROL, CONTROL_, control_predecessors, control_shallow_copy(), control_successors, control_to_replicate(), control_undefined, control_undefined_p, gen_free_list(), gen_in_list_p(), gen_length(), gen_list_and_not(), hash_get(), hash_pointer, hash_table_free(), hash_table_make(), hash_table_undefined, HASH_UNDEFINED_VALUE, make_meaningless_control(), make_unstructured(), MAP, MAPL, NIL, pips_assert, replicate_map, unstructured_undefined, and useless().

+ Here is the call graph for this function:

◆ print_and_check_control_node()

static void print_and_check_control_node ( control  c,
bool  check_p 
)
static

Definition at line 276 of file bourdoncle.c.

277 {
278  fprintf(stderr,
279  "ctr %p, %zd preds, %zd succs: %s",
280  c,
284  fprintf(stderr,"\tsuccessors:\n");
285  MAP(CONTROL, s, {
286  fprintf(stderr, "\t\t%p %s", s,
288  }, control_successors(c));
289  fprintf(stderr,"\tpredecessors:\n");
290  MAP(CONTROL, p, {
291  fprintf(stderr, "\t\t%p %s", p,
293  }, control_predecessors(c));
294  fprintf(stderr, "\n");
295  if(check_p)
296  (void) check_control_statement(c);
297 }
string safe_statement_identification(statement)
Definition: statement.c:1726

References check_control_statement(), CONTROL, control_predecessors, control_statement, control_successors, fprintf(), gen_length(), MAP, and safe_statement_identification().

Referenced by print_control_node_b(), and print_control_node_without_check().

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

◆ print_control_node_b()

static void print_control_node_b ( control  c)
static

Definition at line 299 of file bourdoncle.c.

300 {
302 }
static void print_and_check_control_node(control c, bool check_p)
Definition: bourdoncle.c:276

References print_and_check_control_node().

Referenced by bourdoncle_component(), print_embedding_graph(), print_unstructured(), registered_controls_p(), scc_to_dag(), and update_successor_in_copy().

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

◆ print_control_node_without_check()

static void print_control_node_without_check ( control  c)
static

Code partly replicated from semantics/unstructured.c to be able to taylor it to the exact needs.

Definition at line 304 of file bourdoncle.c.

305 {
307 }

References print_and_check_control_node().

Referenced by check_control_statement(), and update_successor_in_copy().

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

◆ print_control_nodes_without_check()

static void print_control_nodes_without_check ( list  l)
static

Was moved into ri-util/control, minus the check_control_statement()

Definition at line 322 of file bourdoncle.c.

323 {
324  MAP(CONTROL, c, {
325  fprintf(stderr, "%p, %s", c,
327  }, l);
328  fprintf(stderr, "\n");
329 }

References CONTROL, control_statement, fprintf(), MAP, and safe_statement_identification().

Referenced by update_successors_of_predecessor().

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

◆ print_control_to_control_mapping()

static void print_control_to_control_mapping ( string  message,
hash_table  map 
)
static

Definition at line 823 of file bourdoncle.c.

824 {
825  fprintf(stderr, "%s\n", message);
826  HASH_MAP(c1, c2,
827  {
828  fprintf(stderr, "%p -> %p\n", c1, c2);
829  }
830  , map);
831  fprintf(stderr, "\n");
832 }

References fprintf(), and HASH_MAP.

Referenced by ancestor_map_consistent_p(), and scc_to_dag().

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

◆ print_embedding_graph()

static void print_embedding_graph ( control  c,
string  msg 
)
static

Do not go down into nested unstructured

Check its structure: make sure that each node is a successor of its predecessors and a predecessor of all its successors

Make sure that no meaningful node only has meaningless successors

Make sure that no node has any meaningless predecessor

Make sure that destructured test statements always have two successors... not ture anymore with non-determinacy.

Definition at line 540 of file bourdoncle.c.

541 {
542  ifdebug(2) {
543  bool consistent_embedding_graph_p = true;
544 
545  pips_debug(2, "Embedding graph for vertex %p:\n", c);
546  /* Do not go down into nested unstructured */
549 
550  /* Check its structure: make sure that each node is a successor of its
551  predecessors and a predecessor of all its successors */
552  pips_assert("The embedding control list is NIL", embedding_control_list == NIL);
555  MAP(CONTROL, ec, {
556  MAP(CONTROL, pred, {
557  if(!gen_in_list_p(ec, control_successors(pred))){
558  consistent_embedding_graph_p = false;
559  fprintf(stderr, "Control %p is a predecessor of control %p "
560  "but control %p is not a successor of control %p\n",
561  pred, ec, ec, pred);
562  }
563 
564  }
565  , control_predecessors(ec));
566  MAP(CONTROL, succ, {
567  if(!gen_in_list_p(ec, control_predecessors(succ))){
568  consistent_embedding_graph_p = false;
569  fprintf(stderr, "Control %p is a successor of control %p "
570  "but control %p is not a predecessor of control %p\n",
571  succ, ec, ec, succ);
572  }
573 
574  }
575  , control_successors(ec));
576  }
578 
579  /* Make sure that no meaningful node only has meaningless successors */
580  MAP(CONTROL, ec, {
581  if(!meaningless_control_p(ec)) {
582  bool meaningless_p = !ENDP(control_successors(ec));
583 
584  MAP(CONTROL, succ, {
585  if(!meaningless_control_p(succ)) {
586  meaningless_p = false;
587  }
588  }, control_successors(ec));
589 
590  if(meaningless_p) {
591  consistent_embedding_graph_p = false;
592  fprintf(stderr, "Control %p only has meaningless successors\n",
593  ec);
594  }
595  }
597 
598  /* Make sure that no node has any meaningless predecessor */
599  MAP(CONTROL, ec, {
600  MAP(CONTROL, pred, {
601  if(meaningless_control_p(pred)) {
602  consistent_embedding_graph_p = false;
603  fprintf(stderr, "Control %p has meaningless predecessor %p\n",
604  ec, pred);
605  }
606  }, control_predecessors(ec));
608 
609  /* Make sure that destructured test statements always have two
610  successors... not ture anymore with non-determinacy. */
611  MAP(CONTROL, ec, {
612  (void) check_control_statement(ec);
614 
616 
617  pips_assert("The embedding graph is consistent", consistent_embedding_graph_p);
618 
621  pips_debug(2, "End: the embedding graph for vertex %p is consistent.\n", c);
622  }
623 }
static void davinci_print_control_nodes(list l, string msg)
Definition: bourdoncle.c:433

References add_control_to_embedding_control_list(), check_control_statement(), CONTROL, control_domain, control_predecessors, control_successors, davinci_print_control_nodes(), embedding_control_list, ENDP, fprintf(), gen_false(), gen_free_list(), gen_in_list_p(), gen_multi_recurse(), gen_null(), gen_true(), ifdebug, MAP, meaningless_control_p(), NIL, pips_assert, pips_debug, print_control_node_b(), and statement_domain.

Referenced by scc_to_dag().

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

◆ print_replicate_map()

static void print_replicate_map ( )
static

Definition at line 959 of file bourdoncle.c.

960 {
961  fprintf(stderr,"\nDump of replicate_map:\n");
962  HASH_MAP(old_c, new_c,
963  {
964  fprintf(stderr, "Old %p -> New %p\n", old_c, new_c);
965  }
966  , replicate_map);
967  fprintf(stderr,"\n");
968 }

References fprintf(), HASH_MAP, and replicate_map.

Referenced by unstructured_shallow_copy().

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

◆ print_unstructured()

static void print_unstructured ( unstructured  u)
static

Do not go down into nested unstructured

Definition at line 331 of file bourdoncle.c.

332 {
333  pips_debug(2, "Unstructured %p with nodes:\n", u);
334  /* Do not go down into nested unstructured */
337  pips_debug(2, "With entry nodes\n");
339  pips_debug(2, "And exit node\n");
341 }

References control_domain, gen_false(), gen_multi_recurse(), gen_null(), gen_true(), pips_debug, print_control_node_b(), statement_domain, unstructured_control, and unstructured_exit.

Referenced by bourdoncle_partition().

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

◆ proper_cycle_head_p()

bool proper_cycle_head_p ( control  c,
hash_table  scc_map 
)

This node is really the head of a cycle (red on daVinci pictures).

Parameters
scc_mapcc_map

Definition at line 2405 of file bourdoncle.c.

2406 {
2407  bool is_proper_cycle_head_p = false;
2408 
2409  HASH_MAP(n, u,
2410  {
2411  unstructured scc_u = (unstructured) u;
2412 
2413  if((control)c==unstructured_control(scc_u)) {
2414  is_proper_cycle_head_p = true;
2415  break;
2416  }
2417  }, scc_map);
2418  return is_proper_cycle_head_p;
2419 }
struct _newgen_struct_unstructured_ * unstructured
Definition: ri.h:447

References HASH_MAP, and unstructured_control.

Referenced by replicate_cycles().

+ Here is the caller graph for this function:

◆ proper_cycle_head_to_scc()

unstructured proper_cycle_head_to_scc ( control  h,
hash_table  scc_map 
)

Retrieve a scc_u from its head.

Parameters
scc_mapcc_map

Definition at line 2368 of file bourdoncle.c.

2369 {
2371 
2372  HASH_MAP(k_c, v_scc_u, {
2373  unstructured scc_u = (unstructured) v_scc_u;
2374 
2375  if(h==unstructured_control(scc_u)) {
2376  r_scc_u = scc_u;
2377  break;
2378  }
2379  }, scc_map);
2380 
2381  return r_scc_u;
2382 }

References HASH_MAP, unstructured_control, and unstructured_undefined.

Referenced by dag_to_flow_sensitive_preconditions().

+ Here is the caller graph for this function:

◆ registered_controls_p()

static bool registered_controls_p ( hash_table  ancestor_map,
list  l 
)
static

Definition at line 882 of file bourdoncle.c.

883 {
884  bool registered_p = true;
885 
886  MAP(CONTROL, c,
887  {
888  if(!meaningless_control_p(c)) {
889  if(hash_get(ancestor_map, c)==HASH_UNDEFINED_VALUE) {
890  if(!ancestor_control_p(ancestor_map, c)) {
891  ifdebug(2) {
892  pips_debug(2, "Control %p is not registered:\n", c);
894  }
895  registered_p = false;
896  }
897  }
898  }
899  }
900  , l);
901  return registered_p;
902 }

References ancestor_control_p(), CONTROL, hash_get(), HASH_UNDEFINED_VALUE, ifdebug, MAP, meaningless_control_p(), pips_debug, and print_control_node_b().

Referenced by scc_to_dag().

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

◆ replicate_cycles()

static void replicate_cycles ( unstructured  u_main,
hash_table  scc_map,
hash_table  ancestor_map 
)
static

Only the head of the main unstructured can be a pointer to a cycle. The head of a scc cannot point to another scc as they would be the same by construction: all their cycles would be cut off by the head of each scc.

Only live scc are useful

we really need a shallow_free_unstructured()

free_unstructured(u_u);

Definition at line 1803 of file bourdoncle.c.

1804 {
1805  list scc_to_process = CONS(UNSTRUCTURED, u_main, NIL);
1806  list scc_to_process_next = NIL;
1807  list live_scc = NIL;
1808  int replication_number = 0;
1809  int deletion_number = 0;
1810 
1811  pips_debug(1, "Start with %d cycles for unstructured %p with entry %p\n",
1812  hash_table_entry_count(scc_map), u_main, unstructured_control(u_main));
1813 
1814  while(!ENDP(scc_to_process)) {
1815  MAP(UNSTRUCTURED, u, {
1816  list nl = NIL;
1817  control root = unstructured_control(u);
1818  FORWARD_CONTROL_MAP(c, {
1819  /* Only the head of the main unstructured can be a pointer to a
1820  cycle. The head of a scc cannot point to another scc as they
1821  would be the same by construction: all their cycles would be
1822  cut off by the head of each scc. */
1823  if((c!=root || c==unstructured_control(u_main))
1824  && !meaningless_control_p(c)
1825  && cycle_head_p((control)c, ancestor_map, scc_map)) {
1826  control a = control_to_ancestor(c, ancestor_map);
1827  unstructured scc_u = ancestor_cycle_head_to_scc((control)a, scc_map);
1828 
1829  unstructured scc_u_c = unstructured_shallow_copy(scc_u, ancestor_map);
1830  scc_to_process_next = CONS(UNSTRUCTURED, scc_u_c, scc_to_process_next);
1831  hash_put(scc_map, c, (void *) scc_u_c);
1832  replication_number++;
1833 
1834  ifdebug(1) {
1835  control e = unstructured_control(scc_u_c);
1836  pips_debug(1, "New scc %p with entry %p for node %p copy of ancestor node %p\n",
1837  scc_u_c, e, c, control_to_ancestor(c, ancestor_map));
1838  pips_assert("e is a proper cycle head", proper_cycle_head_p(e, scc_map));
1839  pips_assert("e is a cycle head", cycle_head_p(e, ancestor_map, scc_map));
1840  pips_assert("e is a not a direct cycle head",
1841  !direct_cycle_head_p(e, scc_map));
1842  }
1843 
1844  }
1845  }, root, nl);
1846  gen_free_list(nl);
1847  }, scc_to_process);
1848  live_scc = gen_nconc(live_scc, scc_to_process);
1849  scc_to_process = scc_to_process_next;
1850  scc_to_process_next = NIL;
1851  }
1852 
1853  /* Only live scc are useful */
1854  HASH_MAP(c, scc, {
1855  if(!gen_in_list_p(scc, live_scc)) {
1856  void * key = NULL;
1858  u_u = (unstructured) hash_delget(scc_map, (void *) c, (void **) &key);
1859  if(unstructured_undefined_p(u_u)) {
1860  pips_internal_error("No scc for control %p", c);
1861  }
1862  else {
1863  /* we really need a shallow_free_unstructured() */
1864  /* free_unstructured(u_u); */
1865  pips_debug(1, "scc %p unlinked from node %p\n", u_u, c);
1866  deletion_number++;
1867  }
1868  }
1869  }, scc_map);
1870 
1871  pips_assert("The number of scc's has increased",
1872  replication_number >= deletion_number);
1873 
1874  gen_free_list(live_scc);
1875 
1876  pips_debug(1, "End replication process with %d copies and %d deletions\n",
1877  replication_number, deletion_number);
1878 
1879  pips_debug(1, "Start with %d cycles\n", hash_table_entry_count(scc_map));
1880 }
bool direct_cycle_head_p(control c, hash_table scc_map)
This node is directly associated to a specific cycle.
Definition: bourdoncle.c:2422
bool proper_cycle_head_p(control c, hash_table scc_map)
This node is really the head of a cycle (red on daVinci pictures).
Definition: bourdoncle.c:2405
#define FORWARD_CONTROL_MAP(ctl, code, c, list)
Walk through all the controls forward-reachable from a given control node of an unstructured.
void * hash_delget(hash_table htp, const void *key, void **pkey)
deletes key from the hash table.
Definition: hash.c:398
#define UNSTRUCTURED(x)
UNSTRUCTURED.
Definition: ri.h:2974

References ancestor_cycle_head_to_scc(), CONS, control_to_ancestor(), cycle_head_p(), direct_cycle_head_p(), ENDP, FORWARD_CONTROL_MAP, gen_free_list(), gen_in_list_p(), gen_nconc(), hash_delget(), HASH_MAP, hash_put(), hash_table_entry_count(), ifdebug, MAP, meaningless_control_p(), NIL, pips_assert, pips_debug, pips_internal_error, proper_cycle_head_p(), UNSTRUCTURED, unstructured_control, unstructured_shallow_copy(), unstructured_undefined, and unstructured_undefined_p.

Referenced by bourdoncle_partition().

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

◆ reset_dfn()

static void reset_dfn ( control  c)
static

Definition at line 106 of file bourdoncle.c.

107 {
108  hash_put(dfn, (void *) c, (void *) 0);
109 }

References dfn, and hash_put().

Referenced by bourdoncle_partition().

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

◆ scc_to_dag()

static unstructured scc_to_dag ( control  root,
list  partition,
hash_table  ancestor_map 
)
static

The nodes in scc partition but root must be removed.

Replicated nodes must be added to build all input and output paths to and from root using control nodes in partition.

This is the key change to Bourdoncle's algorithm. When moving back up in the recursion, the CFG is altered to obtain pure cycles with only one entry and one exit nodes.

The cycle head must be a non-deterministic control node. Hence it cannot be a test since tests stay deterministics (thanks to Pierre's data structure). Another node in the partition could be chosen as new cycle head, but the partition may only contain tests with side effects. Instead we choose to insert a non-deterministic node in front in case it is needed. The initial CFG is less disturbed.

Well, I changed my mind again because inserting new control nodes does not make it easy to stay compatible with Bourdoncle's algorithm and previous assumptions made about the cycle head. Instead, tests can become non-deterministic. The number of successors must be even or odd. Odd successors are true successors. Even successors are false successors.

Look for new input nodes in partition

c cannot have been replicated earlier or it would not be in partition

Keep only predecessors out of partition for new_c1.

Make sure that new_c1 is a successor of its predecessors... Oupss, there is a problem with test to encode the fact that is is a true or a false successor?

Keep only c's predecessors in partition.

That's probably wrong and damaging because we need them for paths crossing directly the SCC and useless because these nodes will be destroyed in parent graph.

Update the successor of its predecessors

Update successors of new_c1 which have already been replicated

Add new_c1 as predecessor of new_succ

Look for new output nodes

c cannot have been replicated earlier or it would not be in partition

Keep only successors out of partition for new_c2.

A true branch successor may have to be replaced to preserve the position of the false branch successor.

gen_list_and_not(&control_successors(new_c2), partition);

Update reverse arcs

Keep only c's succcessors in partition. Wise or not? See above...

gen_list_and(&control_successors(c), partition);

Reverse arcs have already been correctly updated

Update predecessors of new_c2 which have already been replicated

gen_list_patch() has no effect because new_pred's successors have already been updated and c does not appear there.

gen_list_patch(control_successors(new_pred), c, new_c2);

Update reverse edges of predecessors... which may be tough if you end up with more than one true and/or more than one false successor.

Remove cycle partition but its head

We do not want to free these nodes because they are part of partition. We should not have duplicated partition earlier to make a new unstructured. We only need a copy of the head, root. This should be dealt with after scc_to_dag is called and not before.

MAP(CONTROL, c, { if(c!=root) { shallow_free_control(c); } } , partition);

Unlink partition from its head. We could keep an arc from root to root...

This unlinking would better be performed at the caller level, even though this would make the name scc_to_dag() imprecise.

replicate root and unlink the cycles defined by partition from the embedding graph

new_root does not belong to partition and must be processed too.

All nodes are linked to an ancestor node or are an ancestor or are meaningless

Definition at line 1465 of file bourdoncle.c.

1466 {
1468  control new_root = control_undefined;
1469  hash_table replicated_input_controls = hash_table_make(hash_pointer, 0);
1470  hash_table replicated_output_controls = hash_table_make(hash_pointer, 0);
1471  bool stable_graph_p = false;
1472  int number_in = 0;
1473  int number_out = 0;
1474  int iteration = 0;
1475  char msg[200];
1476 
1477  ifdebug(3) {
1478  pips_debug(3, "Begin for vertex %p and partition:\n", root);
1479  print_control_nodes(partition);
1480  }
1481 
1482  while(!stable_graph_p) {
1483  int number = 0;
1484  list c_c = list_undefined;
1485 
1486  stable_graph_p = true;
1487  iteration++;
1488 
1489  /* Look for new input nodes in partition */
1490  for(c_c = partition; !ENDP(c_c); POP(c_c)) {
1491  control c = CONTROL(CAR(c_c));
1492 
1493  if(c!=root && hash_get(replicated_input_controls, c)==HASH_UNDEFINED_VALUE) {
1494  if(entry_control_p(c, partition)) {
1495  control new_c1 = control_undefined;
1496 
1497  /* c cannot have been replicated earlier or it would not be in partition */
1498  pips_assert("c has not yet been input replicated",
1499  hash_get(replicated_input_controls, c)==HASH_UNDEFINED_VALUE);
1500  new_c1 = make_control(control_statement(c),
1503  add_child_parent_pair(ancestor_map, new_c1, c);
1504  copy_dfn(new_c1, c);
1505 
1506  pips_debug(4, "Allocate new input control node new_c1=%p"
1507  " as a copy of node %p with depth %td\n",
1508  new_c1, c, get_dfn(c));
1509 
1510  /* Keep only predecessors out of partition for new_c1. */
1511  gen_list_and_not(&control_predecessors(new_c1), partition);
1512  /* Make sure that new_c1 is a successor of its
1513  predecessors... Oupss, there is a problem with test to encode
1514  the fact that is is a true or a false successor? */
1515  MAP(CONTROL, pred_c1, {
1516  gen_list_patch(control_successors(pred_c1), c, new_c1);
1517  },control_predecessors(new_c1) );
1518 
1519 
1520  /* Keep only c's predecessors in partition.
1521 
1522  That's probably wrong and damaging because we need them for
1523  paths crossing directly the SCC and useless because these
1524  nodes will be destroyed in parent graph. */
1525  gen_list_and(&control_predecessors(c), partition);
1526  /* Update the successor of its predecessors */
1527 
1528  /* Update successors of new_c1 which have already been replicated */
1529  MAPL(succ_new_c1_c,
1530  {
1531  control succ_new_c1 = CONTROL(CAR(succ_new_c1_c));
1532  control new_succ_new_c1 = hash_get(replicated_input_controls, succ_new_c1);
1533  if(new_succ_new_c1!=HASH_UNDEFINED_VALUE) {
1534  CONTROL_(CAR(succ_new_c1_c)) = new_succ_new_c1;
1535  /* Add new_c1 as predecessor of new_succ */
1536  control_predecessors(new_succ_new_c1) =
1537  gen_once(new_c1, control_predecessors(new_succ_new_c1));
1538  }
1539  else {
1540  update_predecessors_of_successor(succ_new_c1, new_c1, c);
1541  }
1542  }
1543  , control_successors(new_c1));
1544 
1545  stable_graph_p = false;
1546  number++;
1547  number_in++;
1548  hash_put(replicated_input_controls, c, new_c1);
1549  }
1550  }
1551  }
1552 
1553  ifdebug(9) {
1554  if(number>0) {
1555  pips_debug(4, "Embedding graph after replication"
1556  " of %d input control node(s) at iteration %d:\n",
1557  number, iteration);
1558  sprintf(msg, "Embedding graph after replication"
1559  " of %d input control node(s) at iteration %d:",
1560  number, iteration);
1561  print_embedding_graph(root, msg);
1562  pips_debug(4, "End of embedding graph after replication"
1563  " of input control nodes\n");
1564  }
1565  else {
1566  pips_debug(4, "No new input control node at iteration %d\n",
1567  iteration);
1568  }
1569  }
1570 
1571  /* Look for new output nodes */
1572  number = 0;
1573  for(c_c = partition; !ENDP(c_c); POP(c_c)) {
1574  control c = CONTROL(CAR(c_c));
1575 
1576  if(c!=root && hash_get(replicated_output_controls, c)==HASH_UNDEFINED_VALUE) {
1577  if(exit_control_p(c, partition)) {
1578  control new_c2 = control_undefined;
1579  list pred_new_c2_c = list_undefined;
1580 
1581  /* c cannot have been replicated earlier or it would not be in partition */
1582  pips_assert("c has not yet been output replicated",
1583  hash_get(replicated_output_controls, c)==HASH_UNDEFINED_VALUE);
1584  new_c2 = make_control(control_statement(c),
1587  add_child_parent_pair(ancestor_map, new_c2, c);
1588  copy_dfn(new_c2, c);
1589 
1590  pips_debug(4, "Allocate new output control node new_c2=%p as a copy of node %p\n",
1591  new_c2, c);
1592 
1593  /* Keep only successors out of partition for new_c2. */
1594  /* A true branch successor may have to be replaced to preserve
1595  the position of the false branch successor. */
1596  /* gen_list_and_not(&control_successors(new_c2), partition); */
1598 
1599  /* Update reverse arcs */
1600  MAP(CONTROL, succ_c2, {
1601  gen_list_patch(control_predecessors(succ_c2), c, new_c2);
1602  }, control_successors(new_c2) );
1603 
1604  /* Keep only c's succcessors in partition. Wise or not? See above... */
1605  /* gen_list_and(&control_successors(c), partition); */
1607  /* Reverse arcs have already been correctly updated */
1608 
1609  /* Update predecessors of new_c2 which have already been replicated */
1610  for(pred_new_c2_c=control_predecessors(new_c2);
1611  !ENDP(pred_new_c2_c); POP(pred_new_c2_c)) {
1612  control pred_new_c2 = CONTROL(CAR(pred_new_c2_c));
1613  control new_pred_new_c2 = hash_get(replicated_output_controls, pred_new_c2);
1614  if(new_pred_new_c2!=HASH_UNDEFINED_VALUE) {
1615  /* gen_list_patch() has no effect because new_pred's
1616  successors have already been updated and c does not
1617  appear there. */
1618  /* gen_list_patch(control_successors(new_pred), c, new_c2); */
1619  update_successor_in_copy(new_pred_new_c2, pred_new_c2, c, new_c2);
1620  /*
1621  CONTROL(CAR(pred_new_c2_c)) = new_pred_new_c2;
1622  pips_assert("new_c2 is now consistent", check_control_statement(new_c2));
1623  */
1624  }
1625  else{
1626  /* Update reverse edges of predecessors... which may be
1627  tough if you end up with more than one true and/or more
1628  than one false successor. */
1629  update_successors_of_predecessor(pred_new_c2, new_c2, c);
1630  }
1631  }
1632  pips_assert("new_c2 is now consistent", check_control_statement(new_c2));
1633 
1634  stable_graph_p = false;
1635  number++;
1636  number_out++;
1637  hash_put(replicated_output_controls, c, new_c2);
1638  }
1639  }
1640  }
1641 
1642  ifdebug(9) {
1643  if(number>0) {
1644  pips_debug(3, "Embedding graph after replication"
1645  " of output control nodes at iteration %d:\n", iteration);
1646  sprintf(msg, "Embedding graph after replication"
1647  " of output control nodes at iteration %d:", iteration);
1648  print_embedding_graph(root, msg);
1649  pips_debug(3, "End of embedding graph after replication"
1650  " of output control nodes\n");
1651  }
1652  else {
1653  pips_debug(3, "No new output control node at iteration %d\n", iteration);
1654  }
1655  }
1656  }
1657 
1659 
1660  ifdebug(3) {
1661  if(number_out>0 || number_in>0) {
1662  pips_assert("At least two iterations", iteration>1);
1663  pips_debug(3, "Final embedding graph after replication of all input and output paths (%d iterations)\n", iteration);
1664  sprintf(msg, "Final embedding graph after replication of all input and output paths (%d iterations)", iteration);
1665  print_embedding_graph(root, msg);
1666  pips_debug(3, "End of final embedding graph after replication of all input and output paths\n");
1667  }
1668  else {
1669  pips_assert("Only one iteration", iteration==1);
1670  pips_debug(3, "No new output paths\n");
1671  }
1672  }
1673 
1674  /* Remove cycle partition but its head */
1675  /* We do not want to free these nodes because they are part of
1676  partition. We should not have duplicated partition earlier to make a
1677  new unstructured. We only need a copy of the head, root. This should
1678  be dealt with after scc_to_dag is called and not before.
1679 
1680  MAP(CONTROL, c,
1681  {
1682  if(c!=root) {
1683  shallow_free_control(c);
1684  }
1685  }
1686  , partition); */
1687  /* Unlink partition from its head.
1688  We could keep an arc from root to root... */
1689  /* This unlinking would better be performed at the caller level, even
1690  though this would make the name scc_to_dag() imprecise. */
1691 
1692  /* replicate root and unlink the cycles defined by partition from the
1693  embedding graph */
1694  new_root = make_control(control_statement(root),
1697 
1698  add_child_parent_pair(ancestor_map, new_root, root);
1699  u = make_unstructured(new_root, new_root);
1700  gen_list_and_not(&control_predecessors(root), partition);
1702  gen_list_and(&control_predecessors(new_root), partition);
1703  intersect_successors_with_partition(new_root, partition);
1704  MAP(CONTROL, c,
1705  {
1706  gen_list_patch(control_successors(c), root, new_root);
1707  gen_list_patch(control_predecessors(c), root, new_root);
1708  }
1709  , partition);
1710  /* new_root does not belong to partition and must be processed too. */
1711  gen_list_patch(control_successors(new_root), root, new_root);
1712  gen_list_patch(control_predecessors(new_root), root, new_root);
1713 
1714  ifdebug(3) {
1715  list l_root = node_to_linked_nodes(root);
1716  list l_new_root = node_to_linked_nodes(new_root);
1717 
1718  pips_debug(3, "Nodes linked to root=%p\n", root);
1719  print_control_node_b(root);
1720  print_control_nodes(l_root);
1721  pips_debug(3, "Nodes linked to new_root=%p\n", new_root);
1722  print_control_node_b(new_root);
1723  print_control_nodes(l_new_root);
1724 
1725  gen_list_and(&l_root, l_new_root);
1726 
1727  if(!ENDP(l_root)) {
1728  fprintf(stderr,
1729  "Bug: l_root and l_new_root share at least one node and must be equal\n");
1730  fprintf(stderr, "Common control nodes:\n");
1731  print_control_nodes(l_root);
1732  pips_assert("l_root and l_new_root have an empty intersection",
1733  ENDP(l_root));
1734  }
1735 
1736  gen_free_list(l_root);
1737  gen_free_list(l_new_root);
1738  }
1739 
1741 
1742  clean_up_embedding_graph(new_root);
1743 
1744  ifdebug(3) {
1745  list l_root = node_to_linked_nodes(root);
1746  list l_new_root = node_to_linked_nodes(new_root);
1747 
1748  pips_debug(3, "Final embedding graph after replication and cycle removal\n");
1749  sprintf(msg, "Final embedding graph after replication and cycle removal");
1750  print_embedding_graph(root, msg);
1751  pips_debug(3, "End of final embedding graph after replication and cycle removal\n");
1752  pips_debug(3, "Final cycle graph\n");
1753  sprintf(msg, "Final cycle graph");
1754  print_embedding_graph(new_root, msg);
1755  pips_debug(3, "End of final cycle graph\n");
1756 
1757  /* All nodes are linked to an ancestor node or are an ancestor or are
1758  meaningless */
1759  pips_assert("All nodes in l_root are registered",
1760  registered_controls_p(ancestor_map, l_root));
1761  pips_assert("All nodes in l_new_root are registered",
1762  registered_controls_p(ancestor_map, l_new_root));
1763  pips_assert("Children and ancestors have an empty intersection",
1764  ancestor_map_consistent_p(ancestor_map));
1765 
1766  gen_free_list(l_root);
1767  gen_free_list(l_new_root);
1768  }
1769 
1770  ifdebug(3) {
1771  pips_debug(3, "End with %d replicated control nodes:\n\n", number_in+number_out);
1772  if(number_in>0){
1773  print_control_to_control_mapping("replicated_input_controls",
1774  replicated_input_controls);
1775  }
1776 
1777  if(number_out>0) {
1778  print_control_to_control_mapping("replicated_output_controls",
1779  replicated_output_controls);
1780  }
1781 
1782  }
1783 
1784  hash_table_free(replicated_input_controls);
1785  hash_table_free(replicated_output_controls);
1786 
1787  ifdebug(3) {
1788  pips_debug(3, "End for vertex %p and partition:\n", root);
1789  print_control_nodes(partition);
1790  }
1791 
1792  return u;
1793 }
void intersect_successors_with_partition_complement(control c, list partition)
Definition: bourdoncle.c:1230
static bool ancestor_map_consistent_p(hash_table ancestor_map)
No control can be an ancestor and a child.
Definition: bourdoncle.c:905
static bool exit_control_p(control c, list partition)
Definition: bourdoncle.c:1172
static void update_predecessors_of_successor(control succ, control new_c, control old_c)
Definition: bourdoncle.c:1305
static void print_embedding_graph(control c, string msg)
Definition: bourdoncle.c:540
static bool registered_controls_p(hash_table ancestor_map, list l)
Definition: bourdoncle.c:882
static bool entry_control_p(control c, list partition)
Definition: bourdoncle.c:1167
static void clean_up_embedding_graph(control c)
Definition: bourdoncle.c:747
static void copy_dfn(control new_c, control old_c)
Definition: bourdoncle.c:111
static void update_successors_of_predecessor(control pred, control new_c, control old_c)
new_c is not consistent on entry and might not be on exit because it is called from within a loop
Definition: bourdoncle.c:1263
static void add_child_parent_pair(hash_table ancestor_map, control child, control parent)
Definition: bourdoncle.c:934
void intersect_successors_with_partition(control c, list partition)
Definition: bourdoncle.c:1224
static void update_successor_in_copy(control new_pred, control pred, control c, control new_c)
Make new_c a successor of new_pred, the same way c is a successor of pred.
Definition: bourdoncle.c:1381

References add_child_parent_pair(), ancestor_map_consistent_p(), CAR, check_control_statement(), clean_up_embedding_graph(), CONTROL, CONTROL_, control_predecessors, control_statement, control_successors, control_undefined, copy_dfn(), ENDP, entry_control_p(), exit_control_p(), fprintf(), gen_copy_seq(), gen_free_list(), gen_list_and(), gen_list_and_not(), gen_list_patch(), gen_once(), get_dfn(), hash_get(), hash_pointer, hash_put(), hash_table_free(), hash_table_make(), HASH_UNDEFINED_VALUE, ifdebug, intersect_successors_with_partition(), intersect_successors_with_partition_complement(), list_undefined, make_control(), make_unstructured(), MAP, MAPL, node_to_linked_nodes(), pips_assert, pips_debug, POP, print_control_node_b(), print_control_nodes(), print_control_to_control_mapping(), print_embedding_graph(), registered_controls_p(), unstructured_undefined, update_predecessors_of_successor(), update_successor_in_copy(), and update_successors_of_predecessor().

Referenced by bourdoncle_component().

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

◆ set_davinci_count()

static void set_davinci_count ( )
static

Definition at line 427 of file bourdoncle.c.

428 {
429  davinci_count = 0;
430 }

References davinci_count.

Referenced by bourdoncle_partition().

+ Here is the caller graph for this function:

◆ suppress_statement_reference()

static void suppress_statement_reference ( control  c)
static

The statements were not replicated and are still pointed to by the initial unstructured.

Definition at line 2488 of file bourdoncle.c.

2489 {
2490  /* The statements were not replicated and are still pointed to by the
2491  initial unstructured. */
2493 }

References control_statement, and statement_undefined.

Referenced by bourdoncle_unstructured_free().

+ Here is the caller graph for this function:

◆ true_successors_only_p()

bool true_successors_only_p ( control  c)

Definition at line 2474 of file bourdoncle.c.

2475 {
2476  bool true_only_p = false;
2477  true_only_p = one_successor_kind_only_p(c, true);
2478  return true_only_p;
2479 }

References one_successor_kind_only_p().

Referenced by dag_to_flow_sensitive_preconditions(), and process_ready_node().

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

◆ unstructured_shallow_copy()

unstructured unstructured_shallow_copy ( unstructured  u,
hash_table  ancestor_map 
)

Do not go down into nested unstructured and replicate all control nodes

Update predecessor and successor arcs of the new control nodes to point to the new control nodes using the global conversion mapping replicate_map

Generate new unstructured with relevant entry and exit nodes

Generate ancestor_map as the inverse function of replicate_map

Parameters
ancestor_mapncestor_map

Definition at line 1009 of file bourdoncle.c.

1010 {
1012 
1013  pips_assert("replicate_map is undefined",
1015 
1017 
1018  /* Do not go down into nested unstructured and replicate all control
1019  nodes */
1022 
1024 
1025  /* Update predecessor and successor arcs of the new control nodes to
1026  point to the new control nodes using the global conversion mapping
1027  replicate_map */
1028  HASH_MAP(old_c, new_c,
1029  {
1031  }
1032  , replicate_map);
1033 
1034  /* Generate new unstructured with relevant entry and exit nodes */
1037 
1038  /* Generate ancestor_map as the inverse function of replicate_map */
1039  HASH_MAP(old_n, new_n,{
1040  add_child_parent_pair(ancestor_map, (control) new_n, (control) old_n);
1041  }, replicate_map);
1042 
1045 
1046  return new_u;
1047 }
static void print_replicate_map()
Definition: bourdoncle.c:959
static void control_translate_arcs(control c)
Definition: bourdoncle.c:982
#define hash_table_undefined_p(h)
Definition: newgen_hash.h:50

References add_child_parent_pair(), control_domain, control_shallow_copy(), control_to_replicate(), control_translate_arcs(), gen_false(), gen_multi_recurse(), gen_null(), gen_true(), HASH_MAP, hash_pointer, hash_table_free(), hash_table_make(), hash_table_undefined, hash_table_undefined_p, ifdebug, make_unstructured(), pips_assert, print_replicate_map(), replicate_map, statement_domain, unstructured_control, unstructured_exit, and unstructured_undefined.

Referenced by bourdoncle_partition(), and replicate_cycles().

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

◆ update_dfn()

static void update_dfn ( control  c,
_int  d 
)
static

Definition at line 131 of file bourdoncle.c.

132 {
133  hash_update(dfn, (void *) c, (void *) d);
134 }
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

References dfn, and hash_update().

Referenced by bourdoncle_visit().

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

◆ update_partition()

static void update_partition ( control  root,
list  partition,
hash_table  ancestor_map 
)
static

Controls in partition may have been copied and may not appear anymore in the graph embedding root. The input graph is modified to separate clean cycles with one entry-exit node, but Bourdoncle's algorithm is not aware of this.

Find a replacement for c, and hope to find only one!

pips_internal_error("No replacement for node %p", c);

This node must be eliminated since it is no longer part of the partition, probably because it has disappeared in an inner cycle.

Many possible replacements... Keep them all.

Some nodes may no longer be part of the partition because they only belonged to an inner cycle which has already been eliminated.

Unreachable controls have been found

It does not make sense to use &partition but...

Definition at line 2066 of file bourdoncle.c.

2069 {
2070  /* Controls in partition may have been copied and may not appear anymore
2071  in the graph embedding root. The input graph is modified to
2072  separate clean cycles with one entry-exit node, but Bourdoncle's
2073  algorithm is not aware of this. */
2074  list embedding_nodes = node_to_linked_nodes(root);
2075  int changes = 0;
2076  size_t eliminations = 0;
2077  list eliminated = NIL;
2078 
2079  pips_assert("The head is in the partition", gen_in_list_p(root, partition));
2080 
2081  ifdebug(2) {
2082  pips_debug(2, "Begin for partition:\n");
2083  print_control_nodes(partition);
2084  }
2085 
2086  MAPL(c_c,
2087  {
2088  control c = CONTROL(CAR(c_c));
2089  pips_assert("c is not a meaningless control node",
2090  !meaningless_control_p(c));
2091 
2092  if(!gen_in_list_p(c, embedding_nodes)) {
2093  /* Find a replacement for c, and hope to find only one! */
2094  control a = control_to_ancestor(c, ancestor_map);
2095  list replacement_list = NIL;
2096 
2097  changes++;
2098 
2099  MAP(CONTROL, c_new,
2100  {
2101  if(!meaningless_control_p(c_new)) {
2102  control a_new = control_to_ancestor(c_new, ancestor_map);
2103  if(a==a_new) {
2104  replacement_list = CONS(CONTROL, c_new, replacement_list);
2105  }
2106  }
2107 
2108  }
2109  , embedding_nodes);
2110 
2111  switch(gen_length(replacement_list)) {
2112  case 0:
2113  /* pips_internal_error("No replacement for node %p", c); */
2114  /* This node must be eliminated since it is no longer part of the
2115  partition, probably because it has disappeared in an inner
2116  cycle. */
2117  eliminated = CONS(CONTROL, CONTROL(CAR(c_c)), eliminated);
2118  break;
2119  case 1:
2120  CONTROL_(CAR(c_c)) = CONTROL(CAR(replacement_list));
2121  gen_free_list(replacement_list);
2122  break;
2123  default:
2124  /* Many possible replacements... Keep them all. */
2125  CONTROL_(CAR(c_c)) = CONTROL(CAR(replacement_list));
2126  replacement_list = gen_nconc(replacement_list, CDR(c_c));
2127  CDR(c_c) = CDR(replacement_list);
2128  CDR(replacement_list) = NIL;
2129  gen_free_list(replacement_list);
2130 
2131  /*
2132  fprintf(stderr,
2133  "Too many replacement nodes (%d) in embedding nodes for node %p\n",
2134  gen_length(replacement_list), c);
2135  print_control_node_b(c);
2136  print_control_nodes(replacement_list);
2137  pips_internal_error("Too many replacement nodes");
2138  */
2139  break;
2140  }
2141 
2142  }
2143  }
2144  , partition);
2145 
2146  ifdebug(2) {
2147  if(changes==0) {
2148  pips_debug(2, "No renaming\n");
2149  }
2150  else{
2151  pips_debug(2, "After %d renamings, new partition:\n", changes);
2152  print_control_nodes(partition);
2153  }
2154  }
2155 
2156  eliminations = gen_length(eliminated);
2157 
2158  ifdebug(2) {
2159  if(eliminations>0) {
2160  pips_debug(2, "Untranslatable control(s) to be eliminated from partition:\n");
2161  print_control_nodes(eliminated);
2162  }
2163  }
2164 
2165  /* Some nodes may no longer be part of the partition because they only
2166  belonged to an inner cycle which has already been eliminated. */
2167 
2168  MAP(CONTROL, c, {
2169  if(c==root) {
2170  pips_assert("There is a path from root to root in partition",
2171  partition_successor_p(c, root, partition));
2172  }
2173  else {
2174  if(!partition_successor_p(c, root, partition)){
2175  eliminated = gen_once(c, eliminated);
2176  }
2177  }
2178  } , partition);
2179 
2180  ifdebug(2) {
2181  if(eliminations < gen_length(eliminated)) {
2182  /* Unreachable controls have been found */
2183  pips_debug(2, "Untranslatable and unreachable control(s) to be eliminated from partition:\n");
2184  print_control_nodes(eliminated);
2185  }
2186  }
2187 
2188  /* It does not make sense to use &partition but... */
2189  pips_assert("root is the fist element in partition",
2190  CONTROL(CAR(partition))==root);
2191  pips_assert("root is not eliminated",
2192  !gen_in_list_p(root, eliminated));
2193  gen_list_and_not(&partition, eliminated);
2194 
2195  gen_free_list(eliminated);
2196 
2197  ifdebug(2) {
2198  if(eliminations==0 && changes==0) {
2199  pips_debug(2, "End with same partition (no renaming, no elimination)\n");
2200  }
2201  else if(eliminations==0){
2202  pips_debug(2, "End with renamed partition (%d renamings, no elimination)\n",
2203  changes);
2204  }
2205  else if(changes==0){
2206  pips_debug(2, "End with reduced partition (no renamings, %zd eliminations)\n",
2207  eliminations);
2208  }
2209  else{
2210  pips_debug(2, "End with new partition (%d renamings, %zd eliminations):\n",
2211  changes, eliminations);
2212  print_control_nodes(partition);
2213  }
2214  }
2215 }
static bool partition_successor_p(control b, control e, list partition)
FUNCTIONS FOR BOURDONCLE_COMPONENT()
Definition: bourdoncle.c:2015

References CAR, CDR, CONS, CONTROL, CONTROL_, control_to_ancestor(), gen_free_list(), gen_in_list_p(), gen_length(), gen_list_and_not(), gen_nconc(), gen_once(), ifdebug, MAP, MAPL, meaningless_control_p(), NIL, node_to_linked_nodes(), partition_successor_p(), pips_assert, pips_debug, and print_control_nodes().

Referenced by bourdoncle_component().

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

◆ update_predecessors_of_successor()

static void update_predecessors_of_successor ( control  succ,
control  new_c,
control  old_c 
)
static

These asserts might become wrong when intermediate CONTINUE nodes are used to carry many true and/or false successors

Definition at line 1305 of file bourdoncle.c.

1306 {
1307  /* These asserts might become wrong when intermediate CONTINUE nodes are
1308  used to carry many true and/or false successors */
1309  pips_assert("old_c is already a predecessor of succ",
1310  gen_in_list_p(old_c, control_predecessors(succ)));
1311  pips_assert("new_c is not yet a predecessor of succ",
1312  !gen_in_list_p(new_c, control_predecessors(succ)));
1313 
1314  control_predecessors(succ) = CONS(CONTROL, new_c, control_predecessors(succ));
1315 }

References CONS, CONTROL, control_predecessors, gen_in_list_p(), and pips_assert.

Referenced by scc_to_dag().

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

◆ update_successor_in_copy()

static void update_successor_in_copy ( control  new_pred,
control  pred,
control  c,
control  new_c 
)
static

Make new_c a successor of new_pred, the same way c is a successor of pred.

new_c is not consistent on entry: it points towards pred but is not a successor of pred. Also, this function is called from within a loop and new_c is onsistent only on loop exit.

new_c is not consistent, this is why this function is called!

c and new_c have pred as predecessor

new_c must have new_pred as predecessor instead

Definition at line 1381 of file bourdoncle.c.

1385 {
1386  ifdebug(3) {
1387  pips_debug(3, "Begin for new_pred=%p, pred=%p, c=%p, new_c=%p\n",
1388  new_pred, pred, c, new_c);
1389  print_control_node_b(new_pred);
1390  print_control_node_b(pred);
1392  /* new_c is not consistent, this is why this function is called! */
1394 
1395  pips_assert("pred is predecessor of new_c",
1396  gen_in_list_p(pred, control_predecessors(new_c)));
1397  }
1398 
1399  /* c and new_c have pred as predecessor */
1400  /* new_c must have new_pred as predecessor instead */
1401  pips_assert("c is a successor of pred",
1402  gen_in_list_p(c, control_successors(pred)));
1403  pips_assert("pred is a predecessor of new_c",
1404  gen_in_list_p(pred, control_predecessors(new_c)));
1405  pips_assert("pred and new_pred share the same statement",
1406  control_statement(pred) ==control_statement(new_pred));
1407  pips_assert("c and new_c share the same statement",
1408  control_statement(c) ==control_statement(new_c));
1409 
1410  if(control_test_p(pred)) {
1411  int pos = gen_position(c, control_successors(pred));
1412  bool is_true_succ = pos%2;
1413 
1414  pips_assert("The position is not zero since c is among the sucessors of pred"
1415  " (see previous assert)", pos!=0);
1416 
1417  pips_debug(4, "position=%d, is_true_succ=%d \n", pos, is_true_succ);
1418  pips_assert("pred is a test, new_pred is a test too", control_test_p(new_pred));
1419  pips_assert("pred is still a predecessor of new_c",
1420  gen_in_list_p(pred, control_predecessors(new_c)));
1421  add_test_successor(new_pred, new_c, is_true_succ);
1422  }
1423  else {
1424  control_successors(new_pred) = gen_nconc(control_successors(new_pred),
1425  CONS(CONTROL, new_c, NIL));
1426  }
1427 
1428  gen_list_patch(control_predecessors(new_c), pred, new_pred);
1429 
1430  ifdebug(3) {
1431  pips_debug(3, "End with new_pred=%p\n", new_pred);
1432  print_control_node_b(new_pred);
1433  pips_debug(3, "and pred=%p\n", pred);
1434  print_control_node_b(pred);
1435  pips_debug(3, "and c=%p\n", c);
1437  pips_debug(3, "and new_c=%p\n", new_c);
1439  }
1440 }
static void add_test_successor(control t, control new_s, bool is_true_successor)
Called from within a loop where neither t nor new_s are consistent.
Definition: bourdoncle.c:1318
int gen_position(const void *item, const list l)
Element ranks are strictly positive as for first, second, and so on.
Definition: list.c:995

References add_test_successor(), CONS, CONTROL, control_predecessors, control_statement, control_successors, control_test_p(), gen_in_list_p(), gen_list_patch(), gen_nconc(), gen_position(), ifdebug, NIL, pips_assert, pips_debug, print_control_node_b(), and print_control_node_without_check().

Referenced by scc_to_dag().

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

◆ update_successors_of_predecessor()

static void update_successors_of_predecessor ( control  pred,
control  new_c,
control  old_c 
)
static

new_c is not consistent on entry and might not be on exit because it is called from within a loop

A meaningless control node must be inserted?

true successor

r%2==0

No problem this kind of node may have several successors

Definition at line 1263 of file bourdoncle.c.

1264 {
1265  pips_assert("old_c is already a successor of pred",
1266  gen_in_list_p(old_c, control_successors(pred)));
1267  pips_assert("new_c is not yet a successor of pred",
1268  !gen_in_list_p(new_c, control_successors(pred)));
1269 
1270  if(control_test_p(pred)) {
1271  int r = 0;
1272  bool insert_p = false; /* A meaningless control node must be inserted? */
1273 
1274  if((r=gen_position(old_c, control_successors(pred)))==0) {
1275  pips_internal_error("old_c %p must be a successor of pred %p", old_c, pred);
1276  }
1277  else if(r%2==1) {
1278  /* true successor */
1279  insert_p = (gen_length(control_successors(pred))%2==1);
1280  }
1281  else /* r%2==0 */ {
1282  insert_p = (gen_length(control_successors(pred))%2==0);
1283  }
1284  if(insert_p) {
1286 
1288  CONS(CONTROL, mlc, NIL));
1289  }
1291  CONS(CONTROL, new_c, NIL));
1292 
1293  ifdebug(8) {
1294  pips_debug(8, "%s meaningless control node added. New successor list of pred %p:\n",
1295  insert_p? "A" : "No", pred);
1297  }
1298  }
1299  else {
1300  /* No problem this kind of node may have several successors */
1301  control_successors(pred) = CONS(CONTROL, new_c, control_successors(pred));
1302  }
1303 }
static void print_control_nodes_without_check(list l)
Was moved into ri-util/control, minus the check_control_statement()
Definition: bourdoncle.c:322

References CONS, CONTROL, control_successors, control_test_p(), gen_in_list_p(), gen_length(), gen_nconc(), gen_position(), ifdebug, make_meaningless_control(), NIL, pips_assert, pips_debug, pips_internal_error, and print_control_nodes_without_check().

Referenced by scc_to_dag().

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

Variable Documentation

◆ davinci_count

int davinci_count = 0
static

This counter is pre-incremented each time a new graph is stored to generate a new file name.

Definition at line 425 of file bourdoncle.c.

Referenced by davinci_print_control_nodes(), davinci_print_non_deterministic_unstructured(), and set_davinci_count().

◆ dfn

bourdoncle.c

Decomposition of a CFG into SCC's and sub-SCC's. Algorithm 3.9, Page 43, Francois Bourdoncle's PhD. Define heuristically SCC and sub-SCC heads.

Build a set of new data structures to represent any CFG as a recursive structure of CFG's (scc_map) and one parent DAG (ndu) and one node traversal order (partition list) and a correspondance between the new nodes and the original nodes (ancestor_map).

Some predecessors or successors must be deleted in the recursive descent. These vertices are given a statement_undefined statement and empty lists of predecessors and successors. Empty successors must be maintained so as to know if they are true or false successors. I suppose that we do not really care about irrelevant predecessors and that we might as well delete them. In fact, only the true branch successor absolutely must be preserved.

Since the new CFG's are not deterministic, the number of successors is not bounded to two and any statement can have more than one successor. Standard consistency check are likely to fail if applied to the unstructured produced by this decomposition.

When a node pointing to a scc is replicated, two options are available. Either all copies point to a unique scc (initial implementation) or each control copy points towards its own copy of the scc. In the initial implementation and first option, only ancestor control nodes can point to a scc, and ancestor_map is used to reach the scc_associated to a node. In the second case, any control node, replicated or not, can point to a scc. The first option makes sense when transformers are not context dependent: all identical cycles can be analyzed as one cycle, although I do not understand the miracle for the preconditions, since they clearly are context-sensitive. The second option is useful when transformers are computed in context, since all replicates of a cycle can operate in diferrent contexts. This is performed as a post-processing step conditional to property SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT.

Structure of the code: bourdoncle_partition() bourdoncle_visit() bourdoncle_component() bourdoncle_visit() recursively update_partition() scc_to_dag() [Not part of Bourdoncle's algorithm: transforms a scc into a non-deterministic while loop] replicate_cycles() [Not part of Bourdoncle's algorithm: allocate a copy of each scc, i.e. cycle, i.e. while loop for each of its "call" sites] Data structures for Bourdoncle's heuristics:

dfn = depth first number

num = current vertex number

vertex_stack = stack of visited nodes

Definition at line 104 of file bourdoncle.c.

Referenced by bourdoncle_partition(), copy_dfn(), get_dfn(), reset_dfn(), and update_dfn().

◆ embedding_control_list

list embedding_control_list = NIL
static

◆ num

◆ replicate_map

hash_table replicate_map = hash_table_undefined
static

Replication of unstructured (i.e.

CFG) and control nodes (i.e. vertices)

Definition at line 957 of file bourdoncle.c.

Referenced by control_shallow_copy(), control_to_replicate(), control_translate_arcs(), partition_to_unstructured(), print_replicate_map(), and unstructured_shallow_copy().