PIPS
control.h File Reference

Go to the source code of this file.

Macros

#define CONTROL_INCLUDED
 Warning! Do not modify this file that is automatically generated! More...
 
#define USE_NEW_CONTROLIZER_ENV_VAR_NAME   "PIPS_USE_NEW_CONTROLIZER"
 Define the environment variables used to select which controlizer version to use independently of which one was activated at the pipsmake level: More...
 
#define USE_OLD_CONTROLIZER_ENV_VAR_NAME   "PIPS_USE_OLD_CONTROLIZER"
 The name of the one to force the use of the old controlizer: More...
 

Functions

statement unsugared_loop_header (statement)
 LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i=1), the test (i<10) and the increment (i=i+1). More...
 
statement unsugared_forloop_header (statement)
 
statement unsugared_whileloop_header (statement)
 
statement unsugared_loop_test (statement)
 Do a crude test of end of do-loop for do-loop unsugaring. More...
 
statement unsugared_forloop_test (statement)
 
statement unsugared_whileloop_test (statement)
 
statement unsugared_loop_inc (statement)
 Do an index increment instruction for do-loop unsugaring. More...
 
statement unsugared_forloop_inc (statement)
 
control find_exit_control_node (list, control)
 Find the exit node of a sub-CFG defined by the list of nodes ctls and by the first node to execute when finished. More...
 
control find_or_create_exit_control_node (list, control)
 FI: remake of function above, incomplete backward approach, now obsolete because the forward approach works. More...
 
bool controlize_statement (control, control, hash_table)
 Controlize a statement that is in a control node, that is restructure it to have a HCFG recursively (a hierarchical control flow graph). More...
 
statement hcfg (statement)
 Compute the hierarchical control flow graph (HCFG) of a statement. More...
 
statement loop_header (statement)
 LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i=1), the test (i<10) and the increment (i=i+1). More...
 
statement loop_test (statement)
 
statement loop_inc (statement)
 
statement forloop_header (statement)
 
statement forloop_test (statement)
 
statement forloop_inc (statement)
 
unstructured control_graph (statement)
 CONTROL_GRAPH returns the control graph of the statement ST. More...
 
bool ctrl_graph_undefined_p (void)
 graph.c More...
 
void reset_ctrl_graph (void)
 
void error_reset_ctrl_graph (void)
 
void set_ctrl_graph (controlmap)
 
controlmap get_ctrl_graph (void)
 
void init_ctrl_graph (void)
 
void close_ctrl_graph (void)
 
void store_ctrl_graph (statement, control)
 
void update_ctrl_graph (statement, control)
 
control load_ctrl_graph (statement)
 
control delete_ctrl_graph (statement)
 
bool bound_ctrl_graph_p (statement)
 
void store_or_update_ctrl_graph (statement, control)
 
void clean_ctrl_graph (void)
 global mapping from statements to their control in the full control graph More...
 
list control_list_to_statement_list (list)
 of statement More...
 
void build_full_ctrl_graph (statement)
 
void full_control_graph (string)
 FULL CONTROL GRAPH for module NAME. More...
 
void init_ctrl_graph_travel (statement, bool(*)(statement))
 
bool next_ctrl_graph_travel (statement *)
 
void close_ctrl_graph_travel (void)
 
void control_graph_recursive_decomposition (unstructured)
 hierarchize.c More...
 
bool new_controlizer (const char *)
 module.c More...
 
bool controlizer (const char *)
 The old controlizer user interface. More...
 
void fuse_sequences_in_unstructured (statement)
 Try to transform each control sequence in a single statement instead of a list of control nodes: More...
 
statement take_out_the_exit_node_if_not_a_continue (statement)
 Extract the statement from an exit node of an unstructured statement if it is a useful statement. More...
 
void unspaghettify_or_restructure_statement (statement)
 The entry point common to unspaghettify or restructure a module: More...
 
void unspaghettify_statement (statement)
 The real entry point of unspaghettify: More...
 
void simple_restructure_statement (statement)
 A simple cleaning of the control graph without major topological restructuring. More...
 
bool unspaghettify (const string)
 Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code. More...
 
void restructure_statement (statement)
 The real entry point of control graph restructuring: More...
 
bool restructure_control (const string)
 Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code, etc. More...
 
bool unstructured_consistency_p (unstructured, bool)
 cfg.c More...
 
bool unstructured_while_p (unstructured)
 Test if an unstructured is found to be like a structured while-loop. More...
 
void init_reachable (statement)
 unreachable.c More...
 
bool statement_reachable_p (statement)
 Test if the given statement is reachable from some statements given at init_reachable(start) More...
 
bool statement_continued_p (statement)
 Test if the execution goes on after the given statement. More...
 
void close_reachable (void)
 Remove reachability information about previously checked statements. More...
 
bool meaningless_control_p (control)
 bourdoncle.c More...
 
bool control_test_p (control)
 Check that a node is used as a test in a CFG. More...
 
void add_control_to_embedding_control_list (control)
 
control control_to_ancestor (control, hash_table)
 If vertex is an ancestor control node from the input control graph, return vertex, else return its ancestor. More...
 
control control_shallow_copy (control)
 
unstructured unstructured_shallow_copy (unstructured, hash_table)
 
unstructured partition_to_unstructured (control, list)
 Build a new unstructured (CFG) for partition. More...
 
void intersect_successors_with_partition_or_complement (control, list, bool)
 If complement_p, preserve successors in the complement of partition. More...
 
void intersect_successors_with_partition (control, list)
 
void intersect_successors_with_partition_complement (control, list)
 
list bourdoncle_partition (unstructured, unstructured *, hash_table *, hash_table *)
 
list bourdoncle_component (control, hash_table, hash_table)
 
int bourdoncle_visit (control, list *, hash_table, hash_table)
 
unstructured ancestor_cycle_head_to_scc (control, hash_table)
 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, hash_table)
 Retrieve a scc_u from its head. More...
 
bool cycle_head_p (control, hash_table, hash_table)
 This node is a cycle call site. More...
 
bool proper_cycle_head_p (control, hash_table)
 This node is really the head of a cycle (red on daVinci pictures). More...
 
bool direct_cycle_head_p (control, hash_table)
 This node is directly associated to a specific cycle. More...
 
unstructured cycle_head_to_scc (control, hash_table, hash_table)
 The ancestor of this node is associated to a specific cycle. More...
 
bool one_successor_kind_only_p (control, bool)
 useful for non-deterministic control flow graph only More...
 
bool true_successors_only_p (control)
 
bool false_successors_only_p (control)
 
void bourdoncle_free (unstructured, hash_table, hash_table)
 
bool guess_late_read_effect_on_entity (expression, entity)
 for_to_do_or_while_loops.c More...
 
sequence for_to_do_loop_conversion (forloop, statement)
 Try to convert a C-like for-loop into a Fortran-like do-loop. More...
 
void try_to_transform_a_for_loop_into_a_do_loop (forloop)
 Try to to transform the C-like for-loops into Fortran-like do-loops. More...
 
bool for_loop_to_do_loop (const string)
 For-loop to do-loop transformation phase. More...
 
sequence for_to_while_loop_conversion (expression, expression, expression, statement, extensions)
 Build a sequence with a while-loop from for-loop parameters. More...
 
void transform_a_for_loop_into_a_while_loop (forloop)
 Try to to transform the C-like for-loops into Fortran-like do-loops. More...
 
void transform_a_for_loop_statement_into_a_while_loop (statement)
 Same as above, but with no calls to ancestors. More...
 
bool for_loop_to_while_loop (const string)
 For-loop to while-loop transformation phase. More...
 
bool dowhile_to_while (const char *)
 dowhile_to_while.c More...
 
void do_loop_to_while_loop (statement)
 converts a doloop to a while loop, in place More...
 
void do_loop_to_for_loop (statement)
 converts a doloop to a for loop, in place More...
 

Variables

char vcid_control_controlizer []
 cproto-generated files More...
 
char vcid_control_old_controlizer []
 old_controlizer.c More...
 
char vcid_unspaghettify []
 unspaghettify.c More...
 

Macro Definition Documentation

◆ CONTROL_INCLUDED

#define CONTROL_INCLUDED

Warning! Do not modify this file that is automatically generated!

Modify src/Libs/control/control-local.h instead, to add your own modifications. header file built by cproto control-local.hcontrol.h

Definition at line 35 of file control.h.

◆ USE_NEW_CONTROLIZER_ENV_VAR_NAME

#define USE_NEW_CONTROLIZER_ENV_VAR_NAME   "PIPS_USE_NEW_CONTROLIZER"

Define the environment variables used to select which controlizer version to use independently of which one was activated at the pipsmake level:

The name of the one to force the use of the new controlizer:

Definition at line 41 of file control.h.

◆ USE_OLD_CONTROLIZER_ENV_VAR_NAME

#define USE_OLD_CONTROLIZER_ENV_VAR_NAME   "PIPS_USE_OLD_CONTROLIZER"

The name of the one to force the use of the old controlizer:

Definition at line 43 of file control.h.

Function Documentation

◆ 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
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
#define CONTROL(x)
CONTROL.
Definition: ri.h:910

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:

◆ 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 }
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
#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 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:

◆ bound_ctrl_graph_p()

bool bound_ctrl_graph_p ( statement  )

Referenced by stmt_rewrite().

+ 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 print_control_nodes(list l)
Display identification of a list of control nodes.
Definition: control.c:589
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
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#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
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 pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define control_undefined
Definition: ri.h:916
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

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
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60

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_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)
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
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:

◆ build_full_ctrl_graph()

void build_full_ctrl_graph ( statement  s)

first pass to initialize the ctrl_graph controls

STATEMENT

second pass to link the statements

Definition at line 238 of file graph.c.

239 {
240  pips_debug(3, "statement (%td,%td:%td)\n",
243  statement_number(s));
244 
245  /* first pass to initialize the ctrl_graph controls
246  */
247  init_ctrl_graph();
249  statement_domain, gen_true, stmt_rewrite, /* STATEMENT */
250  NULL);
251 
252  /* second pass to link the statements
253  */
254  statement_arrows(s, NIL);
255 }
static void stmt_rewrite(statement s)
Definition: graph.c:232
static void statement_arrows(statement s, list next)
Definition: graph.c:110
void init_ctrl_graph(void)
#define ORDERING_NUMBER(o)
#define ORDERING_STATEMENT(o)
#define statement_ordering(x)
Definition: ri.h:2454
#define statement_number(x)
Definition: ri.h:2452

References gen_multi_recurse(), gen_true(), init_ctrl_graph(), NIL, ORDERING_NUMBER, ORDERING_STATEMENT, pips_debug, statement_arrows(), statement_domain, statement_number, statement_ordering, and stmt_rewrite().

Referenced by full_control_graph(), and handle_hpf_directives().

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

◆ clean_ctrl_graph()

void clean_ctrl_graph ( void  )

global mapping from statements to their control in the full control graph

the crtl_graph is freed by hand, because the default behavior is not convenient for my purpose. I would have needed a persistant statement in the control, but it is not desired in pips.

now it can be freed safely

Definition at line 53 of file graph.c.

54 {
55  CONTROLMAP_MAP(s, c,
56  {
57  pips_debug(7, "statement (%td,%td)\n",
60 
66  },
67  get_ctrl_graph());
68 
69  close_ctrl_graph(); /* now it can be freed safely */
70 }
controlmap get_ctrl_graph(void)
void close_ctrl_graph(void)
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROLMAP_MAP(k, v, c, f)
Definition: ri.h:900
#define control_statement(x)
Definition: ri.h:941
#define statement_undefined
Definition: ri.h:2419

References close_ctrl_graph(), control_predecessors, control_statement, control_successors, CONTROLMAP_MAP, gen_free_list(), get_ctrl_graph(), NIL, ORDERING_NUMBER, ORDERING_STATEMENT, pips_debug, statement_ordering, and statement_undefined.

Referenced by handle_hpf_directives().

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

◆ close_ctrl_graph()

void close_ctrl_graph ( void  )

Referenced by clean_ctrl_graph().

+ Here is the caller graph for this function:

◆ close_ctrl_graph_travel()

void close_ctrl_graph_travel ( void  )

Definition at line 340 of file graph.c.

341 {
342  free_to_see_stack();
343  free_stacked_map();
344 }

Referenced by handle_independent_directive(), handle_reduction_directive(), and propagate_synonym().

+ Here is the caller graph for this function:

◆ close_reachable()

void close_reachable ( void  )

Remove reachability information about previously checked statements.

Definition at line 252 of file unreachable.c.

253 {
254  close_reached();
255  close_continued();
256 }

Referenced by module_name_to_preconditions(), and module_name_to_total_preconditions().

+ Here is the caller graph for this function:

◆ control_graph_recursive_decomposition()

void control_graph_recursive_decomposition ( unstructured  u)

hierarchize.c

hierarchize.c

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

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

The seed interval graph is indeed the control graph itself:

Apply recursively interval graph decomposition:

For all intervals of the graph:

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

Useless to restructure the exit node...

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

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

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

Skip the entry interval

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

Construct the interval graph from the previous one:

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

Definition at line 563 of file hierarchize.c.

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

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

Referenced by unspaghettify_or_restructure_statement().

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

◆ control_list_to_statement_list()

list control_list_to_statement_list ( list  lc)

of statement

of statements

Parameters
lcc

Definition at line 103 of file graph.c.

104 {
105  list /* of statements */ ls = NIL;
106  MAP(CONTROL, c, ls = CONS(STATEMENT, control_statement(c), ls), lc);
107  return ls;
108 }
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413

References CONS, CONTROL, control_statement, MAP, NIL, and STATEMENT.

Referenced by compute_cumulated_reductions(), and statement_arrows().

+ 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 }
control make_control(statement a1, list a2, list a3)
Definition: ri.c:523
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 }
bool meaningless_control_p(control c)
Is exported to exploit non-deterministic control flow graphs.
Definition: bourdoncle.c:154
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
bool statement_test_p(statement)
Definition: statement.c:343
#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 }
static bool ancestor_control_p(hash_table ancestor_map, control c)
Functions to deal with the ancestor_map.
Definition: bourdoncle.c:837
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:

◆ controlizer()

bool controlizer ( const char *  module_name)

The old controlizer user interface.

Transform a code with some goto and labels (typically generated by a parser) into a code that is a hierarchical control flow graph, the standard abstract syntax tree of PIPS (the RI).

Interface for pipsdbm and pipsmake

Should never arise

To have the debug in unspaghettify_statement() working:

The statement of a compilation unit is a long list of continue statements and it takes a long time to restructure although nothing is done in the end. So, let's skip this useless processing. SG:it may be ok to skip it, but we still need to call module_reorder ...

gen_copy_seq(statement_declarations(parsed_mod_stat))

By setting this property, we try to unspaghettify the control graph of the module:

With C code, some local declarations may have been lost by the (current) restructurer

Reorder the module, because we have a new statement structure.

Parameters
module_nameodule_name

Definition at line 224 of file module.c.

225 {
226  if (getenv(USE_NEW_CONTROLIZER_ENV_VAR_NAME) != NULL) {
227  pips_user_warning("Force the use of the new controlizer because a '%s' environment variable is defined\n", USE_NEW_CONTROLIZER_ENV_VAR_NAME);
229  }
230 
232  pips_assert("Module must be defined in symbol table",!entity_undefined_p(m));
233 
234  statement module_stat, parsed_mod_stat;
235 
236  // generate pragma string or expression using the correct language:
238  if(value_code_p(mv)) {
239  code c = value_code(mv);
241  } else {
242  /* Should never arise */
244  }
245 
247 
248  parsed_mod_stat = (statement) db_get_memory_resource(DBR_PARSED_CODE, module_name, true);
249  module_stat = copy_statement(parsed_mod_stat) ;
250  /* To have the debug in unspaghettify_statement() working: */
251  set_current_module_statement(module_stat);
252 
253  debug_on("CONTROL_DEBUG_LEVEL");
254  ifdebug(1){
255  statement_consistent_p(parsed_mod_stat);
256  statement_consistent_p(module_stat);
257  }
258 
259  /* The statement of a compilation unit is a long list of continue
260  statements and it takes a long time to restructure although
261  nothing is done in the end. So, let's skip this useless
262  processing.
263  SG:it may be ok to skip it, but we still need to call module_reorder ...
264  */
266  /* *module_stat can be re-used because control_graph reallocates
267  statements; do not show that to any student!
268  statement_instruction(module_stat) =
269  make_instruction(is_instruction_unstructured,
270  control_graph(module_stat));
271  Maintenant que je nettoie le code aussi avant le controlizer,
272  un programme sans instruction ne contient qu'un statement
273  RETURN, c'est a` dire un statement de CALL vers RETURN avec le
274  label 00000. Comme la ligne ci-dessus recycle le label et le
275  commentaire, on se retrouve avec un unstructured avec le label
276  et le commentaire du RETURN qu'il contient... En plus il y avait
277  une re'cursion de l'unstructured vers module_stat. :-(
278 
279  So now correct the label and the comment: */
280 
281  ifdebug(1) pips_assert("the module statement is consistent "
282  "before the controlizer is called",
283  statement_consistent_p(module_stat));
284 
285  module_stat = make_statement(entity_empty_label(),
287  MAKE_ORDERING(0,1),
290  control_graph(module_stat)),
291  NIL /* gen_copy_seq(statement_declarations(parsed_mod_stat))*/,
292  NULL,
295 
296  ifdebug(1) pips_assert("the module statement is consistent "
297  "after the controlizer call",
298  statement_consistent_p(module_stat));
299 
300  /* By setting this property, we try to unspaghettify the control graph
301  of the module: */
302  if (get_bool_property("UNSPAGHETTIFY_IN_CONTROLIZER"))
303  unspaghettify_statement(module_stat);
304 
305 
306  /* With C code, some local declarations may have been lost by the
307  (current) restructurer */
308  if(c_module_p(m))
309  module_stat = update_unstructured_declarations(module_stat);
310 
311  }
312 
313  /* Reorder the module, because we have a new statement structure. */
314  module_reorder(module_stat);
315 
316  ifdebug(1) statement_consistent_p(module_stat);
317 
318  DB_PUT_MEMORY_RESOURCE(DBR_CODE, module_name, module_stat);
319 
322 
323  debug_off();
324 
325  return true;
326 }
statement copy_statement(statement p)
STATEMENT.
Definition: ri.c:2186
bool statement_consistent_p(statement p)
Definition: ri.c:2195
statement make_statement(entity a1, intptr_t a2, intptr_t a3, string a4, instruction a5, list a6, string a7, extensions a8, synchronization a9)
Definition: ri.c:2222
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
synchronization make_synchronization_none(void)
Definition: ri.c:2424
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
#define USE_NEW_CONTROLIZER_ENV_VAR_NAME
– control.h
Definition: control-local.h:33
bool controlizer(const char *module_name)
The old controlizer user interface.
Definition: module.c:224
static statement update_unstructured_declarations(statement module_stat)
FI: a short-term solution to fix declarations lost due to unstructured building by controlizer.
Definition: module.c:49
bool new_controlizer(const char *module_name)
Transform a code with some goto and labels (typically generated by a parser) into a code that is a hi...
Definition: module.c:102
void unspaghettify_statement(statement)
The real entry point of unspaghettify:
bool compilation_unit_p(const char *module_name)
The names of PIPS entities carry information about their nature.
Definition: entity_names.c:56
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
if(!(yy_init))
Definition: genread_lex.c:1029
unstructured control_graph(statement)
CONTROL_GRAPH returns the control graph of the statement ST.
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
void set_prettyprint_language_from_property(enum language_utype native)
set the prettyprint language according to the property PRETTYPRINT_LANGUAGE @description If the prope...
Definition: language.c:103
#define pips_user_warning
Definition: misc-local.h:146
#define true
Definition: newgen_types.h:81
static char * module
Definition: pips.c:74
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define STATEMENT_NUMBER_UNDEFINED
default values
#define MAKE_ORDERING(u, s)
On devrait utiliser Newgen pour cela, mais comme on ne doit pas les utiliser directement (mais via st...
#define empty_comments
Empty comments (i.e.
bool c_module_p(entity m)
Test if a module "m" is written in C.
Definition: entity.c:2777
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
entity entity_empty_label(void)
Definition: entity.c:1105
extensions empty_extensions(void)
extension.c
Definition: extension.c:43
#define value_code_p(x)
Definition: ri.h:3065
#define entity_undefined_p(x)
Definition: ri.h:2762
@ is_instruction_unstructured
Definition: ri.h:1475
#define value_code(x)
Definition: ri.h:3067
#define code_language(x)
Definition: ri.h:792
#define language_tag(x)
Definition: ri.h:1590
@ is_language_fortran
Definition: ri.h:1566
#define entity_initial(x)
Definition: ri.h:2796
return(s1)

References c_module_p(), code_language, compilation_unit_p(), control_graph(), copy_statement(), db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, debug_off, debug_on, empty_comments, empty_extensions(), entity_empty_label(), entity_initial, entity_undefined_p, get_bool_property(), ifdebug, is_instruction_unstructured, is_language_fortran, language_tag, make_instruction(), MAKE_ORDERING, make_statement(), make_synchronization_none(), module_name(), module_name_to_entity(), module_reorder(), new_controlizer(), NIL, pips_assert, pips_user_warning, reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), set_prettyprint_language_from_property(), statement_consistent_p(), STATEMENT_NUMBER_UNDEFINED, unspaghettify_statement(), update_unstructured_declarations(), USE_NEW_CONTROLIZER_ENV_VAR_NAME, value_code, and value_code_p.

Referenced by AddEntityToCompilationUnit(), new_controlizer(), outliner_independent(), and RemoveEntityFromCompilationUnit().

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

◆ ctrl_graph_undefined_p()

bool ctrl_graph_undefined_p ( void  )

graph.c

◆ 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:

◆ delete_ctrl_graph()

control delete_ctrl_graph ( statement  )

◆ 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:

◆ do_loop_to_for_loop()

void do_loop_to_for_loop ( statement  sl)

converts a doloop to a for loop, in place

Parameters
sll

Definition at line 162 of file dowhile_to_while.c.

163 {
164  pips_assert("statement is a loop",statement_loop_p(sl));
165  loop l =statement_loop(sl);
166  range r = loop_range(l);
167 
168  forloop fl = make_forloop(
179 }
instruction make_instruction_forloop(forloop _field_)
Definition: ri.c:1193
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
forloop make_forloop(expression a1, expression a2, expression a3, statement a4)
Definition: ri.c:1025
loop statement_loop(statement)
Get the loop of a statement.
Definition: statement.c:1374
bool statement_loop_p(statement)
Definition: statement.c:349
statement update_statement_instruction(statement, instruction)
Replace the instruction in statement s by instruction i.
Definition: statement.c:3039
#define PLUS_UPDATE_OPERATOR_NAME
#define LESS_OR_EQUAL_OPERATOR_NAME
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression MakeBinaryCall(entity f, expression eg, expression ed)
Creates a call expression to a function with 2 arguments.
Definition: expression.c:354
expression make_assign_expression(expression lhs, expression rhs)
Make an assign expression, since in C the assignment is a side effect operator.
Definition: expression.c:390
#define loop_body(x)
Definition: ri.h:1644
#define range_upper(x)
Definition: ri.h:2290
#define range_increment(x)
Definition: ri.h:2292
#define range_lower(x)
Definition: ri.h:2288
#define loop_range(x)
Definition: ri.h:1642
#define loop_index(x)
Definition: ri.h:1640

References copy_expression(), copy_statement(), entity_intrinsic(), entity_to_expression(), LESS_OR_EQUAL_OPERATOR_NAME, loop_body, loop_index, loop_range, make_assign_expression(), make_forloop(), make_instruction_forloop(), MakeBinaryCall(), pips_assert, PLUS_UPDATE_OPERATOR_NAME, range_increment, range_lower, range_upper, statement_loop(), statement_loop_p(), and update_statement_instruction().

Referenced by rw_loop().

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

◆ do_loop_to_while_loop()

void do_loop_to_while_loop ( statement  sl)

converts a doloop to a while loop, in place

convert the loop to a while loop : fst the body

then the whileloop

and the prelude

Parameters
sll

Definition at line 115 of file dowhile_to_while.c.

116 {
117  pips_assert("statement is a loop",statement_loop_p(sl));
118  loop l =statement_loop(sl);
119  range r = loop_range(l);
120 
121  /* convert the loop to a while loop :
122  * fst the body
123  */
124  list statements = make_statement_list(
131  range_increment(r)
132  )
133  )
134  );
135  /* then the whileloop */
140  range_upper(r)
141  ),
142  make_block_statement(statements),
145 
146  /* and the prelude */
147  sequence seq = make_sequence(
150  range_lower(r)),
152  )
153  );
157 
159 }
evaluation make_evaluation_before(void)
Definition: ri.c:786
whileloop make_whileloop(expression a1, statement a2, entity a3, evaluation a4)
Definition: ri.c:2937
instruction make_instruction_sequence(sequence _field_)
Definition: ri.c:1169
sequence make_sequence(list a)
Definition: ri.c:2125
instruction make_instruction_whileloop(whileloop _field_)
Definition: ri.c:1178
statement make_block_statement(list)
Make a block statement from a list of statement.
Definition: statement.c:616
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
statement make_assign_statement(expression, expression)
Definition: statement.c:583
#define PLUS_OPERATOR_NAME
#define make_statement_list(stats...)
easy list constructor
#define expression_undefined
Definition: ri.h:1223

References copy_statement(), entity_empty_label(), entity_intrinsic(), entity_to_expression(), expression_undefined, instruction_to_statement(), LESS_OR_EQUAL_OPERATOR_NAME, loop_body, loop_index, loop_range, make_assign_statement(), make_block_statement(), make_evaluation_before(), make_instruction_sequence(), make_instruction_whileloop(), make_sequence(), make_statement_list, make_whileloop(), MakeBinaryCall(), pips_assert, PLUS_OPERATOR_NAME, range_increment, range_lower, range_upper, statement_loop(), statement_loop_p(), and update_statement_instruction().

Referenced by terapix_loop_handler().

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

◆ dowhile_to_while()

bool dowhile_to_while ( const char *  module_name)

dowhile_to_while.c

Parameters
module_nameodule_name

Definition at line 82 of file dowhile_to_while.c.

83 {
84  // prelude
85  debug_on("CONTROL_DEBUG_LEVEL");
89  );
90 
91  // whether anything was changed
92  bool changed = false;
93 
94  // actual transformation
97 
98  // postlude
99  if (changed)
100  {
104  }
105 
108  debug_off();
109  return true;
110 }
static void dowhile_to_while_walker(statement stmt, bool *changed)
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
statement get_current_module_statement(void)
Get the current module statement.
Definition: static.c:208
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785

References db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, debug_off, debug_on, dowhile_to_while_walker(), gen_context_recurse, gen_true2(), get_current_module_statement(), module_name(), module_name_to_entity(), module_reorder(), reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), and statement_domain.

+ Here is the call graph for this function:

◆ error_reset_ctrl_graph()

void error_reset_ctrl_graph ( void  )

◆ 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:

◆ for_loop_to_do_loop()

bool for_loop_to_do_loop ( const string  module_name)

For-loop to do-loop transformation phase.

This transformation transform for example a \begin{lstlisting} for (i = lb; i < ub; i += stride) body; \end{lstlisting} into a \begin{lstlisting}[language=fortran] do i = lb, ub - 1, stride body end do \end{lstlisting}

Now use pure local analysis on the code but we could imagine further use of semantics analysis some day...

Get the true ressource, not a copy, since we modify it in place.

We need to access to the instruction containing the current for-loops, so ask NewGen gen_recurse to keep this informations for us:

Iterate on all the for-loops:

Reorder the module, because some statements have been replaced.

Should have worked:

Parameters
module_nameodule_name

Definition at line 779 of file for_to_do_or_while_loops.c.

779  {
781 
782  /* Get the true ressource, not a copy, since we modify it in place. */
784  (statement) db_get_memory_resource(DBR_CODE, module_name, true);
785 
789 
790  debug_on("FOR_LOOP_TO_DO_LOOP_DEBUG_LEVEL");
791  pips_assert("Statement should be OK before...", statement_consistent_p(module_statement));
792 
793  /* We need to access to the instruction containing the current
794  for-loops, so ask NewGen gen_recurse to keep this informations for
795  us: */
796  /* Iterate on all the for-loops: */
798  // Since for-loop statements can be nested, only restructure in
799  // a bottom-up way, :
801 
802  pips_assert("Statement should be OK after...", statement_consistent_p(module_statement));
803 
804  pips_debug(2, "done\n");
805 
806  debug_off();
807 
808  /* Reorder the module, because some statements have been replaced. */
810 
812 
815 
816  /* Should have worked: */
817  return true;
818 }
static statement module_statement
Definition: alias_check.c:125
void try_to_transform_a_for_loop_into_a_do_loop(forloop f)
Try to to transform the C-like for-loops into Fortran-like do-loops.
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
#define forloop_domain
newgen_extensions_domain_defined
Definition: ri.h:178

References db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, debug_off, debug_on, forloop_domain, gen_recurse, gen_true(), module_name(), module_name_to_entity(), module_reorder(), module_statement, pips_assert, pips_debug, reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), statement_consistent_p(), and try_to_transform_a_for_loop_into_a_do_loop().

+ Here is the call graph for this function:

◆ for_loop_to_while_loop()

bool for_loop_to_while_loop ( const string  module_name)

For-loop to while-loop transformation phase.

This transformation transforms a \begin{lstlisting} for (init; cond; update) body; \end{lstlisting} into a \begin{lstlisting} { init; while(cond) { body; update; } } \end{lstlisting}

Get the true ressource, not a copy, since we modify it in place.

We need to access to the instruction containing the current for-loops, so ask NewGen gen_recurse to keep this informations for us:

Iterate on all the for-loops:

Reorder the module, because some statements have been replaced.

Should have worked:

Parameters
module_nameodule_name

Definition at line 1001 of file for_to_do_or_while_loops.c.

1001  {
1003 
1004  /* Get the true ressource, not a copy, since we modify it in place. */
1006  (statement) db_get_memory_resource(DBR_CODE, module_name, true);
1007 
1011 
1012  debug_on("FOR_LOOP_TO_WHILE_LOOP_DEBUG_LEVEL");
1013  pips_assert("Statement should be OK before...", statement_consistent_p(module_statement));
1014 
1015  /* We need to access to the instruction containing the current
1016  for-loops, so ask NewGen gen_recurse to keep this informations for
1017  us: */
1018  /* Iterate on all the for-loops: */
1020  // Since for-loop statements can be nested, only restructure in
1021  // a bottom-up way, :
1022  //forloop_domain, gen_true, transform_a_for_loop_into_a_while_loop);
1024 
1025  pips_assert("Statement should be OK after...", statement_consistent_p(module_statement));
1026 
1027  pips_debug(2, "done\n");
1028 
1029  debug_off();
1030 
1031  /* Reorder the module, because some statements have been replaced. */
1033 
1035 
1038 
1039  /* Should have worked: */
1040  return true;
1041 }
void transform_a_for_loop_statement_into_a_while_loop(statement st)
Same as above, but with no calls to ancestors.

References db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, debug_off, debug_on, gen_recurse, gen_true(), module_name(), module_name_to_entity(), module_reorder(), module_statement, pips_assert, pips_debug, reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), statement_consistent_p(), statement_domain, and transform_a_for_loop_statement_into_a_while_loop().

+ Here is the call graph for this function:

◆ for_to_do_loop_conversion()

sequence for_to_do_loop_conversion ( forloop  theloop,
statement  parent 
)

Try to convert a C-like for-loop into a Fortran-like do-loop.

Assume to match what is done in the prettyprinter C_loop_range().

Returns
a sequence containing the do-loop if the transformation worked or sequence_undefined if it failed.

This does not filter scalar integers...

Consider only scalar integer variables as loop indices

&& type_depth(lit)==1

We got a candidate loop index and final bound, let's check the increment

We have found a do-loop compatible for-loop:

guess lower bound

try hard to reproduce statement content

Parameters
theloopheloop
parentarent

Definition at line 614 of file for_to_do_or_while_loops.c.

615 {
616 
617  sequence output = sequence_undefined;
619  expression cond = forloop_condition(theloop);
620  expression incr = forloop_increment(theloop);
621  statement body = forloop_body(theloop);
622 
623  set cond_entities = get_referenced_entities(cond);
624  /* This does not filter scalar integers... */
625  set incr_entities = get_referenced_entities(incr);
626  set cond_inter_incr_entities = set_make(set_pointer);
627  cond_inter_incr_entities = set_intersection(cond_inter_incr_entities,incr_entities,cond_entities);
628 
629  SET_FOREACH(entity,loop_index,cond_inter_incr_entities)
630  {
631  /* Consider only scalar integer variables as loop indices */
633  if(scalar_integer_type_p(lit) /* && type_depth(lit)==1*/ ) {
636  {
637  bool is_upper_p,is_increasing_p;
638  expression upper_bound;
639  if(condition_expression_to_final_bound(cond,loop_index,&is_upper_p, &upper_bound))
640  {
641  set upper_bound_entities = get_referenced_entities(upper_bound);
642  bool upper_bound_entity_written=false;
643  SET_FOREACH(entity,e,upper_bound_entities)
644  {
646  {
647  upper_bound_entity_written=true;
648  break;
649  }
650  }
651  set_free(upper_bound_entities);
652  if(!upper_bound_entity_written){
653  /* We got a candidate loop index and final bound,
654  let's check the increment */
655  expression increment_expression =
656  guess_loop_increment(incr,loop_index,body);
657  expression increment;
658  if( !expression_undefined_p(increment_expression) &&
659  incrementation_expression_to_increment(increment_expression,
660  loop_index,
661  &is_increasing_p,
662  &increment))
663  {
664  /* We have found a do-loop compatible for-loop: */
665  output=make_sequence(NIL);
666  if(increment_expression!=incr){
667  remove_expression_from_comma_list(incr,increment_expression);
669  //statement_consistent_p(body);
670  }
671 
672  /* guess lower bound */
674  if(expression_undefined_p(lower_bound))
675  lower_bound=entity_to_expression(loop_index);
676  else {
677  if( lower_bound!= init) {
681  }
682  lower_bound=EXPRESSION(CAR(CDR(call_arguments(expression_call(lower_bound)))));
683  }
684 
685  if (!is_upper_p && is_increasing_p)
686  pips_user_warning("Loop with lower bound and increasing index %s\n", entity_local_name(loop_index));
687  if (is_upper_p && !is_increasing_p)
688  pips_user_warning("Loop with upper bound and decreasing index %s\n", entity_local_name(loop_index));
689 
690  range lr;
691  if(is_upper_p)
692  lr = make_range(lower_bound, upper_bound, increment);
693  else {
694  // FI: Unfortunately, the problem must be
695  // postponed to the prettyprinter
696  lr = make_range(lower_bound, upper_bound, increment);
697  }
698  loop l = make_loop(loop_index, lr, body, statement_label(parent),
700 
701  /* try hard to reproduce statement content */
703  statement_label(parent),
704  statement_number(parent),
706  statement_comments(parent),
708  statement_declarations(parent),
709  statement_decls_text(parent),
711 
716  statement_declarations(parent)=NIL;
717  statement_decls_text(parent)=NULL;
719 
721 
722  }
723  }
724  }
725  }
726  }
727  }
728  set_free(cond_entities);
729  set_free(incr_entities );
730  set_free( cond_inter_incr_entities);
731  return output;
732 }
instruction make_instruction_loop(loop _field_)
Definition: ri.c:1175
loop make_loop(entity a1, range a2, statement a3, entity a4, execution a5, list a6)
Definition: ri.c:1301
instruction make_instruction_expression(expression _field_)
Definition: ri.c:1196
execution make_execution_sequential(void)
Definition: ri.c:841
instruction make_instruction_call(call _field_)
Definition: ri.c:1184
range make_range(expression a1, expression a2, expression a3)
Definition: ri.c:2041
bool guess_late_read_effect_on_entity(expression init, entity loop_index)
Check comma expressions used for initialization.
static bool incrementation_expression_to_increment(expression incr, entity li, bool *is_increasing_p, expression *pincrement)
static expression guess_loop_increment(expression incr, entity loop_index, statement body)
iterate over
static expression guess_loop_lower_bound(expression init, entity loop_index)
iterate over the comma-separeted expression
static bool condition_expression_to_final_bound(expression cond, entity li, bool *is_upper_p, expression *pub)
Some passes to transform for-loops into do-loops or while-loops that may be easier to analyze by PIPS...
static void remove_expression_from_comma_list(expression comma_list, expression seed)
given an expression
static bool guess_write_effect_on_entity(void *exp, entity loop_index)
call guess_write_effect_on_entity_walker on each call of
list gen_append(list l1, const list l2)
Definition: list.c:471
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
#define STATEMENT_ORDERING_UNDEFINED
mapping.h inclusion
Definition: newgen-local.h:35
set set_intersection(set, const set, const set)
Definition: set.c:229
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
void set_free(set)
Definition: set.c:332
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
set get_referenced_entities(void *elem)
retrieves the set of entities used in elem beware that this entities may be formal parameters,...
Definition: entity.c:3063
call expression_call(expression e)
Definition: expression.c:445
type ultimate_type(type)
Definition: type.c:3466
bool scalar_integer_type_p(type)
Definition: type.c:3276
#define forloop_initialization(x)
Definition: ri.h:1366
#define forloop_increment(x)
Definition: ri.h:1370
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define statement_label(x)
Definition: ri.h:2450
#define sequence_statements(x)
Definition: ri.h:2360
#define statement_extensions(x)
Definition: ri.h:2464
#define expression_undefined_p(x)
Definition: ri.h:1224
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_comments(x)
Definition: ri.h:2456
#define statement_decls_text(x)
Definition: ri.h:2462
#define forloop_condition(x)
Definition: ri.h:1368
#define call_arguments(x)
Definition: ri.h:711
#define sequence_undefined
Definition: ri.h:2338
#define entity_type(x)
Definition: ri.h:2792
#define forloop_body(x)
Definition: ri.h:1372
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59

References call_arguments, CAR, CDR, condition_expression_to_final_bound(), CONS, empty_comments, empty_extensions(), entity_empty_label(), entity_local_name(), entity_to_expression(), entity_type, EXPRESSION, expression_call(), expression_undefined_p, forloop_body, forloop_condition, forloop_increment, forloop_initialization, gen_append(), get_referenced_entities(), guess_late_read_effect_on_entity(), guess_loop_increment(), guess_loop_lower_bound(), guess_write_effect_on_entity(), incrementation_expression_to_increment(), init, insert_statement(), instruction_to_statement(), loop_index, make_execution_sequential(), make_instruction_call(), make_instruction_expression(), make_instruction_loop(), make_loop(), make_range(), make_sequence(), make_statement(), make_synchronization_none(), NIL, pips_user_warning, remove_expression_from_comma_list(), scalar_integer_type_p(), sequence_statements, sequence_undefined, SET_FOREACH, set_free(), set_intersection(), set_make(), set_pointer, STATEMENT, statement_comments, statement_declarations, statement_decls_text, statement_extensions, statement_label, statement_number, STATEMENT_NUMBER_UNDEFINED, statement_ordering, STATEMENT_ORDERING_UNDEFINED, and ultimate_type().

Referenced by controlize_forloop(), and try_to_transform_a_for_loop_into_a_do_loop().

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

◆ for_to_while_loop_conversion()

sequence for_to_while_loop_conversion ( expression  init,
expression  cond,
expression  incr,
statement  body,
extensions  exts 
)

Build a sequence with a while-loop from for-loop parameters.

The API is a little weird to comply with the controlizer implementation...

Build the loop body of the while with { body; incr_st; } :

Build the while(cond) { n_body } statement:

ifdebug(5) {

pips_debug(5, "Initialization statement:\n");

print_statement(init_st);

pips_debug(5, "Incrementation statement:\n");

print_statement(incr_st);

pips_debug(5, "New body statement with incrementation:\n");

print_statement(n_body);

pips_debug(5, "New whileloop statement:\n");

print_statement(wl_st);

}

Parameters
initnit
condond
incrncr
bodyody
extsxts

Definition at line 826 of file for_to_do_or_while_loops.c.

830  {
831  pips_debug(5, "Begin\n");
832 
834  statement incr_st = make_expression_statement(incr);
836 
837  /* Build the loop body of the while with { body; incr_st; } : */
839  incr_st,
840  NULL);
841  /* Build the while(cond) { n_body } statement: */
842  statement wl_st = make_whileloop_statement(cond,
843  n_body,
845  true);
846  if(!empty_extensions_p(exts)) {
849  }
850 
851  /* ifdebug(5) { */
852  /* pips_debug(5, "Initialization statement:\n"); */
853  /* print_statement(init_st); */
854  /* pips_debug(5, "Incrementation statement:\n"); */
855  /* print_statement(incr_st); */
856  /* pips_debug(5, "New body statement with incrementation:\n"); */
857  /* print_statement(n_body); */
858  /* pips_debug(5, "New whileloop statement:\n"); */
859  /* print_statement(wl_st); */
860  /* } */
861 
862  wlseq = make_sequence(CONS(STATEMENT, init_st,
863  CONS(STATEMENT, wl_st, NIL)));
864  return wlseq;
865 }
void free_extensions(extensions p)
Definition: ri.c:950
extensions copy_extensions(extensions p)
EXTENSIONS.
Definition: ri.c:947
statement make_statement_from_statement_varargs_list(statement,...)
Build a statement sequence from a statement NULL-terminated varargs list.
Definition: statement.c:735
statement make_whileloop_statement(expression, statement, int, bool)
Build a while loop statement.
Definition: statement.c:1150
statement make_expression_statement(expression)
Build a statement from a given expression.
Definition: statement.c:1308
bool empty_extensions_p(extensions es)
Definition: extension.c:50

References CONS, copy_extensions(), empty_extensions_p(), free_extensions(), init, make_expression_statement(), make_sequence(), make_statement_from_statement_varargs_list(), make_whileloop_statement(), NIL, pips_debug, sequence_undefined, STATEMENT, statement_extensions, and STATEMENT_NUMBER_UNDEFINED.

Referenced by controlize_forloop(), transform_a_for_loop_into_a_while_loop(), and transform_a_for_loop_statement_into_a_while_loop().

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

◆ full_control_graph()

void full_control_graph ( string  name)

FULL CONTROL GRAPH for module NAME.

should put something in the db if made as a pass

Parameters
nameame

Definition at line 259 of file graph.c.

260 {
261  statement s = (statement) db_get_memory_resource(DBR_CODE, name, true);
263 
264  /* should put something in the db if made as a pass
265  */
266 }
void build_full_ctrl_graph(statement s)
Definition: graph.c:238

References build_full_ctrl_graph(), and db_get_memory_resource().

+ Here is the call graph for this function:

◆ fuse_sequences_in_unstructured()

void fuse_sequences_in_unstructured ( statement  s)

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

The entry point of the unstructured:

and its exit point:

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

ifdebug(5)

print_statement(s);

Select a node with only one successor:

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

...Accept the exit node

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

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

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

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

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

Reverse the list to follow the order of appearance :

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

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

...The control node has not been moved

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

Ok, the node has been located:

Follow a former control movement:

ifdebug(5) {

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

entity_local_name(statement_label(control_statement(a_control_to_fuse))),

a_control_to_fuse);

print_statement(control_statement(a_control_to_fuse));

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

print_statement(control_statement(a_control_to_fuse));

}

ifdebug(6) {

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

print_statement(s);

}

Verify that the fusion is still valid:

...Accept the exit node

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

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

make st with the statements of 2 following nodes:

Update the entry node if we fuse with it:

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

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

Update the potentially modified entry and exit nodes:

Definition at line 250 of file unspaghettify.c.

251 {
252  list blocs = NIL;
253  list control_nodes_to_fuse = NIL;
256  /* The entry point of the unstructured: */
257  control entry_node = unstructured_control(u);
258  /* and its exit point: */
259  control exit_node = unstructured_exit(u);
260  /* To store the list of the controls to fuse we use a mapping since
261  we need to keep track of eventual previous fuse on a control: */
262  hash_table controls_to_fuse_with_their_successors =
264 
265  bool aggressive_restructure_p = get_bool_property("FUSE_CONTROL_NODES_WITH_COMMENTS_OR_LABEL");
266 
267  ifdebug(4) {
268  pips_debug(4, "Begin with implicit target labels:");
269  print_arguments(tl);
270  pips_debug(4, "\n");
271  }
272 
273  ifdebug (1)
274  pips_assert("unstructured is consistent",
276  pips_debug(3, "Unstructured %p\n", u);
277 
278  CONTROL_MAP(c,
279  {
281  ifdebug (1)
282  pips_assert("control is consistent",
284  pips_debug(3, "Looking for control %p...\n", c);
285  /* ifdebug(5) */
286  /* print_statement(s); */
287 
288  /* Select a node with only one successor: */
289  if (gen_length(control_successors(c)) == 1) {
290  control the_successor = CONTROL(CAR(control_successors(c)));
291 
292  size_t number_of_successors_of_the_successor = gen_length(control_successors(the_successor));
293  size_t number_of_predecessors_of_the_successor = gen_length(control_predecessors(the_successor));
294  pips_debug(3, "Control %p: (gen_length(control_successors(c)) == 1), number_of_successors_of_the_successor = %zd, number_of_predecessors_of_the_successor = %zd, the successor is the entry node: %d, empty_statement_or_continue_p(control_statement(c)) = %d\n",
295  c,
296  number_of_successors_of_the_successor,
297  number_of_predecessors_of_the_successor,
298  the_successor == entry_node,
300  /* Since I use an O(n) algorithm instead of an
301  O(n^2) all this condition must be checked
302  again later since these topological and
303  semantical properties may have changed
304  during the fusion phase. I think it is true
305  because the fused graph is included into
306  the former graph but I am too lazy to write
307  a proof... :-( Have a look to
308  Validation/Control/create.f. */
309  if ((number_of_successors_of_the_successor <= 1
310  /* ...Accept the exit node */
311  && the_successor != entry_node
312  && number_of_predecessors_of_the_successor == 1)
313  || (aggressive_restructure_p ? empty_statement_or_continue_p(s) : empty_statement_or_continue_without_comment_p(s))) {
314  /* Ok, we have found a node in a
315  sequence. Note that we cannot fuse with the
316  entry node since it must keep this
317  role... */
318  /* But if c is empty, we can fuse it with any
319  successor without changing the semantincs,
320  even if the successor is the entry
321  node. Don't do this if there is a comment
322  since it mess up the original source
323  look-alike. */
324  /* The fact we can have a cycle is considered
325  a page below... */
326  /* Put the control in the fuse
327  list. Since no fusing occurs yet, the
328  address of a control node is itself: */
329  hash_put(controls_to_fuse_with_their_successors,
330  (char *) c,
331  (char *) c);
332  /* Use also a real list to remove the
333  non-determinism of a later
334  HASH_MAP. Note that since it follow a
335  depth-first algorithm, the output
336  program is more likely to be similar to
337  the output, especially with cycles in
338  the control graph: */
339  control_nodes_to_fuse = CONS(CONTROL,
340  c,
341  control_nodes_to_fuse);
342  }
343  }
344  else {
345  pips_debug(3, "(gen_length(control_successors(c)) == %zd)\n",
347  }
348  },
349  entry_node,
350  blocs);
351  gen_free_list(blocs);
352 
353  /* Reverse the list to follow the order of appearance : */
354  control_nodes_to_fuse = gen_nreverse(control_nodes_to_fuse);
355 
356  /* Now, since we have the list of the control nodes to fuse with
357  their successors, do the fusion: */
358  MAP(CONTROL, the_original_control, {
359  control a_control_to_fuse;
360  control the_successor;
361  char * its_address_now;
362  char * old_address;
363 
364  its_address_now = hash_get(controls_to_fuse_with_their_successors,
365  (char *) the_original_control);
366  /* Find the address of a control node to fuse even if
367  it has already been fused with predecessors through
368  a transitive closure: */
369  for(old_address = (char *) the_original_control;;) {
370  pips_debug(3, "Control %p (originally %p):\n",
371  its_address_now, the_original_control);
372  if (old_address == its_address_now
373  /* ...The control node has not been moved */
374  || !hash_defined_p(controls_to_fuse_with_their_successors,
375  (char *) its_address_now)
376  /* ...or it has not been moved because it is
377  not a control node to fuse anyway. */
378  )
379  /* Ok, the node has been located: */
380  break;
381  else {
382  /* Follow a former control movement: */
383  old_address = its_address_now;
384  its_address_now
385  = hash_get(controls_to_fuse_with_their_successors,
386  (char *) its_address_now);
387  }
388  }
389  a_control_to_fuse = (control) its_address_now;
390 
391  /* ifdebug(5) { */
392  /* fprintf(stderr,"Statement with label \"%s\" for control a_control_fo_fuse=%p\n", */
393  /* entity_local_name(statement_label(control_statement(a_control_to_fuse))), */
394  /* a_control_to_fuse); */
395  /* print_statement(control_statement(a_control_to_fuse)); */
396  /* fprintf(stderr,"Let's print the statement a second time to see its label again:\n"); */
397  /* print_statement(control_statement(a_control_to_fuse)); */
398  /* } */
399  /* ifdebug(6) { */
400  /* pips_debug(5, "All the unstructured %p:\n", u); */
401  /* print_statement(s); */
402  /* } */
403  ifdebug (3)
404  fprintf(stderr, "Want to fuse control %p\n", a_control_to_fuse);
405  ifdebug (1)
406  pips_assert("control a_control_to_fuse is consistent",
407  control_consistent_p(a_control_to_fuse));
408 
409  the_successor = CONTROL(CAR(control_successors(a_control_to_fuse)));
410  ifdebug (3)
411  fprintf(stderr, " with control %p\n", the_successor);
412  ifdebug (1)
413  pips_assert("control the_successor is consistent",
414  control_consistent_p(the_successor));
415 
416  if (a_control_to_fuse == the_successor) {
417  pips_debug(3, "\tA loop of control has been found... Do not fuse the control %p\n", a_control_to_fuse);
418  }
419  else {
420  int number_of_successors_of_the_successor =
421  gen_length(control_successors(the_successor));
422  int number_of_predecessors_of_the_successor =
423  gen_length(control_predecessors(the_successor));
424  /* Verify that the fusion is still valid: */
425  if ((number_of_successors_of_the_successor <= 1
426  /* ...Accept the exit node */
427  && the_successor != entry_node
428  && number_of_predecessors_of_the_successor == 1)
429  ||
431  && (!gen_in_list_p(statement_to_label(control_statement(a_control_to_fuse)), tl)
432  /* ||entity_empty_label_p(statement_to_label(control_statement(the_successor)))*/)
433  /*
434  (entity_empty_label_p(statement_to_label(control_statement(a_control_to_fuse)))
435  || entity_empty_label_p(statement_to_label(control_statement(the_successor))))
436  */
437  )) {
438  /* Well, it seems to be a real sequence, at most a
439  loop with 2 control nodes... */
440  pips_debug(3, "\tOk fuse them.\n");
441 
442  fuse_2_control_nodes(a_control_to_fuse, the_successor);
443  /* make st with the statements of 2 following nodes: */
444 
445  if (the_successor == entry_node)
446  /* Update the entry node if we fuse with it: */
447  entry_node = a_control_to_fuse;
448  if (the_successor == exit_node)
449  exit_node = a_control_to_fuse;
450 
451  /* If the node "the_successor" is in the fuse list, we
452  want to keep track of its new place, that is in
453  fact fused in "a_control_to_fuse", so that an
454  eventual fusion will use "a_control_to_fuse"
455  instead of "the_successor": */
456  if (hash_defined_p(controls_to_fuse_with_their_successors,
457  (char *) the_successor)) {
458  /* Ok, "the_successor" is a node to fuse or that
459  has been already fused (in this case the
460  following is useless, but anyway...). Thus we
461  keep track of its new location: */
462  hash_update(controls_to_fuse_with_their_successors,
463  (char *) the_successor,
464  (char *) a_control_to_fuse);
465  }
466  }
467  else
468  pips_debug(3, "\tDo not fuse them because the semantics have changed.\n");
469  }
470  ifdebug (1)
471  pips_assert("control after fuse is consistent",
472  control_consistent_p(a_control_to_fuse));
473 
474  },
475  control_nodes_to_fuse);
476 
477  /* Update the potentially modified entry and exit nodes: */
478  unstructured_control(u)= entry_node;
479  unstructured_exit(u)= exit_node;
480 
481  gen_free_list(tl);
482  hash_table_free(controls_to_fuse_with_their_successors);
483 }
bool control_consistent_p(control p)
Definition: ri.c:496
void fuse_2_control_nodes(control first, control second)
Fuse a 2 control nodes.
Definition: control.c:1391
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
bool empty_statement_or_continue_p(statement)
Return true if the statement is an empty instruction block or a continue or a recursive combination o...
Definition: statement.c:474
bool empty_statement_or_continue_without_comment_p(statement)
Return true if the statement is an empty instruction block or a continue without comments or without ...
Definition: statement.c:497
list statement_to_implicit_target_labels(statement)
Look for labels appearing in END= or ERR= IO clauses and allocate a label list.
Definition: statement.c:3145
entity statement_to_label(statement)
See if statement s is labelled and can be reached by a GO TO.
Definition: statement.c:2090
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
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
struct _newgen_struct_control_ * control
void print_arguments(list args)
Definition: naming.c:228
#define statement_instruction(x)
Definition: ri.h:2458
#define instruction_unstructured(x)
Definition: ri.h:1532

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

Referenced by recursively_restructure_an_unstructured().

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

◆ get_ctrl_graph()

controlmap get_ctrl_graph ( void  )

Referenced by clean_ctrl_graph().

+ Here is the caller graph for this function:

◆ guess_late_read_effect_on_entity()

bool guess_late_read_effect_on_entity ( expression  init,
entity  loop_index 
)

for_to_do_or_while_loops.c

for_to_do_or_while_loops.c

Assuming loop_index is a potential do loop index, and init a comma expression, do we have subexpressions after the loop_index initialization that may use this index? If yes, the loop cannot be transformed into a DO loop, because this subexpression will be moved before the loop index initialization. Or the loop index initialization should be replicated before the loop.

Example (SPEC2006, milc):

for (i = parity==0x01?even_sites_on_node:0, s = &lattice[i]; i<(parity==0x02?even_sites_on_node:sites_on_node); i++, s++) {

s = &lattice[i] is going to be placed ahead of i's own initialization.

In other words, the loop can be changed in different ways:

  • the loop is converted into a while loop with the initialization expression moved into a statement (easy, alreayd implemented, safe)
  • the conversion into a DO loop is performed, but all initializations are moved into a statement and the new initialization expression is "loop_init = loop_init" to satisfy the do loop semantics (a new implementation is required).
Parameters
initnit
loop_indexoop_index

Definition at line 412 of file for_to_do_or_while_loops.c.

413 {
414  bool guess_p = false;
415  if(expression_call_p(init)) {
417  entity f = call_function(c);
418  if(ENTITY_COMMA_P(f)) {
419  bool write_found_p = false;
420  list el = call_arguments(c);
421  FOREACH(EXPRESSION, e, el) {
422  if(!write_found_p && guess_write_effect_on_entity(e, loop_index))
423  write_found_p = true;
424  else if(write_found_p) {
426  FOREACH(REFERENCE, r, rl) {
427  guess_p = reference_variable(r)==loop_index;
428  if(guess_p)
429  break;
430  }
431  if(guess_p) {
432  gen_free_list(rl); // Just the spine...
433  break;
434  }
435  }
436  }
437  }
438  }
439  return guess_p;
440 }
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
#define ENTITY_COMMA_P(e)
bool expression_call_p(expression e)
Definition: expression.c:415
list expression_to_reference_list(expression e, list lr)
conversion of an expression into a list of references; references are appended to list lr as they are...
Definition: expression.c:1263
#define REFERENCE(x)
REFERENCE.
Definition: ri.h:2296
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326

References call_arguments, call_function, ENTITY_COMMA_P, EXPRESSION, expression_call(), expression_call_p(), expression_to_reference_list(), f(), FOREACH, gen_free_list(), guess_write_effect_on_entity(), init, loop_index, NIL, REFERENCE, and reference_variable.

Referenced by for_to_do_loop_conversion().

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

◆ init_ctrl_graph()

void init_ctrl_graph ( void  )

Referenced by build_full_ctrl_graph().

+ Here is the caller graph for this function:

◆ init_ctrl_graph_travel()

void init_ctrl_graph_travel ( statement  s,
bool(*)(statement decision 
)

initializations

no loop back

Definition at line 315 of file graph.c.

316 {
317  make_to_see_stack(); /* initializations */
318  make_stacked_map();
319  travel_decision = decision;
320 
321  store_statement_stacked(s, true); /* no loop back */
322  push_successors(s);
323 }
static void push_successors(statement s)
Definition: graph.c:310
static bool(* travel_decision)(statement)
Static data for the travel.
Definition: graph.c:290

References push_successors(), and travel_decision.

Referenced by handle_independent_directive(), handle_reduction_directive(), and propagate_synonym().

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

◆ init_reachable()

void init_reachable ( statement  start)

unreachable.c

unreachable.c

Parameters
startstatement.
Parameters
starttart

Definition at line 223 of file unreachable.c.

223  {
224  debug_on("REACHABLE_DEBUG_LEVEL");
225  init_reached();
226  init_continued();
227  propagate(start);
228  debug_off();
229 }
static char start[1024]
The name of the variable from which to start counting domain numbers.
Definition: genLisp.c:55
static bool propagate(statement)
returns whether propagation is continued after s.
Definition: unreachable.c:124

References debug_off, debug_on, propagate(), and start.

Referenced by module_name_to_preconditions(), and module_name_to_total_preconditions().

+ 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 }
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 control_test_p(control c)
Check that a node is used as a test in a CFG.
Definition: bourdoncle.c:175
void gen_list_and(list *a, const list b)
Compute A = A inter B: complexity in O(n2)
Definition: list.c:941
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
#define CONTROL_(x)
Definition: ri.h:913

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:

◆ load_ctrl_graph()

control load_ctrl_graph ( statement  )

Referenced by add_arrow_in_ctrl_graph(), and push_successors().

+ Here is the caller graph for this function:

◆ meaningless_control_p()

◆ new_controlizer()

bool new_controlizer ( const char *  module_name)

module.c

module.c

Interface for pipsdbm and pipsmake

Should never happen

To have the debug in unspaghettify_statement() working:

The statement of a compilation unit is a long list of continue statements and it takes a long time to restructure although nothing is done in the end. So, let's skip this useless processing. SG:it may be ok to skip it, but we still need to call module_reorder ...

By setting this property, we try to unspaghettify the control graph of the module:

With C code, some local declarations may have been lost by the (current) restructurer. FI: not investigated; should be useless by now..

Reorder the module, because we have a new statement structure.

Parameters
module_nameodule_name

Definition at line 102 of file module.c.

103 {
104  if (getenv(USE_OLD_CONTROLIZER_ENV_VAR_NAME) != NULL) {
105  pips_user_warning("Force the use of the old controlizer because a '%s' environment variable is defined\n", USE_OLD_CONTROLIZER_ENV_VAR_NAME);
106  return controlizer(module_name);
107  }
108 
110  pips_assert("Module must be defined in symbol table",!entity_undefined_p(m));
111 
112  statement module_stat, parsed_mod_stat;
113 
114  // generate pragma string or expression using the correct language:
116  if(value_code_p(mv)) {
117  code c = value_code(mv);
119  } else {
120  /* Should never happen */
122  }
123 
125 
126  parsed_mod_stat = (statement) db_get_memory_resource(DBR_PARSED_CODE, module_name, true);
127  module_stat = copy_statement(parsed_mod_stat) ;
128  /* To have the debug in unspaghettify_statement() working: */
129  set_current_module_statement(module_stat);
130 
131  debug_on("CONTROL_DEBUG_LEVEL");
132  ifdebug(1){
133  statement_consistent_p(parsed_mod_stat);
134  statement_consistent_p(module_stat);
135  }
136 
137  /* The statement of a compilation unit is a long list of continue
138  statements and it takes a long time to restructure although
139  nothing is done in the end. So, let's skip this useless
140  processing.
141  SG:it may be ok to skip it, but we still need to call module_reorder ...
142  */
144  /* *module_stat can be re-used because control_graph reallocates
145  statements; do not show that to any student!
146  statement_instruction(module_stat) =
147  make_instruction(is_instruction_unstructured,
148  control_graph(module_stat));
149  Maintenant que je nettoie le code aussi avant le controlizer,
150  un programme sans instruction ne contient qu'un statement
151  RETURN, c'est a` dire un statement de CALL vers RETURN avec le
152  label 00000. Comme la ligne ci-dessus recycle le label et le
153  commentaire, on se retrouve avec un unstructured avec le label
154  et le commentaire du RETURN qu'il contient... En plus il y avait
155  une re'cursion de l'unstructured vers module_stat. :-(
156 
157  So now correct the label and the comment: */
158 
159  pips_assert("the module statement is consistent "
160  "before the controlizer is called",
161  statement_consistent_p(module_stat));
162 
163  module_stat = hcfg(module_stat);
164 
165  pips_assert("the module statement is consistent "
166  "after the controlizer call",
167  statement_consistent_p(module_stat));
168 
169  if (get_bool_property("FOR_TO_DO_LOOP_IN_CONTROLIZER")) {
170  gen_recurse(module_stat,
171  // Since for-loop statements can be nested,
172  // only restructure in a bottom-up way, :
175 
176  }
177 
178  if (get_bool_property("FOR_TO_WHILE_LOOP_IN_CONTROLIZER")) {
179  gen_recurse(module_stat,
180  // Since for-loop statements can be nested,
181  // only restructure in a bottom-up way, :
182  //forloop_domain, gen_true,
183  //transform_a_for_loop_into_a_while_loop);
186  }
187 
188  /* By setting this property, we try to unspaghettify the control graph
189  of the module: */
190  if (get_bool_property("UNSPAGHETTIFY_IN_CONTROLIZER"))
191  unspaghettify_statement(module_stat);
192 
193  /* With C code, some local declarations may have been lost by the
194  (current) restructurer. FI: not investigated; should be
195  useless by now.. */
196  if(c_module_p(m))
197  module_stat = update_unstructured_declarations(module_stat);
198 
199  }
200 
201  /* Reorder the module, because we have a new statement structure. */
202  module_reorder(module_stat);
203 
204  statement_consistent_p(module_stat);
205 
206  DB_PUT_MEMORY_RESOURCE(DBR_CODE, module_name, module_stat);
207 
210 
211  debug_off();
212 
213  return true;
214 }
#define USE_OLD_CONTROLIZER_ENV_VAR_NAME
The name of the one to force the use of the old controlizer:
Definition: control-local.h:35
void transform_a_for_loop_statement_into_a_while_loop(statement)
Same as above, but with no calls to ancestors.
void try_to_transform_a_for_loop_into_a_do_loop(forloop)
Try to to transform the C-like for-loops into Fortran-like do-loops.
statement hcfg(statement)
Compute the hierarchical control flow graph (HCFG) of a statement.
Definition: controlizer.c:2621

References c_module_p(), code_language, compilation_unit_p(), controlizer(), copy_statement(), db_get_memory_resource(), DB_PUT_MEMORY_RESOURCE, debug_off, debug_on, entity_initial, entity_undefined_p, forloop_domain, gen_recurse, gen_true(), get_bool_property(), hcfg(), ifdebug, is_language_fortran, language_tag, module_name(), module_name_to_entity(), module_reorder(), pips_assert, pips_user_warning, reset_current_module_entity(), reset_current_module_statement(), set_current_module_entity(), set_current_module_statement(), set_prettyprint_language_from_property(), statement_consistent_p(), statement_domain, transform_a_for_loop_statement_into_a_while_loop(), try_to_transform_a_for_loop_into_a_do_loop(), unspaghettify_statement(), update_unstructured_declarations(), USE_OLD_CONTROLIZER_ENV_VAR_NAME, value_code, and value_code_p.

Referenced by controlizer().

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

◆ next_ctrl_graph_travel()

bool next_ctrl_graph_travel ( statement ps)
Parameters
pss

Definition at line 325 of file graph.c.

326 {
327  while (!to_see_empty_p())
328  {
329  *ps = to_see_pop();
330  if ((*travel_decision)(*ps))
331  {
332  push_successors(*ps);
333  return true;
334  }
335  }
336 
337  return false;
338 }

References push_successors(), and travel_decision.

Referenced by handle_independent_directive(), handle_reduction_directive(), and propagate_synonym().

+ 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_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
static int useless(Pproblem XX, int i)
Definition: isolve.c:521
#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:

◆ 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:

◆ reset_ctrl_graph()

void reset_ctrl_graph ( void  )

◆ restructure_control()

bool restructure_control ( const string  mod_name)

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

as in unspaghettify.

Do also test restructuring and control graph recursive graph decomposition.

Get the true resource, not a copy.

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

Parameters
mod_nameod_name

Definition at line 1492 of file unspaghettify.c.

1493 {
1494  statement mod_stmt;
1495 
1496  /* Get the true resource, not a copy. */
1497  mod_stmt = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
1498  set_current_module_statement(mod_stmt);
1499 
1501 
1502  restructure_statement(mod_stmt);
1503 
1504  /* Reorder the module, because new statements may have been
1505  changed. */
1506  module_reorder(mod_stmt);
1507 
1508  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(mod_name), mod_stmt);
1509 
1512 
1513  return true;
1514 }
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
char * strdup()
void restructure_statement(statement mod_stmt)
The real entry point of control graph restructuring:

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

+ Here is the call graph for this function:

◆ restructure_statement()

void restructure_statement ( statement  mod_stmt)

The real entry point of control graph restructuring:

Parameters
mod_stmtod_stmt

Definition at line 1477 of file unspaghettify.c.

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

References currently_apply_recursive_decomposition, currently_apply_test_restructuring, and unspaghettify_or_restructure_statement().

Referenced by restructure_control().

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

◆ set_ctrl_graph()

void set_ctrl_graph ( controlmap  )

◆ simple_restructure_statement()

void simple_restructure_statement ( statement  mod_stmt)

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

Used by example by PHRASE.

Parameters
mod_stmtod_stmt

Definition at line 1435 of file unspaghettify.c.

1436 {
1439 
1441 }

References currently_apply_recursive_decomposition, currently_apply_test_restructuring, and unspaghettify_or_restructure_statement().

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

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

◆ statement_continued_p()

bool statement_continued_p ( statement  s)

Test if the execution goes on after the given statement.

For example it is false after a "return" in C

Definition at line 242 of file unreachable.c.

243 {
244  if (bound_continued_p(s))
245  return continued_p(s);
246  else
247  return false;
248 }
#define continued_p(s)
Definition: unreachable.c:51

References continued_p.

◆ statement_reachable_p()

bool statement_reachable_p ( statement  s)

Test if the given statement is reachable from some statements given at init_reachable(start)

Definition at line 234 of file unreachable.c.

235 {
236  return reached_p(s);
237 }
#define reached_p(s)
A mapping to store if a given statement is reachable from the control flow point of view:
Definition: unreachable.c:50

References reached_p.

Referenced by statement_to_postcondition(), and statement_to_total_precondition().

+ Here is the caller graph for this function:

◆ store_ctrl_graph()

void store_ctrl_graph ( statement  ,
control   
)

Referenced by stmt_rewrite().

+ Here is the caller graph for this function:

◆ store_or_update_ctrl_graph()

void store_or_update_ctrl_graph ( statement  ,
control   
)

◆ take_out_the_exit_node_if_not_a_continue()

statement take_out_the_exit_node_if_not_a_continue ( statement  s)

Extract the statement from an exit node of an unstructured statement if it is a useful statement.

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

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

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

To return and keep track of the unstructured:

ifdebug(5) {

pips_debug(5,

"Statement at entry:\n");

print_statement(s);

}

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

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

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

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

...followed by the last statements:

Fix the variables for the following pass:

Here the_exit_statement is not a sequence.

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

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

Keep track of the statement number:

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

Definition at line 734 of file unspaghettify.c.

735 {
737 
738  pips_assert("take_out_the_exit_node_if_not_a_continue :"
739  "The statement must be an unstructured",
741 
742  /* To return and keep track of the unstructured: */
743  statement the_unstructured = s;
745  control exit_node = unstructured_exit(u);
746  statement the_exit_statement = control_statement(exit_node);
747  instruction the_exit_instruction;
748 
749  /* ifdebug(5) { */
750  /* pips_debug(5, */
751  /* "Statement at entry:\n"); */
752  /* print_statement(s); */
753  /* } */
754 
755  /* First, linearize the exit statement since
756  fuse_sequences_in_unstructured() may have gathered many
757  statements in a messy way: */
758  clean_up_sequences_internal(the_exit_statement);
759  the_exit_instruction =
760  statement_instruction(the_exit_statement);
761 
762  /* Then normalize to have only one non-sequence statement as the
763  exit node: */
764  if (instruction_sequence_p(the_exit_instruction)
765  && !nop_statement_p(the_exit_statement)) {
766  list first_statement_list;
767  statement first_statement, last_statements;
768 
769  list the_statements =
770  sequence_statements(instruction_sequence(the_exit_instruction));
771  pips_assert("the_statements must be a true sequence",
772  gen_length(the_statements) >= 2);
773 
774  /* Well, this should be always true if the sequence
775  survived to clean_up_sequences_rewrite()... */
776  first_statement_list = the_statements;
777  first_statement = STATEMENT(CAR(first_statement_list));
778  the_statements = CDR(the_statements);
779  CDR(first_statement_list) = NIL;
780  gen_free_list(first_statement_list);
781 
782  last_statements = the_exit_statement;
783  sequence_statements(instruction_sequence(the_exit_instruction)) =
784  the_statements;
785 
786  control_statement(exit_node) = first_statement;
787  /* Then, append the last statements at the end of the
788  unstructured: */
789  the_unstructured = instruction_to_statement(i);
792  the_unstructured,
793  /* ...followed by the last
794  statements: */
795  CONS(STATEMENT,
796  last_statements,
797  NIL)));
798  /* Fix the variables for the following pass: */
799  the_exit_statement = first_statement;
800  the_exit_instruction = statement_instruction(the_exit_statement);
801  }
802  /* Here the_exit_statement is not a sequence. */
803  if (! empty_statement_or_continue_p(the_exit_statement)
804  && ! return_statement_p(the_exit_statement)) {
805  statement new_statement;
806  statement out_keeping;
807  /* Put an empty exit node and keep the statement for the
808  label: */
809  statement_instruction(the_exit_statement) =
811  ifdebug (1)
812  pips_assert("Statement is consistent", statement_consistent_p(the_exit_statement));
813  /* Replace the unstructured by an unstructured followed by the
814  out-keeped instruction: */
815  new_statement = instruction_to_statement(i);
816  out_keeping = instruction_to_statement(the_exit_instruction);
817  /* Keep track of the statement number: */
818  statement_number(out_keeping) = statement_number(the_exit_statement);
819  statement_instruction(the_unstructured) =
821  new_statement,
822  CONS(STATEMENT, out_keeping, NIL)));
823  the_unstructured = new_statement;
824  }
825  /* Heavily rely on a later clean_up_sequences to normalize the
826  above... */
827 
828  ifdebug (1)
829  pips_assert("Statement is consistent", statement_consistent_p(s));
830 
831  return the_unstructured;
832 }
bool clean_up_sequences_internal(statement s)
An entry point for internal usage, such as from take_out_the_exit_node_if_not_a_continue():
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
instruction make_continue_instruction()
Creates a CONTINUE instruction, that is the FORTRAN nop, the ";" in C or the "pass" in Python for exa...
Definition: instruction.c:79
bool nop_statement_p(statement)
Definition: statement.c:407
bool return_statement_p(statement)
Test if a statement is a C or Fortran "return".
Definition: statement.c:172
#define instruction_sequence_p(x)
Definition: ri.h:1512
#define instruction_sequence(x)
Definition: ri.h:1514
#define instruction_unstructured_p(x)
Definition: ri.h:1530

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

Referenced by recursively_restructure_an_unstructured().

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

◆ transform_a_for_loop_into_a_while_loop()

void transform_a_for_loop_into_a_while_loop ( forloop  f)

Try to to transform the C-like for-loops into Fortran-like do-loops.

Assume we are in a gen_recurse since we use gen_get_recurse_ancestor(f).

The forloop is freed and replaced by a while loop in the statement owning the for-loop

Get the instruction owning the forloop:

Get the statement owning instruction owning the forloop:

Get a sequence with a while-loop instead:

These fields have been re-used, so protect them from memory recycling:

We need to replace the for-loop instruction by the sequence instruction. The cleaner way should be to delete the first one and make the other one, but since we are in a gen_recurse() and we iterate on the first one, it is dangerous. Well, I've tried and it works, but valgrind complains a bit. :-)

So change the type of the instruction on the fly instead:

And discard the old for:

Since we have replaced a statement that may have comments and labels by a sequence, do not forget to forward them where they can be:

FI: one issue: st is an ancestor of the current object and some of its pointers are going to be modified although they are being processed by gen_recurse()...

Removed useless instructions that may remain:

ifdebug(5) {

print_statement(st);

pips_debug(5, "Exiting with statement\n");

}

Definition at line 876 of file for_to_do_or_while_loops.c.

876  {
877  pips_debug(5, "Begin\n");
878 
879  /* Get the instruction owning the forloop: */
881  /* Get the statement owning instruction owning the forloop: */
883 
884  /* Get a sequence with a while-loop instead: */
888  forloop_body(f),
890 
891  /* These fields have been re-used, so protect them from memory
892  recycling: */
897 
898  /* We need to replace the for-loop instruction by the sequence
899  instruction. The cleaner way should be to delete the first one and
900  make the other one, but since we are in a gen_recurse() and we
901  iterate on the first one, it is dangerous. Well, I've tried and it
902  works, but valgrind complains a bit. :-)
903 
904  So change the type of the instruction on the fly instead: */
906  instruction_sequence(i) = wls;
907  /* And discard the old for: */
908  free_forloop(f);
909 
910  /* Since we have replaced a statement that may have comments and labels
911  by a sequence, do not forget to forward them where they can be: */
912  /* FI: one issue: st is an ancestor of the current object and some
913  of its pointers are going to be modified although they are being
914  processed by gen_recurse()... */
916 
917  /* Removed useless instructions that may remain: */
918  clean_up_sequences(st);
919 
920  /* ifdebug(5) { */
921  /* print_statement(st); */
922  /* pips_debug(5, "Exiting with statement\n"); */
923  /* } */
924 }
void free_forloop(forloop p)
Definition: ri.c:992
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
sequence for_to_while_loop_conversion(expression init, expression cond, expression incr, statement body, extensions exts)
Build a sequence with a while-loop from for-loop parameters.
gen_chunk * gen_get_recurse_ancestor(const void *)
Get the first ancestor object encountered during the recursion for the given object.
Definition: genClib.c:3546
void fix_sequence_statement_attributes(statement)
Since blocks are not represented in Fortran, they cannot carry a label.
Definition: statement.c:2016
@ is_instruction_sequence
Definition: ri.h:1469
#define instruction_tag(x)
Definition: ri.h:1511
struct _newgen_struct_instruction_ * instruction
Definition: ri.h:207

References clean_up_sequences(), expression_undefined, f(), fix_sequence_statement_attributes(), for_to_while_loop_conversion(), forloop_body, forloop_condition, forloop_increment, forloop_initialization, free_forloop(), gen_get_recurse_ancestor(), instruction_sequence, instruction_tag, is_instruction_sequence, pips_debug, statement_extensions, and statement_undefined.

+ Here is the call graph for this function:

◆ transform_a_for_loop_statement_into_a_while_loop()

void transform_a_for_loop_statement_into_a_while_loop ( statement  st)

Same as above, but with no calls to ancestors.

Get the instruction owning the forloop:

Get the statement owning instruction owning the forloop:

Get a sequence with a while-loop instead:

These fields have been re-used, so protect them from memory recycling:

We need to replace the for-loop instruction by the sequence instruction. The cleaner way should be to delete the first one and make the other one, but since we are in a gen_recurse() and we iterate on the first one, it is dangerous. Well, I've tried and it works, but valgrind complains a bit. :-)

So change the type of the instruction on the fly instead:

And discard the old for:

Since we have replaced a statement that may have comments and labels by a sequence, do not forget to forward them where they can be:

FI: one issue: st is an ancestor of the current object and some of its pointers are going to be modified although they are being processed by gen_recurse()...

Removed useless instructions that may remain:

ifdebug(5) {

print_statement(st);

pips_debug(5, "Exiting with statement\n");

}

Parameters
stt

Definition at line 928 of file for_to_do_or_while_loops.c.

928  {
929  if(forloop_statement_p(st)) {
930  pips_debug(5, "Begin\n");
931 
932  /* Get the instruction owning the forloop: */
933  //instruction i = (instruction) gen_get_recurse_ancestor(f);
935  /* Get the statement owning instruction owning the forloop: */
936  //statement st = (statement) gen_get_recurse_ancestor(i);
938 
939  /* Get a sequence with a while-loop instead: */
943  forloop_body(f),
945 
946  /* These fields have been re-used, so protect them from memory
947  recycling: */
952 
953  /* We need to replace the for-loop instruction by the sequence
954  instruction. The cleaner way should be to delete the first one and
955  make the other one, but since we are in a gen_recurse() and we
956  iterate on the first one, it is dangerous. Well, I've tried and it
957  works, but valgrind complains a bit. :-)
958 
959  So change the type of the instruction on the fly instead: */
961  instruction_sequence(i) = wls;
962  /* And discard the old for: */
963  free_forloop(f);
964 
965  /* Since we have replaced a statement that may have comments and labels
966  by a sequence, do not forget to forward them where they can be: */
967  /* FI: one issue: st is an ancestor of the current object and some
968  of its pointers are going to be modified although they are being
969  processed by gen_recurse()... */
971 
972  /* Removed useless instructions that may remain: */
973  clean_up_sequences(st);
974 
975  /* ifdebug(5) { */
976  /* print_statement(st); */
977  /* pips_debug(5, "Exiting with statement\n"); */
978  /* } */
979  }
980 }
bool forloop_statement_p(statement)
Definition: statement.c:209
#define instruction_forloop(x)
Definition: ri.h:1538

References clean_up_sequences(), expression_undefined, f(), fix_sequence_statement_attributes(), for_to_while_loop_conversion(), forloop_body, forloop_condition, forloop_increment, forloop_initialization, forloop_statement_p(), free_forloop(), instruction_forloop, instruction_sequence, instruction_tag, is_instruction_sequence, pips_debug, statement_extensions, statement_instruction, and statement_undefined.

Referenced by for_loop_to_while_loop(), and new_controlizer().

+ Here is the call graph for this function:
+ 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:

◆ try_to_transform_a_for_loop_into_a_do_loop()

void try_to_transform_a_for_loop_into_a_do_loop ( forloop  f)

Try to to transform the C-like for-loops into Fortran-like do-loops.

Assume we are in a gen_recurse since we use gen_get_recurse_ancestor(f).

Get the englobing statement of the "for" assuming we are called from a gen_recurse()-like function:

Definition at line 740 of file for_to_do_or_while_loops.c.

740  {
741 
742  /* Get the englobing statement of the "for" assuming we are called
743  from a gen_recurse()-like function: */
744  statement parent=
747 
748  sequence new_l = for_to_do_loop_conversion(f,parent);
749 
750  if (!sequence_undefined_p(new_l)) {
751  pips_debug(3, "do-loop has been generated.\n");
757  free_forloop(f);
758  }
759 }
sequence for_to_do_loop_conversion(forloop theloop, statement parent)
Try to convert a C-like for-loop into a Fortran-like do-loop.
#define sequence_undefined_p(x)
Definition: ri.h:2339

References expression_undefined, f(), for_to_do_loop_conversion(), forloop_body, forloop_condition, forloop_increment, forloop_initialization, free_forloop(), gen_get_recurse_ancestor(), make_instruction_sequence(), pips_debug, sequence_undefined_p, statement_instruction, and statement_undefined.

Referenced by for_loop_to_do_loop(), and new_controlizer().

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

◆ unspaghettify()

bool unspaghettify ( const string  mod_name)

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

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

Unspaguettify is now targetted to be included in the controlizer.

Get the true resource, not a copy.

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

Parameters
mod_nameod_name

Definition at line 1450 of file unspaghettify.c.

1451 {
1452  statement mod_stmt;
1453 
1454  /* Get the true resource, not a copy. */
1455  mod_stmt = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
1456  set_current_module_statement(mod_stmt);
1457 
1459 
1460  unspaghettify_statement(mod_stmt);
1461 
1462  /* Reorder the module, because new statements may have been
1463  changed. */
1464  module_reorder(mod_stmt);
1465 
1466  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(mod_name), mod_stmt);
1467 
1470 
1471  return true;
1472 }
void unspaghettify_statement(statement mod_stmt)
The real entry point of unspaghettify:

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

+ Here is the call graph for this function:

◆ unspaghettify_or_restructure_statement()

void unspaghettify_or_restructure_statement ( statement  mod_stmt)

The entry point common to unspaghettify or restructure a module:

Track the number of restructurations done for a fix point:

To track the number of restructuring iterations:

ifdebug(5) {

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

print_statement(mod_stmt);

}

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

First, clean up easy things done by the controlizer:

Then try to hierarchize the control flow:

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

End by removing parasitic sequences:

If something changed, retry further restructuring:

ifdebug(5) {

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

print_statement(mod_stmt);

}

Parameters
mod_stmtod_stmt

Definition at line 1330 of file unspaghettify.c.

1331 {
1332  /* Track the number of restructurations done for a fix point: */
1333  int nr = 0;
1334  int old_nr;
1335  /* To track the number of restructuring iterations: */
1336  int iter = 0;
1337 
1338  // Note that this debug is not controlled by "UNSPAGHETTIFY_DEBUG_LEVEL":
1339  /* ifdebug(5) { */
1340  /* pips_debug(5, "Statement before unspaghettify_or_restructure_statement:\n"); */
1341  /* print_statement(mod_stmt); */
1342  /* } */
1343 
1344  debug_on("UNSPAGHETTIFY_DEBUG_LEVEL");
1345 
1346  ifdebug (1)
1347  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1348 
1349  if (get_bool_property("GATHER_FORMATS_AT_BEGINNING"))
1351  else if (get_bool_property("GATHER_FORMATS_AT_END"))
1352  put_formats_at_module_end(mod_stmt);
1353 
1354  ifdebug (1)
1355  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1356 
1358 
1359  do {
1360  old_nr = nr;
1361  /* Split the recursion in three parts to fit in my brain: */
1362  /* First, clean up easy things done by the controlizer: */
1363  gen_recurse(mod_stmt, statement_domain,
1365 
1366  ifdebug (1)
1367  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1368 
1370  /* Then try to hierarchize the control flow: */
1371  gen_recurse(mod_stmt, unstructured_domain,
1373 
1374  ifdebug (1)
1375  pips_assert("Statement is consistent",
1376  statement_consistent_p(mod_stmt));
1377  }
1378 
1379  /* Now apply some local rule, such as if/then/else restructuring
1380  and so on: */
1381  gen_recurse(mod_stmt, statement_domain,
1383 
1384  ifdebug (1)
1385  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1386 
1387  if (get_bool_property("UNSPAGHETTIFY_WHILE_RECOVER"))
1388  gen_recurse(mod_stmt, unstructured_domain,
1390 
1391  /* End by removing parasitic sequences: */
1392  clean_up_sequences(mod_stmt);
1393 
1394  ifdebug (1)
1395  pips_assert("Statement is consistent", statement_consistent_p(mod_stmt));
1396 
1397  /* If something changed, retry further restructuring: */
1399  ifdebug(2)
1401  } while (nr != old_nr && ++iter < N_ITER_RESTRUCTURE_FIX_POINT);
1402 
1403  if (nr != old_nr)
1404  pips_user_warning("Possible infinite loop restructuring found.\n");
1405 
1406  pips_debug(2, "done\n");
1407 
1409 
1410  debug_off();
1411  // Note that this debug is not controlled by "UNSPAGHETTIFY_DEBUG_LEVEL":
1412  /* ifdebug(5) { */
1413  /* pips_debug(5, "Statement after unspaghettify_or_restructure_statement:\n"); */
1414  /* print_statement(mod_stmt); */
1415  /* } */
1416 }
void control_graph_recursive_decomposition(unstructured)
hierarchize.c
Definition: hierarchize.c:563
void put_formats_at_module_beginning(statement)
Transfer all the FORMATs at the very beginning of a module:
Definition: statement.c:2311
void put_formats_at_module_end(statement)
Transfer all the FORMATs at the very end of a module:
Definition: statement.c:2328
#define unstructured_domain
newgen_type_domain_defined
Definition: ri.h:442
else
Definition: set.c:239
@ N_ITER_RESTRUCTURE_FIX_POINT
Definition: unspaghettify.c:53
static void display_unspaghettify_statistics()
Definition: unspaghettify.c:99
static int total_number_of_restructurations()
Compute the number of all the computations that have been done.
Definition: unspaghettify.c:89
static void initialize_unspaghettify_statistics()
Definition: unspaghettify.c:76
static void recursively_restructure_an_unstructured(statement s)
Try to recursively restructure the unstructured:
static void recover_structured_while(unstructured u)
Try to recover structured while loops in an already recursively restructured control graph.
static void clean_up_control(statement s)
This is the function that is applied on each statement of the code in a bottom-up way to clean up eas...

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

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

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

◆ unspaghettify_statement()

void unspaghettify_statement ( statement  mod_stmt)

The real entry point of unspaghettify:

Parameters
mod_stmtod_stmt

Definition at line 1421 of file unspaghettify.c.

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

References currently_apply_recursive_decomposition, currently_apply_test_restructuring, get_bool_property(), STUB_ERROR, and unspaghettify_or_restructure_statement().

Referenced by controlizer(), copy_value_of_write(), copy_value_of_write_with_cumulated_regions(), mpi_conversion(), new_controlizer(), ProcessEntry(), and unspaghettify().

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

◆ unstructured_consistency_p()

bool unstructured_consistency_p ( unstructured  u,
bool  assert_p 
)

cfg.c

cfg.c

Francois Irigoin, 1997. Check some nice properties expected to be true after a powerful enough controlizer phase.

The calls to pips_assert could be replaced by calls to user_warning, the control graph could be printed out before core dumping,...

See also check_control_coherency().

the exit and entry nodes must be different or the unstructured would have been reduced to one structured statement

The entry node must have at least one predecessor: else it should have been moved out of the unstructured. Note that it has in fact TWO predecessors since it is the unstructured entry point.

The exit node should have no successors: its real successor is the statement following the unstructured

The exit node should not be a test: else one of its successors should be control_undefined since it would be outside of the unstructured, or the exit condition would be unknown.

The exit node may have no predecessor because an infinite loop appears in the code. Or it is a successor of the entry node.

RK: ??? If the exit node is unreachable, it should be a CONTINUE Since a CONTINUE has no effects, it does not perturb analyses even if they do not check reachability. RK: The NOP might be the empty sequence instead of a CONTINUE?

If the exit node has only one predecessor, it should be a test or the exit node would have been moved outside of the unstructured.

Since sequences are merged into a unique node, if a node c1 has only one successor c2, and if c2 has only one predecessor c3, c3 must be c1 and either c1 is the exit node which is impossible because there would be no exit condition and the exit node would have a successor, c2, or c2 is the entry node. So c2 must be the entry node.

Well, this is not true because only tests can have two successors. hence, a test node cannot be merged.

Parameters
assert_pssert_p

Definition at line 52 of file cfg.c.

53 {
54  control entry_node = unstructured_control(u);
55  control exit_node = unstructured_exit(u);
56  bool consistency_p = true;
57  list nodes = NIL;
58 
59  forward_control_map_get_blocs(entry_node, &nodes);
60 
61  /* the exit and entry nodes must be different or the
62  * unstructured would have been reduced to one structured statement
63  */
64  if(exit_node==entry_node) {
65  consistency_p = false;
66  if(assert_p) pips_assert("Entry and exit nodes are different", false);
67  }
68 
69  /* The entry node must have at least one predecessor:
70  * else it should have been moved out of the unstructured.
71  * Note that it has in fact TWO predecessors since it is the
72  * unstructured entry point.
73  */
74  if(consistency_p && ENDP(control_predecessors(entry_node))) {
75  consistency_p = false;
76  if(assert_p) pips_assert("Entry node has at least one predecessor", false);
77  }
78 
79  /* The exit node should have no successors: its real successor
80  * is the statement following the unstructured
81  */
82  if(consistency_p && !ENDP(control_successors(exit_node))) {
83  consistency_p = false;
84  if(assert_p) pips_assert("Exit node has no successor", false);
85  }
86 
87  /* The exit node should not be a test:
88  * else one of its successors should be control_undefined
89  * since it would be outside of the unstructured, or the
90  * exit condition would be unknown.
91  */
92  if(consistency_p) {
93  statement exit_s = control_statement(exit_node);
94  if(statement_test_p(exit_s)) {
95  consistency_p = false;
96  if(assert_p) pips_assert("Exit node is not a test", false);
97  }
98  }
99 
100  /* The exit node may have no predecessor because an infinite loop
101  * appears in the code. Or it is a successor of the entry node.
102  */
103  if(consistency_p && !ENDP(control_predecessors(exit_node))) {
104  if(gen_find_eq(exit_node, nodes)!=exit_node) {
105  consistency_p = false;
106  if(assert_p) pips_assert("Exit node has predecessors but is unreachable", false);
107  }
108  }
109 
110  /* RK: ??? If the exit node is unreachable, it should be a CONTINUE
111  * Since a CONTINUE has no effects, it does not perturb analyses even
112  * if they do not check reachability.
113  * RK: The NOP might be the empty sequence instead of a CONTINUE?
114  */
115  if(consistency_p && ENDP(control_predecessors(exit_node))) {
116  statement exit_s = control_statement(exit_node);
117 
118  if(!continue_statement_p(exit_s)) {
119  consistency_p = false;
120  if(assert_p) pips_assert("Unreachable exit node is a CONTINUE statement", false);
121  }
122  }
123 
124  /* If the exit node has only one predecessor, it should
125  * be a test or the exit node would have been moved outside of
126  * the unstructured.
127  */
128  if(consistency_p && gen_length(control_predecessors(exit_node))==1) {
129  control c = CONTROL(CAR(control_predecessors(exit_node)));
131 
132  if(!statement_test_p(s)) {
133  consistency_p = false;
134  if(assert_p) pips_assert("Unique predecessor of exit node is a test", false);
135  }
136  }
137 
138  /* Since sequences are merged into a unique node, if a node c1 has only one
139  * successor c2, and if c2 has only one predecessor c3, c3 must be c1
140  * and either c1 is the exit node which is impossible because there
141  * would be no exit condition and the exit node would have a
142  * successor, c2, or c2 is the entry node. So c2 must be the entry node.
143  *
144  * Well, this is not true because only tests can have two successors.
145  * hence, a test node cannot be merged.
146  */
147  MAP(CONTROL, c1, {
148  if(gen_length(control_successors(c1))==1) {
150  statement s2 = control_statement(c2);
151 
152  if(gen_length(control_predecessors(c2))==1) {
154  if(c1!=c3) {
155  consistency_p = false;
156  if(assert_p) {
157  (void) fprintf(stderr,
158  "\nEntry node: %p\nExit node: %p\n"
159  "c1 node: %p\nc2 node: %p\nc3 node: %p\n",
160  entry_node, exit_node, c1, c2, c3);
161  display_linked_control_nodes(entry_node);
162  pips_assert("c3, the unique predecessor of the unique successor of c1, is c1",
163  false);
164  }
165  }
166  else if(c2!=entry_node && !statement_test_p(s2)) {
167  consistency_p = false;
168  if(assert_p) {
169  (void) fprintf(stderr,
170  "\nEntry node: %p\nExit node: %p\nc1 node: %p\nc2 node: %p\n\n",
171  entry_node, exit_node, c1, c2);
172  display_linked_control_nodes(entry_node);
173  pips_assert("c2 is the unique successor of c1. "
174  "c2 has c1 as unique predecessor. c2 must be the entry node",
175  false);
176  }
177  }
178  }
179 
180  }
181  }, nodes)
182 
183  gen_free_list(nodes);
184 
185  return consistency_p;
186 }
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
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
void * gen_find_eq(const void *item, const list seq)
Definition: list.c:422
bool continue_statement_p(statement)
Test if a statement is a CONTINUE, that is the FORTRAN nop, the ";" in C or the "pass" in Python....
Definition: statement.c:203

References CAR, continue_statement_p(), CONTROL, control_predecessors, control_statement, control_successors, display_linked_control_nodes(), ENDP, forward_control_map_get_blocs(), fprintf(), gen_find_eq(), gen_free_list(), gen_length(), MAP, NIL, pips_assert, statement_test_p(), unstructured_control, and unstructured_exit.

Referenced by unstructured_while_p().

+ 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
static void add_child_parent_pair(hash_table ancestor_map, control child, control parent)
Definition: bourdoncle.c:934
#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:

◆ unstructured_while_p()

bool unstructured_while_p ( unstructured  u)

Test if an unstructured is found to be like a structured while-loop.

Make sure that the unstructured has been "normalized"

while_p = unstructured_consistency_p(u, true);

An unstructured is a while loop if and only if the exit node has only one predecessor and if the entry node is a successor of the predecessor of the exit node.

A loop with two exit conditions is not recognized as a while loop.

A loop with an exit test on entry, a final exit test (do...while) or an exit test anywhere is recognized as a while loop.

Definition at line 191 of file cfg.c.

192 {
193  control entry_node = unstructured_control(u);
194  control exit_node = unstructured_exit(u);
195  bool while_p = false;
196 
197  ifdebug(5) {
198  debug(5, "unstructured_while_p", "Begin with graph\n");
199  (void) fprintf(stderr,
200  "\nEntry node: %p\nExit node: %p\n\n",
201  entry_node, exit_node);
202  display_linked_control_nodes(entry_node);
203  }
204 
205  /* Make sure that the unstructured has been "normalized" */
206  /* while_p = unstructured_consistency_p(u, true); */
207  while_p = unstructured_consistency_p(u, false);
208 
209  /* An unstructured is a while loop if and only if the exit node
210  * has only one predecessor and if the entry node is a successor
211  * of the predecessor of the exit node.
212  *
213  * A loop with two exit conditions is not recognized as a while loop.
214  *
215  * A loop with an exit test on entry, a final exit test (do...while) or
216  * an exit test anywhere is recognized as a while loop.
217  */
218 
219  if(while_p && gen_length(control_predecessors(exit_node))==1) {
220  control pred = CONTROL(CAR(control_predecessors(exit_node)));
221  list succs = NIL;
222 
223  forward_control_map_get_blocs(pred, &succs);
224 
225  if(gen_find_eq(entry_node, succs)==entry_node) {
226  while_p = true;
227  }
228  gen_free_list(succs);
229  }
230  else {
231  while_p = false;
232  }
233 
234  debug(5, "unstructured_while_p", "End with while_p=%s\n", bool_to_string(while_p));
235 
236  return while_p;
237 }
bool unstructured_consistency_p(unstructured u, bool assert_p)
Basic functions about control flow graphs (CFG), aka unstructured data structure.
Definition: cfg.c:52
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
string bool_to_string(bool)
Definition: string.c:243

References bool_to_string(), CAR, CONTROL, control_predecessors, debug(), display_linked_control_nodes(), forward_control_map_get_blocs(), fprintf(), gen_find_eq(), gen_free_list(), gen_length(), ifdebug, NIL, unstructured_consistency_p(), unstructured_control, and unstructured_exit.

Referenced by instruction_flt(), and instruction_rwt().

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

◆ unsugared_whileloop_header()

statement unsugared_whileloop_header ( statement  )

◆ update_ctrl_graph()

void update_ctrl_graph ( statement  ,
control   
)

Variable Documentation

◆ vcid_control_controlizer

char vcid_control_controlizer[]
extern

cproto-generated files

controlizer.c

cproto-generated files

Definition at line 40 of file controlizer.c.

◆ vcid_control_old_controlizer

char vcid_control_old_controlizer[]
extern

old_controlizer.c

Definition at line 29 of file old_controlizer.c.

◆ vcid_unspaghettify

char vcid_unspaghettify[]
extern

unspaghettify.c

unspaghettify.c

Definition at line 30 of file unspaghettify.c.