PIPS
unstructured.c File Reference
#include <stdio.h>
#include <string.h>
#include "genC.h"
#include "database.h"
#include "linear.h"
#include "ri.h"
#include "effects.h"
#include "text.h"
#include "text-util.h"
#include "ri-util.h"
#include "effects-util.h"
#include "constants.h"
#include "control.h"
#include "effects-generic.h"
#include "effects-simple.h"
#include "misc.h"
#include "properties.h"
#include "vecteur.h"
#include "contrainte.h"
#include "ray_dte.h"
#include "sommet.h"
#include "sg.h"
#include "polyedre.h"
#include "transformer.h"
#include "semantics.h"
+ Include dependency graph for unstructured.c:

Go to the source code of this file.

Data Structures

struct  recursive_context
 

Functions

static void print_control_node_uns (control c)
 semantical analysis More...
 
static void print_control_node_unss_sem (list l)
 
static transformer load_control_postcondition (control c, control_mapping control_postcondition_map)
 
static transformer load_arc_precondition (control, control, control_mapping)
 forward declaration More...
 
static transformer get_control_precondition (control c, control_mapping control_postcondition_map, unstructured u, transformer pre_entry)
 
static void store_control_postcondition (control c, transformer post, control_mapping control_postcondition_map)
 
static void update_control_postcondition (control c, transformer post, control_mapping control_postcondition_map)
 
void print_control_postcondition_map (control_mapping control_postcondition_map)
 unstructured.c More...
 
static control_mapping make_control_postcondition_map ()
 
static control_mapping free_control_postcondition_map (control_mapping control_postcondition_map)
 
static transformer load_control_fix_point (control c, control_mapping control_fix_point_map, hash_table ancestor_map, hash_table scc_map)
 The fix point can be linked either to the entry node of the scc or to the ancestor node. More...
 
static void store_control_fix_point (control c, transformer fptf, control_mapping control_fix_point_map)
 
static control_mapping make_control_fix_point_map ()
 
static control_mapping free_control_fix_point_map (control_mapping control_fix_point_map)
 
static bool ready_to_be_processed_p (control c, list to_be_processed, list still_to_be_processed, list already_processed, control_mapping control_postcondition_map)
 a control is ready to be processed if all its predecessors have known postconditions or can receive a trivial empty postcondition More...
 
transformer load_cycle_fix_point (control c, hash_table fix_point_map)
 
static list unstructured_to_effects (unstructured scc, hash_table ancestor_map, hash_table scc_map)
 In fact, non-deterministic unstructured to effects. More...
 
static list non_deterministic_unstructured_to_effects (unstructured scc, hash_table ancestor_map, hash_table scc_map)
 
static void process_ready_node (control c, transformer pre_entry, transformer n_pre, unstructured u, control_mapping control_postcondition_map, hash_table ancestor_map, hash_table scc_map, list partition, control_mapping fix_point_map, bool postcondition_p)
 
static bool process_unreachable_node (control c, control_mapping control_postcondition_map, bool postcondition_p)
 
static void add_cycle_dependency (control d, control c, control_mapping cycle_dependencies_map)
 State that d depends on c: cycle c must be processed before cycle d can be processed. More...
 
static void remove_cycle_dependencies (control c, control_mapping cycle_dependencies_map)
 c has been processed and no other cycle can depend on it More...
 
static list get_cycle_dependencies (control d, control_mapping cycle_dependencies_map)
 Some cycle may appear nowhere but in the DAG and have no entries in the table. More...
 
void update_temporary_precondition (void *k, transformer pre, hash_table precondition_map)
 
void update_statement_temporary_precondition (statement s, transformer pre, statement_mapping statement_temporary_precondition_map)
 
void print_statement_temporary_precondition (statement_mapping statement_temporary_precondition_map)
 
void update_cycle_temporary_precondition (control c, transformer pre, control_mapping cycle_temporary_precondition_map)
 
transformer load_cycle_temporary_precondition (control c, control_mapping cycle_temporary_precondition_map, hash_table ancestor_map, hash_table scc_map __attribute__((__unused__)))
 
transformer load_statement_temporary_precondition (statement s, statement_mapping statement_temporary_precondition_map)
 
static void cycle_to_flow_sensitive_preconditions (list partition, unstructured c_u, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, control_mapping cycle_temporary_precondition_map, statement_mapping statement_temporary_precondition_map, transformer c_pre, transformer pre, control_mapping control_postcondition_map)
 Very likely the transformer paths wrt the entry point and not really a postcondition. More...
 
static void dag_to_flow_sensitive_preconditions (list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer pre_u, transformer pre, control_mapping control_postcondition_map)
 
transformer dag_or_cycle_to_flow_sensitive_postconditions_or_transformers (list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p, bool is_dag)
 Should ndu be a dag or a cycle? More...
 
transformer dag_to_flow_sensitive_postconditions_or_transformers (list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
 Compute transformers or preconditions. More...
 
transformer cycle_to_flow_sensitive_postconditions_or_transformers (list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
 Compute transformers or preconditions. More...
 
static void local_process_unreachable_node (control c, recursive_context *pcontext)
 
static void node_to_path_transformer_or_postcondition (control c, recursive_context *pcontext)
 A debug function to prettyprint the result. More...
 
static void print_cycle_head_to_fixpoint (control c, recursive_context *pcontext)
 A debug function to prettyprint the fix points. More...
 
transformer unstructured_to_flow_sensitive_postconditions_or_transformers (transformer pre_u, transformer pre, unstructured u, bool postcondition_p)
 compute either the postconditions in an unstructured or the transformer of this unstructured. More...
 
static transformer unstructured_to_postconditions (transformer pre, transformer pre_first, unstructured u)
 
transformer unstructured_to_flow_sensitive_postconditions (transformer pre_u, transformer pre, unstructured u)
 compute pre- and post-conditions in an unstructured from the entry precondition pre and return the exit postcondition. More...
 
transformer unstructured_to_postcondition (transformer pre, unstructured u, transformer tf)
 
static void unreachable_node_to_transformer (control c)
 
transformer unstructured_to_flow_insensitive_transformer (unstructured u)
 This simple fix-point over-approximates the CFG by a fully connected graph. More...
 
static void unstructured_to_transformers (unstructured u, transformer pre)
 Computation of transformers associated to each node of u and to each of its sub-statements. More...
 
transformer unstructured_to_transformer (unstructured u, transformer e_pre, list e)
 effects of u More...
 
transformer unstructured_to_flow_sensitive_total_preconditions (transformer t_post_u, transformer pre, unstructured u)
 

Function Documentation

◆ add_cycle_dependency()

static void add_cycle_dependency ( control  d,
control  c,
control_mapping  cycle_dependencies_map 
)
static

State that d depends on c: cycle c must be processed before cycle d can be processed.

Update the hash_table by side effect

Definition at line 934 of file unstructured.c.

935 {
936  list dependencies = (list) hash_get((hash_table) cycle_dependencies_map,
937  (void *) d);
938 
939  if(dependencies == (list) HASH_UNDEFINED_VALUE) {
940  dependencies = CONS(CONTROL, c, NIL);
941  hash_put((hash_table) (cycle_dependencies_map),
942  (void *) d, (void *) dependencies);
943  }
944  else {
945  /* Update the hash_table by side effect */
946  dependencies = gen_nconc(dependencies, CONS(CONTROL, c, NIL));
947  }
948 }
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
struct cons * list
Definition: newgen_types.h:106
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

References CONS, CONTROL, gen_nconc(), hash_get(), hash_put(), HASH_UNDEFINED_VALUE, and NIL.

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ cycle_to_flow_sensitive_postconditions_or_transformers()

transformer cycle_to_flow_sensitive_postconditions_or_transformers ( list  partition,
unstructured  ndu,
hash_table  ancestor_map,
hash_table  scc_map,
control_mapping  fix_point_map,
transformer  e_pre,
transformer  n_pre,
hash_table  control_postcondition_map,
bool  postcondition_p 
)

Compute transformers or preconditions.

Parameters
partitionartition
nduBourdoncle's processing ordering
ancestor_mapA non-deterministic acyclic control flow graph
scc_mapMapping from non-deterministic nodes to deterministic nodes
fix_point_mapmapping from deterministic nodes to non-deterministic cycles
e_premapping from cycle heads to fix point transformers
n_preprecondition on entry
control_postcondition_mapprecondition true for any node.
postcondition_postcondition_p

Definition at line 1744 of file unstructured.c.

1754 {
1756 
1758  (partition, ndu, ancestor_map, scc_map, fix_point_map, e_pre, n_pre,
1759  control_postcondition_map, postcondition_p, false);
1760 
1761  return tf;
1762 }
#define transformer_undefined
Definition: ri.h:2847
transformer dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p, bool is_dag)
Should ndu be a dag or a cycle?

References dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), and transformer_undefined.

Referenced by process_ready_node().

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

◆ cycle_to_flow_sensitive_preconditions()

static void cycle_to_flow_sensitive_preconditions ( list  partition,
unstructured  c_u,
hash_table  ancestor_map,
hash_table  scc_map,
control_mapping  fix_point_map,
control_mapping  cycle_temporary_precondition_map,
statement_mapping  statement_temporary_precondition_map,
transformer  c_pre,
transformer  pre,
control_mapping  control_postcondition_map 
)
static

Very likely the transformer paths wrt the entry point and not really a postcondition.

Let's update it as a real postcondition.

Yet another forward DAG propagation with an exception for the cycle head: cut-and-paste and adapt

forward reachable nodes in u

FI: Please the compiler complaining about useless parameters (and remove them later!)

wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed);

Take care of the entry node whose precondition does not rely on its predecessors

post = statement_to_postcondition(c_pre, es);

c_pre is USED

Propagate the postcondition downwards

process forward

right away because c's cdr might be modified

Already done earlier if(cycle_head_p(c, ancestor_map, scc_map)) { transformer fp_tf = load_control_fix_point(a, fix_point_map, ancestor_map, scc_map); e_pre = transformer_apply(fp_tf, pre); update_cycle_temporary_precondition (a, e_pre, cycle_temporary_precondition_map); } else { e_pre = transformer_dup(pre); }

fix point are unique for all replication of a cycle

(a, e_pre, cycle_temporary_precondition_map);

Go down the subcycle... when necessary... since there is a loop somewhere else and the cycles are called in the right order?

post = statement_to_postcondition(transformer_dup(e_pre), c_s);

FI: you should use the really current precondition using load_statement_temporary_precondition()

post = transformer_apply(load_statement_transformer(c_s), e_pre);

Hard to track memory leaks...

It is much too late to update the control postcondition!

update_control_postcondition(c, post, control_postcondition_map);

FI: just to see what happens, without any understanding of the process

FI: what is the point when control are replicated?

The precondition for the entry node may be improved by now using the precondition of its predecessors and the cycle entry. OK, but to what end?

Parameters
c_uIs it relevant?
ancestor_mapThe cycle unstructured
statement_temporary_precondition_mapTo be updated when a cycle head is encountered
c_preTo be updated each time a statement is encountered
preprecondition of cycle c_u, already processed with the fix point
control_postcondition_mapaproximate precondition holding for all nodes

Definition at line 1080 of file unstructured.c.

1091 {
1092  /* Yet another forward DAG propagation with an exception for the cycle
1093  head: cut-and-paste and adapt */
1094  list to_be_processed = NIL; /* forward reachable nodes in u */
1095  list still_to_be_processed = NIL;
1096  list already_processed = NIL;
1097  control e = unstructured_control(c_u);
1098  statement es = control_statement(e);
1100 
1101  /* FI: Please the compiler complaining about useless parameters (and
1102  remove them later!) */
1103  pips_assert("Please the compiler", partition==partition);
1104  pips_assert("Please the compiler",
1105  cycle_temporary_precondition_map==cycle_temporary_precondition_map);
1106  pips_assert("Please the compiler", pre==pre);
1107 
1108  /* wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed); */
1109  forward_control_map_get_blocs(unstructured_control(c_u), &to_be_processed);
1110  still_to_be_processed = gen_copy_seq(to_be_processed);
1111 
1112  /* Take care of the entry node whose precondition does not rely on its
1113  predecessors */
1114  /* post = statement_to_postcondition(c_pre, es); */ /* c_pre is USED */
1115  post = transformer_apply(load_statement_transformer(es), c_pre);
1116  update_control_postcondition(e, post, control_postcondition_map);
1117  gen_remove(&still_to_be_processed, e);
1118  already_processed = CONS(CONTROL, e, NIL);
1119 
1120  /* Propagate the postcondition downwards */
1121 
1122  while(!ENDP(still_to_be_processed)) {
1123  int count = -1;
1124  do {
1125  list l = list_undefined;
1126 
1127  /* process forward */
1128  pips_debug(5, "Try forward processing for\n");
1129  ifdebug(5) print_control_node_unss_sem(still_to_be_processed);
1130 
1131  count = 0;
1132  for(l=still_to_be_processed; !ENDP(l); ) {
1133  control c = CONTROL(CAR(l));
1134  POP(l); /* right away because c's cdr might be modified */
1135  if(meaningless_control_p(c)
1136  || ready_to_be_processed_p(c, to_be_processed,
1137  still_to_be_processed,
1138  already_processed,
1139  control_postcondition_map)) {
1140  if(!meaningless_control_p(c)) {
1141  control c_a = control_undefined;
1142  /*
1143  process_ready_node(c, n_pre, n_pre, ndu, control_postcondition_map,
1144  ancestor_map, scc_map, partition, fix_point_map, postcondition_p);
1145  */
1146  statement c_s = control_statement(c);
1147  transformer pre =
1148  get_control_precondition(c, control_postcondition_map, c_u, c_pre);
1152 
1153  /* Already done earlier
1154  if(cycle_head_p(c, ancestor_map, scc_map)) {
1155  transformer fp_tf = load_control_fix_point(a, fix_point_map, ancestor_map, scc_map);
1156  e_pre = transformer_apply(fp_tf, pre);
1157  update_cycle_temporary_precondition
1158  (a, e_pre, cycle_temporary_precondition_map);
1159  }
1160  else {
1161  e_pre = transformer_dup(pre);
1162  }
1163  */
1164  e_pre = transformer_dup(pre);
1165  if(cycle_head_p(c, ancestor_map, scc_map)) {
1167  /*
1168  transformer n_pre = transformer_undefined;
1169  transformer t_sub_scc = transformer_undefined;
1170  */
1171 
1172  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1173  /* fix point are unique for all replication of a cycle */
1174  c_a = control_to_ancestor(c, ancestor_map);
1175  sub_scc = ancestor_cycle_head_to_scc(c_a, scc_map);
1176  }
1177  else {
1178  sub_scc = ancestor_cycle_head_to_scc(c, scc_map);
1179  c_a = unstructured_control(sub_scc);
1180  }
1181 
1183  (c_a, e_pre, cycle_temporary_precondition_map);
1184  /* (a, e_pre, cycle_temporary_precondition_map); */
1185 
1186  /* Go down the subcycle... when necessary... since there is a loop somewhere else and the cycles are called in the right order? */
1187  /*
1188  cycle_to_flow_sensitive_preconditions
1189  (partition, sub_scc, ancestor_map, scc_map, fix_point_map,
1190  cycle_temporary_precondition_map, statement_temporary_precondition_map,
1191  e_pre, n_pre, control_postcondition_map);
1192  */
1193  }
1195  (c_s, e_pre, statement_temporary_precondition_map);
1196  /* post = statement_to_postcondition(transformer_dup(e_pre), c_s); */
1197  /* FI: you should use the really current precondition using
1198  load_statement_temporary_precondition() */
1199  /* post = transformer_apply(load_statement_transformer(c_s), e_pre); */
1200  /* Hard to track memory leaks... */
1201  /* It is much too late to update the control postcondition! */
1202  /* update_control_postcondition(c, post, control_postcondition_map); */
1203  /* FI: just to see what happens, without any understanding of the process */
1205  statement_temporary_precondition_map);
1206  if(cycle_head_p(c, ancestor_map, scc_map)) {
1207  transformer ctf = load_control_fix_point(c, fix_point_map,
1208  ancestor_map, scc_map);
1209  c_e_pre = transformer_apply(ctf, f_e_pre);
1210  }
1211  else {
1212  c_e_pre = transformer_dup(f_e_pre);
1213  }
1214  post = transformer_apply(load_statement_transformer(c_s), c_e_pre);
1215  /* FI: what is the point when control are replicated? */
1216  update_control_postcondition(c, post, control_postcondition_map);
1217  free_transformer(c_e_pre);
1218  }
1219  gen_remove(&still_to_be_processed, c);
1220  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1221  count++;
1222  }
1223  }
1224  } while(count!=0);
1225  if(!ENDP(still_to_be_processed)) {
1226  pips_assert("still_to_be_processed is empty because of the Bourdoncle's restructuring",
1227  false);
1228  }
1229  }
1230  /* The precondition for the entry node may be improved by now using the
1231  precondition of its predecessors and the cycle entry. OK, but to what end? */
1232 }
void free_transformer(transformer p)
Definition: ri.c:2616
static int count
Definition: SDG.c:519
transformer transformer_dup(transformer t_in)
transformer package - basic routines
Definition: basic.c:49
bool meaningless_control_p(control c)
Is exported to exploit non-deterministic control flow graphs.
Definition: bourdoncle.c:154
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
bool cycle_head_p(control c, hash_table ancestor_map, hash_table scc_map)
This node is a cycle call site.
Definition: bourdoncle.c:2385
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
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
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_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
list gen_append(list l1, const list l2)
Definition: list.c:471
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define 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 unstructured_undefined
Definition: ri.h:2980
#define control_statement(x)
Definition: ri.h:941
static void update_control_postcondition(control c, transformer post, control_mapping control_postcondition_map)
Definition: unstructured.c:268
transformer load_statement_temporary_precondition(statement s, statement_mapping statement_temporary_precondition_map)
void update_statement_temporary_precondition(statement s, transformer pre, statement_mapping statement_temporary_precondition_map)
Definition: unstructured.c:997
static bool ready_to_be_processed_p(control c, list to_be_processed, list still_to_be_processed, list already_processed, control_mapping control_postcondition_map)
a control is ready to be processed if all its predecessors have known postconditions or can receive a...
Definition: unstructured.c:427
void update_cycle_temporary_precondition(control c, transformer pre, control_mapping cycle_temporary_precondition_map)
static transformer get_control_precondition(control c, control_mapping control_postcondition_map, unstructured u, transformer pre_entry)
Definition: unstructured.c:185
static transformer load_control_fix_point(control c, control_mapping control_fix_point_map, hash_table ancestor_map, hash_table scc_map)
The fix point can be linked either to the entry node of the scc or to the ancestor node.
Definition: unstructured.c:342
static void print_control_node_unss_sem(list l)
Definition: unstructured.c:143
transformer load_statement_transformer(statement)
#define ifdebug(n)
Definition: sg.c:47
transformer transformer_apply(transformer tf, transformer pre)
transformer transformer_apply(transformer tf, transformer pre): apply transformer tf on precondition ...
Definition: transformer.c:1559

References ancestor_cycle_head_to_scc(), CAR, CONS, CONTROL, control_statement, control_to_ancestor(), control_undefined, count, cycle_head_p(), ENDP, forward_control_map_get_blocs(), free_transformer(), gen_append(), gen_copy_seq(), gen_remove(), get_bool_property(), get_control_precondition(), ifdebug, list_undefined, load_control_fix_point(), load_statement_temporary_precondition(), load_statement_transformer(), meaningless_control_p(), NIL, pips_assert, pips_debug, POP, print_control_node_unss_sem(), ready_to_be_processed_p(), transformer_apply(), transformer_dup(), transformer_undefined, unstructured_control, unstructured_undefined, update_control_postcondition(), update_cycle_temporary_precondition(), and update_statement_temporary_precondition().

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ dag_or_cycle_to_flow_sensitive_postconditions_or_transformers()

transformer dag_or_cycle_to_flow_sensitive_postconditions_or_transformers ( list  partition,
unstructured  ndu,
hash_table  ancestor_map,
hash_table  scc_map,
control_mapping  fix_point_map,
transformer  e_pre,
transformer  n_pre,
hash_table  control_postcondition_map,
bool  postcondition_p,
bool  is_dag 
)

Should ndu be a dag or a cycle?

forward reachable nodes in u

The whole business could be simplified by using a larger definition of "to_be_processed".

wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed);

Take care of unreachable nodes

FI: Wouldn't it be better to clean up the unstructured? Aren't they supposed to be clean? This piece of code contradict get_control_precondition() where the problem could be fixed at a lower cost. Another place where the problem is handled is ready_to_be_processed_p(), but it is called on still_to_be_processed, which does not take into account unreachable nodes. To make things worse, the daVinci printouts only include, most of the time, only reachable nodes.

Take care of the entry node

The entry node must be handled in a specific way... but not in the specific way implemented in process_ready_node() which only deals with DAG's. The entry node cannot be a meaningless control node.

Since control nodes have been replicated, it is difficult to predict if es has already been processed or not.

make_control_postcondition_map();

Take care of the forward reachable control nodes

process forward

right away because c's cdr might be modified

Compute fix point transformer for cycle

Compute the convex hull of the paths associated to each predecessor of the entry. Since this is a cycle, preds cannot be empty.

transformer fp_tf_plus = transformer_undefined;

If an entry range is known, do not use it as there may be more than one occurence of the cycle and more than one entry range. Keep this refinement to the precondition computation phase? It might be too late. The the data structure should be change to store more than one fix point per cycle.

Not convincing anyway: you should apply fp_tf_plus to e_pre for the next two lines to make sense.

Use the + fix point to preserve more information about the output and do not forget to perform a convex hull when you need a * fix point in process_ready_node()

Instead of computing the convex hull over all paths before computing the fix point, compute the fix point of a list of transformers.

e may have many synonyms

fix point are unique for all replication of a cycle

each cycle replication has its own fix-point

We might want to return the corresponding fix point?

Parameters
partitionartition
nduBourdoncle's processing ordering
ancestor_mapA non-deterministic acyclic control flow graph
scc_mapMapping from non-deterministic nodes to deterministic nodes
fix_point_mapmapping from deterministic nodes to non-deterministic cycles
e_premapping from cycle heads to fix point transformers
n_preprecondition on entry
control_postcondition_mapprecondition true for any node.
postcondition_postcondition_p
is_dagCompute transformers or preconditions

Definition at line 1509 of file unstructured.c.

1520 {
1522  list to_be_processed = NIL; /* forward reachable nodes in u */
1523  list still_to_be_processed = NIL;
1524  list already_processed = NIL;
1525  list cannot_be_reached = NIL;
1526 
1527  ifdebug(2) {
1528  pips_debug(2, "Begin for unstructured %p with e_pre=%p:\n", ndu, e_pre);
1529  print_transformer(e_pre);
1530  }
1531 
1532  /* The whole business could be simplified by using a larger definition of "to_be_processed". */
1533  /* wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed); */
1534  forward_control_map_get_blocs(unstructured_control(ndu), &to_be_processed);
1535  control_map_get_blocs(unstructured_control(ndu), &cannot_be_reached);
1536  still_to_be_processed = gen_copy_seq(to_be_processed);
1537  gen_list_and_not(&cannot_be_reached, to_be_processed);
1538 
1539  /* Take care of unreachable nodes */
1540 
1541  if(!ENDP(cannot_be_reached)) {
1542  /* FI: Wouldn't it be better to clean up the unstructured? Aren't they
1543  supposed to be clean? This piece of code contradict
1544  get_control_precondition() where the problem could be fixed at a
1545  lower cost. Another place where the problem is handled is
1546  ready_to_be_processed_p(), but it is called on
1547  still_to_be_processed, which does not take into account unreachable
1548  nodes. To make things worse, the daVinci printouts only include,
1549  most of the time, only reachable nodes. */
1550  ifdebug(3) {
1551  pips_debug(3, "Process unreachable nodes in unstructured %p\n", ndu);
1552  print_control_node_unss_sem(cannot_be_reached);
1553  }
1554  MAP(CONTROL, cbrc, {
1555  if(!meaningless_control_p(cbrc)) {
1557  store_control_postcondition(cbrc, etf, control_postcondition_map);
1558  }
1559  }, cannot_be_reached);
1560  gen_free_list(cannot_be_reached);
1561  cannot_be_reached = list_undefined;
1562  }
1563 
1564  pips_assert("Node lists are defined", !list_undefined_p(to_be_processed)
1565  && !list_undefined_p(still_to_be_processed) && ENDP(already_processed) );
1566 
1567  /* Take care of the entry node */
1568 
1569  if(!is_dag && !postcondition_p) {
1570  /* The entry node must be handled in a specific way... but not in the
1571  specific way implemented in process_ready_node() which only deals
1572  with DAG's. The entry node cannot be a meaningless control node. */
1573  control e = unstructured_control(ndu);
1574  statement es = control_statement(e);
1578 
1579  /* Since control nodes have been replicated, it is difficult to
1580  predict if es has already been processed or not. */
1581  if(transformer_undefined_p(etf)) {
1582  etf = statement_to_transformer(es, n_pre);
1583  }
1584 
1585  post = transformer_apply(etf, init);
1586 
1587  store_control_postcondition(e, post, control_postcondition_map);
1588 
1589  gen_remove(&still_to_be_processed, e);
1590  already_processed = CONS(CONTROL, e, NIL);
1591  }
1592 
1593  /* make_control_postcondition_map(); */
1594 
1595  /* Take care of the forward reachable control nodes */
1596 
1597  while(!ENDP(still_to_be_processed)) {
1598  int count = -1;
1599  do {
1600  list l = list_undefined;
1601 
1602  /* process forward */
1603  pips_debug(5, "Try forward processing for\n");
1604  ifdebug(2) print_control_node_unss_sem(still_to_be_processed);
1605 
1606  count = 0;
1607  for(l=still_to_be_processed; !ENDP(l); ) {
1608  control c = CONTROL(CAR(l));
1609  POP(l); /* right away because c's cdr might be modified */
1610  if(meaningless_control_p(c)
1611  || ready_to_be_processed_p(c, to_be_processed,
1612  still_to_be_processed,
1613  already_processed,
1614  control_postcondition_map)) {
1615  if(!meaningless_control_p(c)) {
1616  process_ready_node(c, e_pre, n_pre, ndu, control_postcondition_map,
1617  ancestor_map, scc_map, partition, fix_point_map, postcondition_p);
1618  }
1619  gen_remove(&still_to_be_processed, c);
1620  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1621  count++;
1622  }
1623  }
1624  } while(count!=0);
1625  if(!ENDP(still_to_be_processed)) {
1626  pips_assert("still_to_be_processed is empty because of the Bourdoncle's restructuring",
1627  false);
1628  }
1629  }
1630 
1631  /* Compute fix point transformer for cycle */
1632  if(!is_dag && !postcondition_p) {
1634  control e = unstructured_control(ndu);
1635  list preds = control_predecessors(e);
1636  control e_a = control_undefined;
1637  // FI: we also need SEMANTICS_USE_DERIVATIVE_LIST = TRUE
1638  // but this should be soon the default option
1639  if(!get_bool_property("SEMANTICS_USE_TRANSFORMER_LISTS")) {
1640  /* Compute the convex hull of the paths associated to each predecessor
1641  of the entry. Since this is a cycle, preds cannot be empty. */
1642  control pred = CONTROL(CAR(preds));
1643  transformer path_tf =
1644  load_arc_precondition(pred, e, control_postcondition_map);
1645  /* transformer fp_tf_plus = transformer_undefined; */
1646 
1647  POP(preds);
1648  FOREACH(CONTROL, pred, preds) {
1649  transformer pred_tf =
1650  load_arc_precondition(pred, e, control_postcondition_map);
1651  transformer old_path_tf = path_tf;
1652 
1653  pips_assert("Partial path transformer pred_tf is defined",
1654  !transformer_undefined_p(pred_tf));
1655  path_tf = transformer_convex_hull(old_path_tf, pred_tf);
1656  free_transformer(old_path_tf);
1657  }
1658 
1659  fp_tf = (*transformer_fix_point_operator)(path_tf);
1660  /* If an entry range is known, do not use it as there may be more than
1661  one occurence of the cycle and more than one entry range. Keep this
1662  refinement to the precondition computation phase? It might be too
1663  late. The the data structure should be change to store more than
1664  one fix point per cycle. */
1665  /* Not convincing anyway: you should apply fp_tf_plus to e_pre for the
1666  next two lines to make sense. */
1667  /* Use the + fix point to preserve more information about the output
1668  and do not forget to perform a convex hull when you need a * fix
1669  point in process_ready_node() */
1670  fp_tf = transformer_combine(fp_tf, path_tf);
1671  /*
1672  fp_tf = transformer_convex_hull(fp_tf_plus, e_pre);
1673  */
1674  free_transformer(path_tf);
1675  }
1676  else {
1677  /* Instead of computing the convex hull over all paths before
1678  computing the fix point, compute the fix point of a list of
1679  transformers. */
1680  list tl = NIL;
1681  FOREACH(CONTROL, pred, preds) {
1682  transformer pred_tf =
1683  load_arc_precondition(pred, e, control_postcondition_map);
1684  tl = CONS(TRANSFORMER, pred_tf, tl);
1685  }
1687  gen_free_list(tl);
1688  }
1689 
1690  /* e may have many synonyms */
1691 
1692  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1693  /* fix point are unique for all replication of a cycle */
1694  e_a = control_to_ancestor(e, ancestor_map);
1695  }
1696  else {
1697  /* each cycle replication has its own fix-point */
1698  e_a = e;
1699  }
1700  store_control_fix_point(e_a, fp_tf, fix_point_map);
1701 
1702  /* We might want to return the corresponding fix point? */
1703  tf = fp_tf;
1704  }
1705 
1706  gen_free_list(to_be_processed);
1707  to_be_processed = list_undefined;
1708  gen_free_list(still_to_be_processed);
1709  still_to_be_processed = list_undefined;
1710  gen_free_list(already_processed);
1711  already_processed = list_undefined;
1712 
1713  ifdebug(2) {
1714  pips_debug(2, "End for %s of %s %p with entry node %s and with transformer %p\n",
1715  postcondition_p? "postcondition" : "transformer",
1716  is_dag? "dag" : "cycle", ndu,
1718  print_transformer(tf);
1719  }
1720 
1721  return tf;
1722 }
transformer transformer_identity()
Allocate an identity transformer.
Definition: basic.c:110
transformer transformer_empty()
Allocate an empty transformer.
Definition: basic.c:120
void control_map_get_blocs(control c, list *l)
Build recursively the list of all controls reachable from a control of an unstructured.
Definition: control.c:75
#define list_undefined_p(c)
Return if a list is undefined.
Definition: newgen_list.h:75
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#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
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700
#define print_transformer(t)
Definition: print.c:357
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
#define transformer_undefined_p(x)
Definition: ri.h:2848
#define TRANSFORMER(x)
TRANSFORMER.
Definition: ri.h:2841
#define control_predecessors(x)
Definition: ri.h:943
transformer statement_to_transformer(statement s, transformer spre)
stmt precondition
static void store_control_postcondition(control c, transformer post, control_mapping control_postcondition_map)
Definition: unstructured.c:245
static transformer load_arc_precondition(control, control, control_mapping)
forward declaration
Definition: unstructured.c:468
static void process_ready_node(control c, transformer pre_entry, transformer n_pre, unstructured u, control_mapping control_postcondition_map, hash_table ancestor_map, hash_table scc_map, list partition, control_mapping fix_point_map, bool postcondition_p)
Definition: unstructured.c:630
static void store_control_fix_point(control c, transformer fptf, control_mapping control_fix_point_map)
Definition: unstructured.c:382
transformer transformer_convex_hull(transformer t1, transformer t2)
transformer transformer_convex_hull(t1, t2): compute convex hull for t1 and t2; t1 and t2 are slightl...
Definition: convex_hull.c:216
transformer transformer_combine(volatile transformer t1, transformer t2)
transformer transformer_combine(transformer t1, transformer t2): compute the composition of transform...
Definition: transformer.c:238
transformer transformer_list_transitive_closure_plus(list)
Compute (U tfl)+.

References CAR, CONS, CONTROL, control_map_get_blocs(), control_predecessors, control_statement, control_to_ancestor(), control_undefined, count, ENDP, FOREACH, forward_control_map_get_blocs(), free_transformer(), gen_append(), gen_copy_seq(), gen_free_list(), gen_list_and_not(), gen_remove(), get_bool_property(), ifdebug, init, list_undefined, list_undefined_p, load_arc_precondition(), load_statement_transformer(), MAP, meaningless_control_p(), NIL, pips_assert, pips_debug, POP, print_control_node_unss_sem(), print_transformer, process_ready_node(), ready_to_be_processed_p(), statement_identification(), statement_to_transformer(), store_control_fix_point(), store_control_postcondition(), TRANSFORMER, transformer_apply(), transformer_combine(), transformer_convex_hull(), transformer_empty(), transformer_identity(), transformer_list_transitive_closure_plus(), transformer_undefined, transformer_undefined_p, and unstructured_control.

Referenced by cycle_to_flow_sensitive_postconditions_or_transformers(), and dag_to_flow_sensitive_postconditions_or_transformers().

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

◆ dag_to_flow_sensitive_postconditions_or_transformers()

transformer dag_to_flow_sensitive_postconditions_or_transformers ( list  partition,
unstructured  ndu,
hash_table  ancestor_map,
hash_table  scc_map,
control_mapping  fix_point_map,
transformer  e_pre,
transformer  n_pre,
hash_table  control_postcondition_map,
bool  postcondition_p 
)

Compute transformers or preconditions.

Parameters
partitionartition
nduBourdoncle's processing ordering
ancestor_mapA non-deterministic acyclic control flow graph
scc_mapMapping from non-deterministic nodes to deterministic nodes
fix_point_mapmapping from deterministic nodes to non-deterministic cycles
e_premapping from cycle heads to fix point transformers
n_preprecondition on entry
control_postcondition_mapprecondition true for any node.
postcondition_postcondition_p

Definition at line 1724 of file unstructured.c.

1734 {
1736 
1738  (partition, ndu, ancestor_map, scc_map, fix_point_map, e_pre, n_pre,
1739  control_postcondition_map, postcondition_p, true);
1740 
1741  return tf;
1742 }

References dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), and transformer_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:

◆ dag_to_flow_sensitive_preconditions()

static void dag_to_flow_sensitive_preconditions ( list  partition,
unstructured  ndu,
hash_table  ancestor_map,
hash_table  scc_map,
control_mapping  fix_point_map,
transformer  pre_u,
transformer  pre,
control_mapping  control_postcondition_map 
)
static

A statement may appear in several nodes, and the same is true for cycles.

DUPLICATED CODE

The cycle is entered

Or the cycle is not entered and the store is not in fptf's domain.

Have we followed a true or a false branch? We'll know later but it is better to add this information before the convex hull is performed.

FI: I do not know why an empty context is passed down.

free_transformer(pre);

END OF DUPLICATED CODE

e_pre = transformer_apply(fp_tf, pre);

fix point are unique for all replication of a cycle

update_cycle_temporary_precondition(a, e_pre, cycle_temporary_precondition_map);

FI: sharing between statement_temporary_precondition and statement_temporary_precondition; freeing the second one frees part of the first one

Build the cycle dependencies

control a = control_to_ancestor(c, ancestor_map);

unstructured scc_ u = cycle_head_to_scc(c, ancestor_map, scc_map);

build dependencies among ancestors, which are representative of scc's

then cc depends on c

build dependencies among heads, which are representative of scc's

No cycles with dependencies

While some cycles still have to be processed.

right away because c's cdr might be modified

The precondition of cycle c is complete

control a = control_to_ancestor(c, ancestor_map);

Definition at line 1234 of file unstructured.c.

1243 {
1244  /* A statement may appear in several nodes, and the same is true for cycles. */
1245  statement_mapping statement_temporary_precondition_map = MAKE_STATEMENT_MAPPING();
1246  control_mapping cycle_temporary_precondition_map = MAKE_CONTROL_MAPPING();
1247  control_mapping cycle_dependencies_map = MAKE_CONTROL_MAPPING();
1248  list still_to_be_processed = NIL;
1249  list already_processed = NIL;
1250  control e = unstructured_control(ndu);
1251  list nl = NIL;
1252  list c_c = list_undefined;
1253 
1254  ifdebug(2) {
1255  pips_debug(2, "Begin with control_postcondition_map=%p:\n",
1256  control_postcondition_map);
1257  print_control_postcondition_map(control_postcondition_map);
1258  }
1259 
1260  /*
1261  * Process first the nodes in the embedding graph, in any order since
1262  * node postconditions are assumed available.
1263  *
1264  */
1265  control_map_get_blocs(e, &nl);
1266 
1267  for(c_c = nl; !ENDP(c_c); POP(c_c)) {
1268  control c = CONTROL(CAR(c_c));
1269 
1270  if(!meaningless_control_p(c)) {
1271  control c_a = control_undefined;
1272  transformer pre = get_control_precondition(c, control_postcondition_map, ndu, pre_u);
1275 
1276  if(cycle_head_p(c, ancestor_map, scc_map)) {
1277  transformer fp_tf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
1278 
1279  /* DUPLICATED CODE */
1280 
1281  /* The cycle is entered */
1282  transformer pre_cycle = transformer_apply(fp_tf, pre);
1283  /* Or the cycle is not entered and the store is not in fptf's domain. */
1284  transformer pre_no_cycle = transformer_dup(pre);
1285  if(control_test_p(c)) {
1286  /* Have we followed a true or a false branch? We'll know later but
1287  it is better to add this information before the convex hull is
1288  performed. */
1291 
1292  /* FI: I do not know why an empty context is passed down. */
1293  if(true_successors_only_p(c)) {
1294  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
1295  transformer_undefined, true);
1296  }
1297  else if(false_successors_only_p(c)) {
1298  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
1299  transformer_undefined, false);
1300  }
1301  }
1302  /* free_transformer(pre); */
1303  e_pre = transformer_convex_hull(pre_cycle, pre_no_cycle);
1304  free_transformer(pre_cycle);
1305  free_transformer(pre_no_cycle);
1306 
1307  /* END OF DUPLICATED CODE */
1308 
1309  /* e_pre = transformer_apply(fp_tf, pre); */
1310 
1311  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1312  /* fix point are unique for all replication of a cycle */
1313  c_a = control_to_ancestor(c, ancestor_map);
1314  }
1315  else {
1317  }
1318  update_cycle_temporary_precondition(c_a, e_pre, cycle_temporary_precondition_map);
1319  /* update_cycle_temporary_precondition(a, e_pre, cycle_temporary_precondition_map); */
1320  }
1321  else {
1322  e_pre = transformer_dup(pre);
1323  }
1324  /* FI: sharing between statement_temporary_precondition and
1325  statement_temporary_precondition; freeing the second one frees
1326  part of the first one */
1327  update_statement_temporary_precondition(s, e_pre, statement_temporary_precondition_map);
1328  }
1329  }
1330 
1331  gen_free_list(nl);
1332 
1333  ifdebug(2) {
1334  pips_debug(2, "\nPreconditions for statements after ND DAG processing:\n");
1335  print_statement_temporary_precondition(statement_temporary_precondition_map);
1336  pips_debug(2, "End of preconditions for statements after ND DAG processing:\n\n");
1337  }
1338 
1339  /*
1340  * Process the cycles from top to bottom in width first?
1341  * Let's use the partition generated by Bourdoncle?!?
1342  *
1343  * Since cycles are not duplicated when transformers are not computed in
1344  * context, the preconditions of all their instances must be unioned
1345  * before preconditions can be propagated down in the cycles. When
1346  * cycles are replicated to have one cycle per cycle call site, the same
1347  * scheme can be used, as long as dependencies are properly computed.
1348  *
1349  * Each cycle c depends on a list of cycles, each of these containing a
1350  * cycle call site to c.
1351  *
1352  * When cycles are not replicated, the dependencies are based on the
1353  * ancestor of the head, so as to have a unique representative. When
1354  * cycles are replicated according to cycle call sites, the dependencies
1355  * are based on the head of the cycle.
1356  *
1357  * It is not clear than a topological order exists. Assume that C2
1358  * occurs in an entry path to C1 and within C1. Somehow the precise
1359  * precondition of C1 depends on C2's postcondition which depends on
1360  * C2's precondition. C2's precondition depends on C1's postcondition
1361  * which depends on C1's precondition and here is the loop.
1362  *
1363  * However, in the previous case, the first instance of C2 can be dealt
1364  * with its transformer and the precondition of its first instance.
1365  *
1366  * */
1367 
1368  /* Build the cycle dependencies */
1369  pips_debug(2, "Compute dependencies for %d cycle%s\n",
1370  hash_table_entry_count(scc_map),
1371  hash_table_entry_count(scc_map)>1? "s":"");
1372  HASH_MAP(c, cndu, {
1373  /* control a = control_to_ancestor(c, ancestor_map); */
1374  /* unstructured scc_ u = cycle_head_to_scc(c, ancestor_map, scc_map); */
1375  list nl = NIL;
1376  list c_cc = list_undefined;
1377  control head = unstructured_control((unstructured) cndu);
1378  statement hs = control_statement(head);
1379 
1380  pips_debug(8, "Compute dependencies for cycle %p with statement %s\n",
1381  head, statement_identification(hs));
1382 
1383  control_map_get_blocs(head, &nl);
1384 
1385  for(c_cc=nl; !ENDP(c_cc); POP(c_cc)) {
1386  control cc = CONTROL(CAR(c_cc));
1387 
1388  if(!meaningless_control_p(cc)
1389  && cycle_head_p(cc, ancestor_map, scc_map)) {
1390  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1391  /* build dependencies among ancestors, which are representative of scc's */
1392  control aa = control_to_ancestor(cc, ancestor_map);
1393  if(aa!=c) {
1394  /* then cc depends on c */
1395  add_cycle_dependency(aa, (control) c, cycle_dependencies_map);
1396  }
1397  }
1398  else {
1399  /* build dependencies among heads, which are representative of scc's */
1400  unstructured scc_u = ancestor_cycle_head_to_scc(cc, scc_map);
1401  control head_scc = unstructured_control(scc_u);
1402  if(head_scc!=(control)c) {
1403  add_cycle_dependency(head_scc, head, cycle_dependencies_map);
1404  }
1405  }
1406  }
1407  }
1408 
1409  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1410  still_to_be_processed = CONS(CONTROL, (control) c, still_to_be_processed);
1411  }
1412  else {
1413  still_to_be_processed = CONS(CONTROL, head, still_to_be_processed);
1414  }
1415  gen_free_list(nl);
1416  }, scc_map);
1417 
1418  ifdebug(2) {
1419  if(hash_table_entry_count(cycle_dependencies_map)>0) {
1420  pips_debug(2, "cycle dependencies:\n");
1421  HASH_MAP(c, l, {
1423  pips_debug(2, "Cycle %p with statement %s depends on:\n",
1424  c, statement_identification(s));
1426  }, cycle_dependencies_map);
1427  }
1428  else {
1429  /* No cycles with dependencies */
1430  pips_debug(2, "no cycles with dependencies\n");
1431  }
1432  }
1433 
1434  /* While some cycles still have to be processed. */
1435  while(!ENDP(still_to_be_processed)) {
1436  int count = -1;
1437  do {
1438  list l = list_undefined;
1439  count = 0;
1440  for(l=still_to_be_processed; !ENDP(l); ) {
1441  control c = CONTROL(CAR(l));
1442 
1443  list dep = get_cycle_dependencies(c, cycle_dependencies_map);
1444  POP(l); /* right away because c's cdr might be modified */
1445 
1446  ifdebug(8) {
1447  if(ENDP(dep)) {
1448  pips_debug(8, "Process cycle %p with statement %s\n",
1450  }
1451  }
1452 
1453  if(ENDP(dep)) {
1454  /* The precondition of cycle c is complete */
1455  /* control a = control_to_ancestor(c, ancestor_map); */
1457  cycle_temporary_precondition_map,
1458  ancestor_map, scc_map);
1459  transformer fp_tf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
1461  transformer f_c_pre = transformer_apply(fp_tf, c_pre);
1462  transformer e_c_pre = transformer_convex_hull(f_c_pre, c_pre);
1463 
1464  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT"))
1465  c_u = cycle_head_to_scc(c, ancestor_map, scc_map);
1466  else
1467  c_u = proper_cycle_head_to_scc(c, scc_map);
1468 
1470  (partition, c_u, ancestor_map, scc_map, fix_point_map,
1471  cycle_temporary_precondition_map, statement_temporary_precondition_map,
1472  e_c_pre, pre, control_postcondition_map);
1473  remove_cycle_dependencies(c, cycle_dependencies_map);
1474  gen_remove(&still_to_be_processed, c);
1475  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1476  count++;
1477  }
1478  }
1479  } while(count!=0);
1480 
1481  pips_assert("All cycles have been processed",
1482  ENDP(still_to_be_processed));
1483  }
1484 
1485  /*
1486  * Exploit the temporary preconditions
1487  *
1488  */
1489  HASH_MAP(s, s_pre, {
1490  transformer post =
1492  free_transformer(post);
1493  }, statement_temporary_precondition_map);
1494 
1495 }
bool control_test_p(control c)
Check that a node is used as a test in a CFG.
Definition: bourdoncle.c:175
unstructured proper_cycle_head_to_scc(control h, hash_table scc_map)
Retrieve a scc_u from its head.
Definition: bourdoncle.c:2368
bool false_successors_only_p(control c)
Definition: bourdoncle.c:2481
bool true_successors_only_p(control c)
Definition: bourdoncle.c:2474
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.
Definition: bourdoncle.c:2433
test statement_test(statement)
Get the test of a statement.
Definition: statement.c:1348
int hash_table_entry_count(hash_table htp)
now we define observers in order to hide the hash_table type...
Definition: hash.c:818
#define MAKE_CONTROL_MAPPING()
Definition: newgen-local.h:82
#define MAKE_STATEMENT_MAPPING()
Definition: newgen-local.h:43
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
#define test_condition(x)
Definition: ri.h:2833
transformer statement_to_postcondition(transformer, statement)
end of the non recursive section
transformer precondition_add_condition_information(transformer pre, expression c, transformer context, bool veracity)
context might be derivable from pre as transformer_range(pre) but this is sometimes very computationa...
Definition: expression.c:1111
static list get_cycle_dependencies(control d, control_mapping cycle_dependencies_map)
Some cycle may appear nowhere but in the DAG and have no entries in the table.
Definition: unstructured.c:963
static void cycle_to_flow_sensitive_preconditions(list partition, unstructured c_u, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, control_mapping cycle_temporary_precondition_map, statement_mapping statement_temporary_precondition_map, transformer c_pre, transformer pre, control_mapping control_postcondition_map)
Very likely the transformer paths wrt the entry point and not really a postcondition.
void print_statement_temporary_precondition(statement_mapping statement_temporary_precondition_map)
transformer load_cycle_temporary_precondition(control c, control_mapping cycle_temporary_precondition_map, hash_table ancestor_map, hash_table scc_map __attribute__((__unused__)))
static void remove_cycle_dependencies(control c, control_mapping cycle_dependencies_map)
c has been processed and no other cycle can depend on it
Definition: unstructured.c:951
static void add_cycle_dependency(control d, control c, control_mapping cycle_dependencies_map)
State that d depends on c: cycle c must be processed before cycle d can be processed.
Definition: unstructured.c:934
void print_control_postcondition_map(control_mapping control_postcondition_map)
unstructured.c
Definition: unstructured.c:295
Definition: statement.c:54

References add_cycle_dependency(), ancestor_cycle_head_to_scc(), CAR, CONS, CONTROL, control_map_get_blocs(), control_statement, control_test_p(), control_to_ancestor(), control_undefined, count, cycle_head_p(), cycle_head_to_scc(), cycle_to_flow_sensitive_preconditions(), ENDP, false_successors_only_p(), free_transformer(), gen_append(), gen_free_list(), gen_remove(), get_bool_property(), get_control_precondition(), get_cycle_dependencies(), HASH_MAP, hash_table_entry_count(), ifdebug, list_undefined, load_control_fix_point(), load_cycle_temporary_precondition(), MAKE_CONTROL_MAPPING, MAKE_STATEMENT_MAPPING, meaningless_control_p(), NIL, pips_assert, pips_debug, POP, precondition_add_condition_information(), print_control_node_unss_sem(), print_control_postcondition_map(), print_statement_temporary_precondition(), proper_cycle_head_to_scc(), remove_cycle_dependencies(), statement_identification(), statement_test(), statement_to_postcondition(), test_condition, transformer_apply(), transformer_convex_hull(), transformer_dup(), transformer_undefined, true_successors_only_p(), unstructured_control, unstructured_undefined, update_cycle_temporary_precondition(), and update_statement_temporary_precondition().

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:

◆ free_control_fix_point_map()

static control_mapping free_control_fix_point_map ( control_mapping  control_fix_point_map)
static

all fix_points must be freed

return control_mapping_undefined;

Definition at line 412 of file unstructured.c.

413 {
414  /* all fix_points must be freed */
415  HASH_MAP(k,v,{
417  }, control_fix_point_map);
418 
419  FREE_CONTROL_MAPPING(control_fix_point_map);
420 
421  /* return control_mapping_undefined; */
422  return NULL;
423 }
#define FREE_CONTROL_MAPPING(map)
Definition: newgen-local.h:84

References FREE_CONTROL_MAPPING, free_transformer(), and HASH_MAP.

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:

◆ free_control_postcondition_map()

static control_mapping free_control_postcondition_map ( control_mapping  control_postcondition_map)
static

all postconditions must be freed

return control_mapping_undefined;

Definition at line 318 of file unstructured.c.

319 {
320  /* all postconditions must be freed */
321  HASH_MAP(k,v,{
323  }, control_postcondition_map);
324 
325  FREE_CONTROL_MAPPING(control_postcondition_map);
326 
327  /* return control_mapping_undefined; */
328  return NULL;
329 }

References FREE_CONTROL_MAPPING, free_transformer(), and HASH_MAP.

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:

◆ get_control_precondition()

static transformer get_control_precondition ( control  c,
control_mapping  control_postcondition_map,
unstructured  u,
transformer  pre_entry 
)
static

Compute its precondition from the postconditions of its predecessor and from the entry precondition. Use arc pred->c information to deal with tests.

Do not forget the unstructured precondition for the entry node

FI: I do not know why it has to be replicated. Probably because the statement containing the unstructured and the statement of the entry node may share the same precondition.

This is not the entry node: without predecessors, it is unreachable

memory leak with lpre. pre_entry and postconditions cannot be freed: lpre cannot be freed during the first iteration

Definition at line 185 of file unstructured.c.

189 {
191  list preds = control_predecessors(c);
192 
193  pips_assert("c is meaningfull", !meaningless_control_p(c));
194 
195  pips_debug(2, "Begin for node %p and statement %s\n", c,
197 
198  /* Compute its precondition from the postconditions of its predecessor
199  and from the entry precondition. Use arc pred->c information to deal
200  with tests. */
201 
202  if(c==unstructured_control(u)) {
203  /* Do not forget the unstructured precondition for the entry node */
204  /* FI: I do not know why it has to be replicated. Probably because the
205  statement containing the unstructured and the statement of the
206  entry node may share the same precondition. */
207  pre = copy_transformer(pre_entry);
208  }
209  else {
210  if(ENDP(preds)) {
211  /* This is not the entry node: without predecessors, it is unreachable */
212  pre = transformer_empty();
213  }
214  else {
215  pre = load_arc_precondition(CONTROL(CAR(preds)), c, control_postcondition_map);
216  POP(preds);
217  }
218  }
219 
220  FOREACH(CONTROL, pred, preds) {
221  transformer npre = load_arc_precondition(pred, c, control_postcondition_map);
222  transformer lpre = pre;
223 
224  pips_assert("The predecessor's postcondition npre is defined",
225  !transformer_undefined_p(npre));
226 
227  pre = transformer_convex_hull(npre, lpre);
228  /* memory leak with lpre. pre_entry and postconditions cannot be
229  freed: lpre cannot be freed during the first iteration */
230  if(pred!=CONTROL(CAR(preds)))
231  free_transformer(lpre);
232  lpre = pre;
233  }
234 
235 
236  ifdebug(2) {
237  pips_debug(2, "End for node %p and statement %s with precondition %p:\n", c,
239  print_transformer(pre);
240  }
241 
242  return pre;
243 }
transformer copy_transformer(transformer p)
TRANSFORMER.
Definition: ri.c:2613

References CAR, CONTROL, control_predecessors, control_statement, copy_transformer(), ENDP, FOREACH, free_transformer(), ifdebug, load_arc_precondition(), meaningless_control_p(), pips_assert, pips_debug, POP, print_transformer, statement_identification(), transformer_convex_hull(), transformer_empty(), transformer_undefined, transformer_undefined_p, and unstructured_control.

Referenced by cycle_to_flow_sensitive_preconditions(), and dag_to_flow_sensitive_preconditions().

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

◆ get_cycle_dependencies()

static list get_cycle_dependencies ( control  d,
control_mapping  cycle_dependencies_map 
)
static

Some cycle may appear nowhere but in the DAG and have no entries in the table.

In that case, they have an empty dependency list.

Definition at line 963 of file unstructured.c.

964 {
965  list dependencies = (list) hash_get((hash_table) cycle_dependencies_map,
966  (void *) d);
967 
968  if(dependencies == (list) HASH_UNDEFINED_VALUE) {
969  dependencies = NIL;
970  }
971 
972  return dependencies;
973 }

References hash_get(), HASH_UNDEFINED_VALUE, and NIL.

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ load_arc_precondition()

static transformer load_arc_precondition ( control  pred,
control  c,
control_mapping  control_postcondition_map 
)
static

forward declaration

Returns the precondition of c associated to arc pred->c in a newly allocated transformer.

pred must be unreachable, left over by the controlizer...

It would be nice to be able to check that it is unreachable... and that we do not land here because of a bug...

This should never happen.

let's assume that Bourdoncle's restructuring does not clutter the successor list too much.

Assume that the same node is in the true and false successor lists.

Do not bother with the test condition... and FI loose the side effects.

If side effects can be detected, perform a convex hull of the true and false branches as nothing else is available.

add the test condition

One of the true successors

One of the false successors

Definition at line 468 of file unstructured.c.

470 {
471  transformer post = load_control_postcondition(pred, control_postcondition_map);
473  int i = gen_position(c, control_successors(pred));
474  int noo = gen_occurences(c, control_successors(pred));
475 
476  if(transformer_undefined_p(post)) {
477  /* pred must be unreachable, left over by the controlizer... */
478  /* It would be nice to be able to check that it is unreachable... and
479  that we do not land here because of a bug...*/
480  /* This should never happen. */
481  pips_debug(2, "Failed for predecessor node pred=%p and node c=%p with map %p:\n",
482  pred, c, control_postcondition_map);
483  pips_assert("postconditions of predecessors are assumed initialized"
484  " (see process_ready_node().", false);
485  pre = transformer_empty();
486  }
487  else {
488  pre = transformer_dup(post);
489 
490  pips_assert("c is a successor of pred", i!=0);
491  /* let's assume that Bourdoncle's restructuring does not clutter the
492  successor list too much. */
493  pips_assert("c does not appear more than twice in the successor list",
494  noo<=2);
495 
496  if(control_test_p(pred)) {
498 
499  pips_assert("stmt is a test", statement_test_p(stmt));
500 
501  if(noo==2) {
502  /* Assume that the same node is in the true and false successor lists. */
503  /* Do not bother with the test condition... and FI loose the side effects. */
504  /* If side effects can be detected, perform a convex hull of the
505  true and false branches as nothing else is available. */
506  ;
507  }
508  else {
509  /* add the test condition */
511 
512  if(i%2==1) { /* One of the true successors */
514  transformer_undefined, true);
515 
516  }
517  else{ /* One of the false successors */
519  transformer_undefined, false);
520  }
521  }
522  }
523  }
524  ifdebug(2) {
525  string msg = control_test_p(pred)? (i%2==1? "true" : "false"): "standard";
526  pips_debug(2, "End for %s arc of position %d between predecessor node pred=%p"
527  " and node c=%p with precondition %p:\n",
528  msg, i, pred, c, pre);
529  print_transformer(pre);
530  }
531 
532  return pre;
533 }
int gen_position(const void *item, const list l)
Element ranks are strictly positive as for first, second, and so on.
Definition: list.c:995
int gen_occurences(const void *vo, const list l)
count occurences of vo in l
Definition: list.c:746
bool statement_test_p(statement)
Definition: statement.c:343
#define control_successors(x)
Definition: ri.h:945
static transformer load_control_postcondition(control c, control_mapping control_postcondition_map)
Definition: unstructured.c:169

References control_statement, control_successors, control_test_p(), gen_occurences(), gen_position(), ifdebug, load_control_postcondition(), pips_assert, pips_debug, precondition_add_condition_information(), print_transformer, statement_test(), statement_test_p(), test_condition, transformer_dup(), transformer_empty(), transformer_undefined, and transformer_undefined_p.

Referenced by dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), get_control_precondition(), and process_ready_node().

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

◆ load_control_fix_point()

static transformer load_control_fix_point ( control  c,
control_mapping  control_fix_point_map,
hash_table  ancestor_map,
hash_table  scc_map 
)
static

The fix point can be linked either to the entry node of the scc or to the ancestor node.

The ancestor node is used by default, when transformer are not computed in context. So the argument is either the ancestor node (transformer out of context), or the call node (transformers computed in context) or the entry node (preconditions computed with transformers in context).

It is assumed that cycle_head_p(c) holds, but it is not assumed that its fixpoint is available..

Definition at line 342 of file unstructured.c.

346 {
349 
350  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
351  c_a = control_to_ancestor(c, ancestor_map);
352  }
353  else {
354  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
355  if(unstructured_undefined_p(scc_u))
356  c_a = c;
357  else
358  c_a = unstructured_control(scc_u);
359  }
360 
361  ifdebug(1) pips_assert("The control node pointing to the fix point is defined",
362  !control_undefined_p(c_a));
363 
364  fptf = (transformer)
365  hash_get((hash_table) control_fix_point_map,
366  (char *) c_a);
367 
369  fptf = transformer_undefined;
370 
371  pips_debug(5, "control %p, ancestor %p, transformer %p\n", c, c_a, fptf);
372 
373  /* It is assumed that cycle_head_p(c) holds, but it is not assumed that
374  its fixpoint is available.. */
375  /*
376  ifdebug(1) pips_assert("The required fix point is defined",
377  !transformer_undefined_p(fptf));
378  */
379  return fptf;
380 }
static void node(FILE *out, string name)
Build for module name a node and link to its successors.
Definition: graph.c:56
if(!(yy_init))
Definition: genread_lex.c:1029
#define control_undefined_p(x)
Definition: ri.h:917
#define unstructured_undefined_p(x)
Definition: ri.h:2981
return(s1)

References ancestor_cycle_head_to_scc(), control_to_ancestor(), control_undefined, control_undefined_p, get_bool_property(), hash_get(), HASH_UNDEFINED_VALUE, ifdebug, pips_assert, pips_debug, transformer_undefined, unstructured_control, and unstructured_undefined_p.

Referenced by cycle_to_flow_sensitive_preconditions(), 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:

◆ load_control_postcondition()

static transformer load_control_postcondition ( control  c,
control_mapping  control_postcondition_map 
)
static

Definition at line 169 of file unstructured.c.

171 {
172  transformer post = (transformer)
173  hash_get((hash_table) control_postcondition_map,
174  (void *) c);
175 
176  if(post == (transformer) HASH_UNDEFINED_VALUE)
177  post = transformer_undefined;
178 
179  return post;
180 }
struct _newgen_struct_transformer_ * transformer
Definition: ri.h:431

References hash_get(), HASH_UNDEFINED_VALUE, and transformer_undefined.

Referenced by load_arc_precondition(), node_to_path_transformer_or_postcondition(), print_cycle_head_to_fixpoint(), process_unreachable_node(), ready_to_be_processed_p(), and unstructured_to_flow_sensitive_postconditions_or_transformers().

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

◆ load_cycle_fix_point()

transformer load_cycle_fix_point ( control  c,
hash_table  fix_point_map 
)
Parameters
fix_point_mapix_point_map

Definition at line 544 of file unstructured.c.

545 {
547 
548  if((fptf = (transformer) hash_get(fix_point_map, (void *) c))
550  pips_assert("c is not a cycle head", false);
551 
552  return fptf;
553 }

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

+ Here is the call graph for this function:

◆ load_cycle_temporary_precondition()

transformer load_cycle_temporary_precondition ( control  c,
control_mapping  cycle_temporary_precondition_map,
hash_table  ancestor_map,
hash_table scc_map   __attribute__(__unused__) 
)

Definition at line 1037 of file unstructured.c.

1041 {
1043  control c_a = control_undefined;
1044 
1045  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1046  c_a = control_to_ancestor(c, ancestor_map);
1047  }
1048  else {
1049  /*
1050  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
1051  c_a = unstructured_control(scc_u);
1052  */
1053  c_a = c;
1054  }
1055 
1056  t_pre = (transformer) hash_get(cycle_temporary_precondition_map, (void *) c_a);
1057 
1058  pips_assert("The cycle precondition is available",
1059  t_pre != (transformer) HASH_UNDEFINED_VALUE);
1060 
1061  ifdebug(6) {
1062  pips_debug(6, "Precondition %p for cycle %p:\n", t_pre, c_a);
1063  print_transformer(t_pre);
1064  }
1065 
1066  return t_pre;
1067 }

References control_to_ancestor(), control_undefined, get_bool_property(), hash_get(), HASH_UNDEFINED_VALUE, ifdebug, pips_assert, pips_debug, print_transformer, and transformer_undefined.

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ load_statement_temporary_precondition()

transformer load_statement_temporary_precondition ( statement  s,
statement_mapping  statement_temporary_precondition_map 
)
Parameters
statement_temporary_precondition_maptatement_temporary_precondition_map

Definition at line 1069 of file unstructured.c.

1071 {
1072  transformer t_pre = (transformer) hash_get(statement_temporary_precondition_map, (void *) s);
1073 
1074  pips_assert("The cycle precondition is available",
1075  t_pre != (transformer) HASH_UNDEFINED_VALUE);
1076 
1077  return t_pre;
1078 }

References hash_get(), HASH_UNDEFINED_VALUE, and pips_assert.

Referenced by cycle_to_flow_sensitive_preconditions().

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

◆ local_process_unreachable_node()

static void local_process_unreachable_node ( control  c,
recursive_context pcontext 
)
static

Definition at line 1781 of file unstructured.c.

1782 {
1783  process_unreachable_node(c, pcontext->smap, pcontext->pcond);
1784 }
static bool process_unreachable_node(control c, control_mapping control_postcondition_map, bool postcondition_p)
Definition: unstructured.c:862
control_mapping smap

References recursive_context::pcond, process_unreachable_node(), and recursive_context::smap.

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:

◆ make_control_fix_point_map()

static control_mapping make_control_fix_point_map ( )
static

Definition at line 405 of file unstructured.c.

406 {
407  control_mapping control_fix_point_map = NULL;
408  control_fix_point_map = MAKE_CONTROL_MAPPING();
409  return control_fix_point_map;
410 }

References MAKE_CONTROL_MAPPING.

Referenced by unstructured_to_flow_sensitive_postconditions_or_transformers().

+ Here is the caller graph for this function:

◆ make_control_postcondition_map()

static control_mapping make_control_postcondition_map ( )
static

Definition at line 311 of file unstructured.c.

312 {
313  control_mapping control_postcondition_map = NULL;
314  control_postcondition_map = MAKE_CONTROL_MAPPING();
315  return control_postcondition_map;
316 }

References MAKE_CONTROL_MAPPING.

Referenced by unstructured_to_flow_sensitive_postconditions_or_transformers().

+ Here is the caller graph for this function:

◆ node_to_path_transformer_or_postcondition()

static void node_to_path_transformer_or_postcondition ( control  c,
recursive_context pcontext 
)
static

A debug function to prettyprint the result.

Definition at line 1787 of file unstructured.c.

1788 {
1789  if(!meaningless_control_p(c)) {
1790  control_mapping control_postcondition_map = pcontext->smap;
1792  transformer tf = load_control_postcondition(c, control_postcondition_map);
1793 
1794  pips_assert("Postcondition tf is defined", !transformer_undefined_p(tf));
1795  fprintf(stderr, "Statement %s", statement_identification(s));
1796  pips_assert("Transformer or postcondition is consistent",
1798  print_transformer(tf);
1799  }
1800 }
bool transformer_consistency_p(transformer t)
FI: I do not know if this procedure should always return or fail when an inconsistency is found.
Definition: basic.c:612
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...

References control_statement, fprintf(), load_control_postcondition(), meaningless_control_p(), pips_assert, print_transformer, recursive_context::smap, statement_identification(), transformer_consistency_p(), and transformer_undefined_p.

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:

◆ non_deterministic_unstructured_to_effects()

static list non_deterministic_unstructured_to_effects ( unstructured  scc,
hash_table  ancestor_map,
hash_table  scc_map 
)
static

entry point

Definition at line 603 of file unstructured.c.

606 {
607  list el = unstructured_to_effects(scc, ancestor_map, scc_map);
608 
609  ifdebug(6) {
610  control e = unstructured_control(scc); /* entry point */
611  pips_debug(6, "Effect list for unstructured %p with entry %p:\n",
612  scc, e);
613  print_effects(el);
614  }
615 
616  return el;
617 }
#define print_effects(e)
Definition: print.c:334
static list unstructured_to_effects(unstructured scc, hash_table ancestor_map, hash_table scc_map)
In fact, non-deterministic unstructured to effects.
Definition: unstructured.c:556

References ifdebug, pips_debug, print_effects, unstructured_control, and unstructured_to_effects().

Referenced by process_ready_node().

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

◆ print_control_node_uns()

static void print_control_node_uns ( control  c)
static

semantical analysis

Computation of transformers and postconditions and total preconditions in unstructured (i.e. CFG).

Accurate results are obtained by restructuring CFG into a set of non-deterministic CFG's using Bourdoncle's partitioning as implemented in control/bourdoncle.c. The cycle heads are chosen using Bourdoncle's heuristics. Then the graph is augmented with new nodes in order that cycle heads are the only entry and exit node of the cycles in each scc. So the input CFG is transformed into a non-deterministic DAG. Some nodes of the DAG point to SCC's. Each SCC is represented by a DAG whose leaves point back to the cycle head. The SCC DAG may contain nodes pointing to sub-SCC's.

It is not clear if you want to store the node pre or postcondition. The postcondition may depend on the outgoing arc. But the precondition would have to be processed by the node transformer once for each arc. To avoid both problems the postconditions are stored without the control information. It is added later according to the outgoing arc considered. But it is not satisfactory to apply a reverse transformer to retrieve the precondition or to re-apply a convex hull on the input after having taken care of the potential cycle. All in all, it would be easier to store preconditions...

Transformers between the entry point and after the current node are very similar to postcondition between the module entry point and the current node. Transformers are obtained like precondition but without a precondition at the CFG entry point.

It is possible to store the star or the plus fix points. I first stored the star fix points. It is often needed. It is safe because it can be applied several times without impacting the result. However, it does not retain information about the cycle body transformer. Because the convex hull operator looses information, it is more accurate to use the plus fix point and to apply a convex hull to the direct precondition and to the cycle output. Thus, if the entry node is a test, its conditions can be added before the convex hull is performed.

It might be useful to add a pseudo-node as predecessor of the CFG entry node. This pseudo-node would simplify the algorithms and the function profiles. Its post-condition would be the precondition of the CFG or no information. Without it, each node must be checked to see if it is the entry node because, then, it has an extra-predecessor.

Francois Irigoin, July 2002 (First version: October 2000)

Note: Bourdoncle's heuristics minimizes the number of cycles under the assumption that most information is lost when performing a widening. We do not use widening but direct computation of an upper approximation of the transition closure. And sometimes, a lot of information is lost when performing convex hulls of transformers. So, using transformers, it would be better to maximize the number of cycles to minimize the number of paths in each cycle. include <stdlib.h>

Definition at line 122 of file unstructured.c.

123 {
124  fprintf(stderr,
125  "ctr %p, %zd preds, %zd succs: %s",
126  c,
130  fprintf(stderr,"\tsuccessors:\n");
131  MAP(CONTROL, s, {
132  fprintf(stderr, "\t\t%p %s", s,
134  }, control_successors(c));
135  fprintf(stderr,"\tpredecessors:\n");
136  MAP(CONTROL, p, {
137  fprintf(stderr, "\t\t%p %s", p,
139  }, control_predecessors(c));
140  fprintf(stderr, "\n");
141 }
size_t gen_length(const list l)
Definition: list.c:150
string safe_statement_identification(statement)
Definition: statement.c:1726

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

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:

◆ print_control_node_unss_sem()

static void print_control_node_unss_sem ( list  l)
static

Definition at line 143 of file unstructured.c.

144 {
145  if(ENDP(l)) {
146  fprintf(stderr, "empty control list");
147  }
148  else {
149  MAP(CONTROL, c, {
150  fprintf(stderr, "%p, %s", c,
152  }, l);
153  }
154  fprintf(stderr, "\n");
155 }

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

Referenced by cycle_to_flow_sensitive_preconditions(), dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), and dag_to_flow_sensitive_preconditions().

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

◆ print_control_postcondition_map()

void print_control_postcondition_map ( control_mapping  control_postcondition_map)

unstructured.c

Parameters
control_postcondition_mapontrol_postcondition_map

Definition at line 294 of file unstructured.c.

296 {
297  if(hash_table_entry_count(control_postcondition_map)>0) {
298  HASH_MAP(c, p, {
300  fprintf(stderr, "Control %p, Statement %s, Temporary postcondition:\n",
303  }, control_postcondition_map);
304  }
305  else {
306  pips_assert("The CFG contains at least one node with one statement",
307  false);
308  }
309 }

References control_statement, fprintf(), HASH_MAP, hash_table_entry_count(), pips_assert, print_transformer, and statement_identification().

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ print_cycle_head_to_fixpoint()

static void print_cycle_head_to_fixpoint ( control  c,
recursive_context pcontext 
)
static

A debug function to prettyprint the fix points.

Most control nodes are not associated to a fix point

Definition at line 1803 of file unstructured.c.

1804 {
1805  control_mapping control_fix_point_map = pcontext->smap;
1807  transformer tf = load_control_postcondition(c, control_fix_point_map);
1808 
1809  /* Most control nodes are not associated to a fix point */
1810  if(!transformer_undefined_p(tf)) {
1811  fprintf(stderr, "Statement %s", statement_identification(s));
1812  pips_assert("Transformer or postcondition is consistent",
1814  print_transformer(tf);
1815  }
1816 }

References control_statement, fprintf(), load_control_postcondition(), pips_assert, print_transformer, recursive_context::smap, statement_identification(), transformer_consistency_p(), and transformer_undefined_p.

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:

◆ print_statement_temporary_precondition()

void print_statement_temporary_precondition ( statement_mapping  statement_temporary_precondition_map)
Parameters
statement_temporary_precondition_maptatement_temporary_precondition_map

Definition at line 1006 of file unstructured.c.

1008 {
1009  if(hash_table_entry_count(statement_temporary_precondition_map)>0) {
1010  HASH_MAP(s, p, {
1011  fprintf(stderr, "Statement %s, Temporary precondition:\n",
1014  }, statement_temporary_precondition_map);
1015  }
1016  else {
1017  pips_assert("The DAG contains at least one control node with one statement", false);
1018  }
1019 }

References fprintf(), HASH_MAP, hash_table_entry_count(), pips_assert, print_transformer, and statement_identification().

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ process_ready_node()

static void process_ready_node ( control  c,
transformer  pre_entry,
transformer  n_pre,
unstructured  u,
control_mapping  control_postcondition_map,
hash_table  ancestor_map,
hash_table  scc_map,
list  partition,
control_mapping  fix_point_map,
bool  postcondition_p 
)
static

Compute its precondition pre from the postconditions of its predecessor and from the entry precondition. Use arc pred->c information to deal with tests.

Do not forget the unstructured precondition for the entry node

FI: I do not know why it has to be replicated. Probably because the statement containing the unstructured and the statement of the entry node may share the same precondition.

memory leak with lpre. pre_entry and postconditions cannot be freed: lpre cannot be freed during the first iteration

if(pred!=CONTROL(CAR(preds))) free_transformer(lpre);

Add the information from the current precondition.

If the control is a cycle head, find and apply its fix point tranformer to the precondition before proceeding into the node itself

unstructured_to_flow_insensitive_transformer(scc_u) cannot be used because it assumes that all transformers for statements in scc_u are defined, which is not true yet.

transformer tf_u = unstructured_to_flow_insensitive_transformer(scc_u);

n_pre_u is assumed more accurate than n_pre

Bourdoncle's processing ordering

A non-deterministic acyclic control flow graph

Mapping from non-deterministic nodes to deterministic nodes

mapping from deterministic nodes to non-deterministic cycles

precondition on entry

precondition true for any node of scc_u.

Compute transformers

The cycle is entered

Or the cycle is not entered and the store is not in fptf's domain.

Have we followed a true or a false branch? We'll know later but it is better to add this information before the convex hull is performed.

FI: I do not know why an empty context is passed down.

Propagate the precondition thru the node to obtain a postcondition which does not include arc information (FI: hard if side-effects?)

FI: The transformer might have to be recomputed before the call if the option is selected? It does not seem to be located in statement_to_postcondition()

FI: is this correct when the statement is a test since the node only exploits the condition? It might be because of the convex hull nullifying the condition and hence the arc information.

FI: statement_to_postcondition() cannot always be used because the statement may appear in different non-deterministic nodes; pre is only of of the many preconditions that can hold before stmt is executed; statement_to_postcondition() should be called later when the whole unstructured has been analyzed.

post = statement_to_postcondition(pre, stmt);

The statement transformer may have been computed earlier thru a fix point calculation, but the transformer may not be correct if it were computed in context (property SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT true).

We are in trouble: the transformer attached to a statement should be the convex hull of its transformers computed in all its context. Our options:

  1. fix statement_to_transformer() to perform the convex hulls when needed
  2. turn off the property SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT as soon as an untructured is entered and restore it on exit
  3. assume that statement stmt is not a compound statement and try to fix the problem locally.

Let's live very dangerously and try 1...

Definition at line 630 of file unstructured.c.

640 {
643  list preds = control_predecessors(c);
645 
646  ifdebug(2) {
647  pips_debug(2, "Begin for control %p with pre_entry=%p:\n", c, pre_entry);
648  print_transformer(pre_entry);
649  pips_debug(2, "Begin with n_pre=%p:\n", n_pre);
650  print_transformer(n_pre);
651  pips_debug(5, "to process node %s\n", statement_identification(control_statement(c)));
652  }
653 
654  /* Compute its precondition pre from the postconditions of its predecessor
655  and from the entry precondition. Use arc pred->c information to deal
656  with tests. */
657 
658  if(c==unstructured_control(u)) {
659  /* Do not forget the unstructured precondition for the entry node */
660  /* FI: I do not know why it has to be replicated. Probably because the
661  statement containing the unstructured and the statement of the
662  entry node may share the same precondition. */
663  pre = copy_transformer(pre_entry);
664  }
665  else {
666  pre = load_arc_precondition(CONTROL(CAR(preds)), c, control_postcondition_map);
667  POP(preds);
668  }
669 
670  MAP(CONTROL, pred, {
671  transformer npre = load_arc_precondition(pred, c, control_postcondition_map);
672  transformer lpre = pre;
673 
674  pre = transformer_convex_hull(npre, lpre);
675  /* memory leak with lpre. pre_entry and postconditions cannot be
676  freed: lpre cannot be freed during the first iteration */
677  /* if(pred!=CONTROL(CAR(preds))) free_transformer(lpre); */
678  free_transformer(lpre);
679  free_transformer(npre);
680  lpre = pre;
681  }, preds);
682 
683  ifdebug(2) {
684  pips_debug(2, "Precondition %p for control %p:\n", pre, c);
685  print_transformer(pre);
686  }
687 
689  /* Add the information from the current precondition. */
692  transformer r_prev_pre = transformer_range(prev_pre);
693 
694  pre = transformer_range_intersection(pre, r_prev_pre);
695  free_transformer(r_prev_pre);
696  ifdebug(2) {
697  pips_debug(2, "Refined precondition %p for control %p:\n", pre, c);
698  print_transformer(pre);
699  }
700  }
701 
702  /* If the control is a cycle head, find and apply its fix point
703  tranformer to the precondition before proceeding into the node itself */
704 
705  if(cycle_head_p(c, ancestor_map, scc_map)) {
706  transformer fptf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
708  transformer pre_no_cycle = transformer_undefined;
709 
710  if(transformer_undefined_p(fptf)) {
711  unstructured scc_u = cycle_head_to_scc(c, ancestor_map, scc_map);
712  /* unstructured_to_flow_insensitive_transformer(scc_u) cannot be
713  used because it assumes that all transformers for statements in
714  scc_u are defined, which is not true yet. */
715  /* transformer tf_u = unstructured_to_flow_insensitive_transformer(scc_u); */
716  list scc_e = non_deterministic_unstructured_to_effects(scc_u, ancestor_map, scc_map);
717  transformer tf_u = effects_to_transformer(scc_e);
718  /* n_pre_u is assumed more accurate than n_pre */
719  transformer n_pre_u = invariant_wrt_transformer(pre, tf_u);
720 
721  ifdebug(6) {
722  pips_debug(6, "Rough fixpoint transformer %p for unstructured %p:\n", tf_u, scc_u);
723  print_transformer(tf_u);
724  pips_debug(6, "Resulting in generic node precondition %p:\n", n_pre_u);
725  print_transformer(n_pre_u);
726  }
727 
728  free_transformer(tf_u);
729  gen_free_list(scc_e);
730 
732  (partition, /* Bourdoncle's processing ordering */
733  scc_u, /* A non-deterministic acyclic control flow graph */
734  ancestor_map, /* Mapping from non-deterministic nodes to deterministic nodes */
735  scc_map, /* mapping from deterministic nodes to non-deterministic cycles */
736  fix_point_map,
737  pre, /* precondition on entry */
738  n_pre_u, /* precondition true for any node of scc_u. */
739  control_postcondition_map, /* */
740  false); /* Compute transformers */
741 
742  ifdebug(2) {
743  pips_debug(2, "Fixpoint transformer %p for control %p:\n", fptf, c);
744  print_transformer(fptf);
745  }
746  }
747 
748  /* The cycle is entered */
749  pre_cycle = transformer_apply(fptf, pre);
750  /* Or the cycle is not entered and the store is not in fptf's domain. */
751  pre_no_cycle = transformer_dup(pre);
752 
753  if(control_test_p(c)) {
754  /* Have we followed a true or a false branch? We'll know later but
755  it is better to add this information before the convex hull is
756  performed. */
759 
760  /* FI: I do not know why an empty context is passed down. */
761  if(true_successors_only_p(c)) {
762  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
763  transformer_undefined, true);
764  }
765  else if(false_successors_only_p(c)) {
766  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
767  transformer_undefined, false);
768  }
769  }
770  free_transformer(pre);
771  pre = transformer_convex_hull(pre_cycle, pre_no_cycle);
772 
773  ifdebug(2) {
774  pips_debug(2, "Precondition after cycle execution %p for control %p:\n", pre, c);
775  print_transformer(pre);
776  pips_debug(2, "derived from pre_cycle %p:\n", pre_cycle);
777  print_transformer(pre_cycle);
778  pips_debug(2, "and from pre_no_cycle %p:\n", pre_no_cycle);
779  print_transformer(pre_no_cycle);
780  }
781 
782  free_transformer(pre_cycle);
783  free_transformer(pre_no_cycle);
784  }
785 
786  /* Propagate the precondition thru the node to obtain a postcondition
787  which does not include arc information (FI: hard if side-effects?) */
788 
789  if(postcondition_p) {
790  /* FI: The transformer might have to be recomputed before the call if
791  the option is selected? It does not seem to be located in
792  statement_to_postcondition() */
793  /* FI: is this correct when the statement is a test since the node
794  only exploits the condition? It might be because of the convex hull
795  nullifying the condition and hence the arc information. */
796  /* FI: statement_to_postcondition() cannot always be used because the
797  statement may appear in different non-deterministic nodes; pre is
798  only of of the many preconditions that can hold before stmt is
799  executed; statement_to_postcondition() should be called later when
800  the whole unstructured has been analyzed. */
801  /* post = statement_to_postcondition(pre, stmt); */
803 
804  pips_assert("The statement transformer is defined",
806  post = transformer_apply(tf, pre);
807 
808  ifdebug(2) {
809  pips_debug(2, "Postcondition %p for control %p:\n", post, c);
810  print_transformer(post);
811  pips_debug(2, "derived from pre %p:\n", pre);
812  print_transformer(pre);
813  pips_debug(2, "and from tf %p:\n", tf);
814  print_transformer(tf);
815  }
816  }
817  else {
818  /* The statement transformer may have been computed earlier thru a fix
819  point calculation, but the transformer may not be correct if it
820  were computed in context (property SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT true). */
823 
824  if(transformer_undefined_p(tfp)) {
825  tf = statement_to_transformer(stmt, pre);
826  }
827  else {
828  if(get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
829  /* We are in trouble: the transformer attached to a statement
830  should be the convex hull of its transformers computed in all
831  its context. Our options:
832 
833  1. fix statement_to_transformer() to perform the convex hulls when needed
834 
835  2. turn off the property
836  SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT as soon as an
837  untructured is entered and restore it on exit
838 
839  3. assume that statement stmt is not a compound statement and
840  try to fix the problem locally.
841 
842  Let's live very dangerously and try 1... */
844 
845  tf = tfn;
846  }
847  else {
848  tf = tfp;
849  }
850  }
851  post = transformer_apply(tf, pre);
852  }
853 
854  store_control_postcondition(c, post, control_postcondition_map);
855 
856  ifdebug(2) {
857  pips_debug(2, "Postcondition %p stored for control %p:\n", post, c);
858  print_transformer(post);
859  }
860 }
bool refine_transformers_p
Transformer recomputation cannot be of real use unless an interprocedural analysis is performed.
transformer effects_to_transformer(list e)
list of effects
transformer cycle_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
Compute transformers or preconditions.
static list non_deterministic_unstructured_to_effects(unstructured scc, hash_table ancestor_map, hash_table scc_map)
Definition: unstructured.c:603
transformer load_statement_precondition(statement)
transformer invariant_wrt_transformer(transformer p, transformer tf)
transformer invariant_wrt_transformer(transformer p, transformer tf): Assume that tf is a fix-point o...
Definition: transformer.c:1948
transformer transformer_range_intersection(transformer tf, transformer r)
Allocate a new transformer rtf that is tf with its range restricted by the range r.
Definition: transformer.c:830
transformer transformer_range(transformer tf)
Return the range of relation tf in a newly allocated transformer.
Definition: transformer.c:714

References CAR, CONTROL, control_predecessors, control_statement, control_test_p(), copy_transformer(), cycle_head_p(), cycle_head_to_scc(), cycle_to_flow_sensitive_postconditions_or_transformers(), effects_to_transformer(), false_successors_only_p(), free_transformer(), gen_free_list(), get_bool_property(), ifdebug, invariant_wrt_transformer(), load_arc_precondition(), load_control_fix_point(), load_statement_precondition(), load_statement_transformer(), MAP, meaningless_control_p(), non_deterministic_unstructured_to_effects(), pips_assert, pips_debug, POP, precondition_add_condition_information(), print_transformer, refine_transformers_p, statement_identification(), statement_test(), statement_to_transformer(), store_control_postcondition(), test_condition, transformer_apply(), transformer_convex_hull(), transformer_dup(), transformer_range(), transformer_range_intersection(), transformer_undefined, transformer_undefined_p, true_successors_only_p(), and unstructured_control.

Referenced by dag_or_cycle_to_flow_sensitive_postconditions_or_transformers().

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

◆ process_unreachable_node()

static bool process_unreachable_node ( control  c,
control_mapping  control_postcondition_map,
bool  postcondition_p 
)
static

Careful, this may have been done earlier by the CONTROL_MAP in unstructured_to_transformers()

FI: We should use the generic node precondition n_pre; it should be an additional component in the context.

Problem with ELSIP in ARC2D after partial redundancy elimination

pips_internal_error(statement_identification(s));

Problem with SHALLOW in SWIM

Definition at line 862 of file unstructured.c.

865 {
867 
868  pips_debug(9,"Statement %s", safe_statement_identification(s));
869 
870  if(!meaningless_control_p(c)) {
872  pips_internal_error("Improper control restructuration, statement with no ordering:%s",
874  }
875 
877  (load_control_postcondition(c, control_postcondition_map))) {
879 
880  if(postcondition_p) {
882  post = statement_to_postcondition(pre, s);
883  }
884  else {
885  /* Careful, this may have been done earlier by the CONTROL_MAP in
886  unstructured_to_transformers() */
888  /* FI: We should use the generic node precondition n_pre; it
889  should be an additional component in the context. */
891  }
892  post = transformer_empty();
893  }
894 
895  semantics_user_warning("After restructuration, unexpected unreachable node:%s",
897 
898  store_control_postcondition(c, post, control_postcondition_map);
899  }
900  else if(postcondition_p
902  /* Problem with ELSIP in ARC2D after partial redundancy elimination */
903  /* pips_internal_error(statement_identification(s)); */
906 
907  pips_assert("the new postcondition is empty", transformer_empty_p(post));
908  pips_assert("the previous postcondition is empty",
909  transformer_empty_p(load_control_postcondition(c, control_postcondition_map)));
910 
911  semantics_user_warning("After restructuration (?),"
912  " postcondtion for unexpected unreachable node:%s",
914  }
915  else if(!postcondition_p
917  /* Problem with SHALLOW in SWIM */
919 
920  semantics_user_warning("After restructuration (?),"
921  " transformer for unexpected unreachable node:%s",
923  }
924  }
925  return true;
926 }
#define pips_internal_error
Definition: misc-local.h:149
#define STATEMENT_ORDERING_UNDEFINED
mapping.h inclusion
Definition: newgen-local.h:35
#define statement_ordering(x)
Definition: ri.h:2454
#define semantics_user_warning
bool transformer_empty_p(transformer t)
If true is returned, the transformer certainly is empty.
Definition: transformer.c:2455

References control_statement, load_control_postcondition(), load_statement_precondition(), load_statement_transformer(), meaningless_control_p(), pips_assert, pips_debug, pips_internal_error, safe_statement_identification(), semantics_user_warning, statement_identification(), statement_ordering, STATEMENT_ORDERING_UNDEFINED, statement_to_postcondition(), statement_to_transformer(), store_control_postcondition(), transformer_empty(), transformer_empty_p(), transformer_undefined, and transformer_undefined_p.

Referenced by local_process_unreachable_node().

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

◆ ready_to_be_processed_p()

static bool ready_to_be_processed_p ( control  c,
list  to_be_processed,
list  still_to_be_processed,
list  already_processed,
control_mapping  control_postcondition_map 
)
static

a control is ready to be processed if all its predecessors have known postconditions or can receive a trivial empty postcondition

useless, except for debugging

postcondition must be empty because pred is not reachable

transformer pre = transformer_empty();

transformer post = statement_to_postcondition(pre, stmt);

Definition at line 427 of file unstructured.c.

432 {
433  bool ready = true;
434  MAP(CONTROL, pred, {
435  if(gen_in_list_p(pred, already_processed)) {
436  /* useless, except for debugging */
437  ready &= true;
438  }
439  else if(!gen_in_list_p(pred, to_be_processed)) {
440  /* postcondition must be empty because pred is not reachable */
441  /* transformer pre = transformer_empty(); */
442  transformer post = load_control_postcondition(pred, control_postcondition_map);
443 
444  if(transformer_undefined_p(post)) {
445  post = transformer_empty();
446  /* transformer post = statement_to_postcondition(pre, stmt); */
447  store_control_postcondition(pred, post, control_postcondition_map);
448  }
449  else {
450  pips_assert("Postcondition for unreachable nodes must be empty",
451  transformer_empty_p(post));
452  }
453  }
454  else if(gen_in_list_p(pred, still_to_be_processed)) {
455  ready &= false;
456  }
457  else {
458  pips_internal_error("node pred does not belong to any category: %s",
460  }
461  }, control_predecessors(c));
462  return ready;
463 }
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734

References CONTROL, control_predecessors, control_statement, gen_in_list_p(), load_control_postcondition(), MAP, pips_assert, pips_internal_error, statement_identification(), store_control_postcondition(), transformer_empty(), transformer_empty_p(), and transformer_undefined_p.

Referenced by cycle_to_flow_sensitive_preconditions(), and dag_or_cycle_to_flow_sensitive_postconditions_or_transformers().

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

◆ remove_cycle_dependencies()

static void remove_cycle_dependencies ( control  c,
control_mapping  cycle_dependencies_map 
)
static

c has been processed and no other cycle can depend on it

Oops... gen_remove() might change the pointer

Definition at line 951 of file unstructured.c.

952 {
953  HASH_MAP(d, dependencies, {
954  /* Oops... gen_remove() might change the pointer */
955  gen_remove((list*) (&dependencies), c);
956  hash_update((hash_table) (cycle_dependencies_map),
957  (void *) d, (void *) dependencies);
958  }, cycle_dependencies_map);
959 }
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491

References gen_remove(), HASH_MAP, and hash_update().

Referenced by dag_to_flow_sensitive_preconditions().

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

◆ store_control_fix_point()

static void store_control_fix_point ( control  c,
transformer  fptf,
control_mapping  control_fix_point_map 
)
static

Definition at line 382 of file unstructured.c.

384 {
385  statement stat = control_statement(c);
386 
387  pips_assert("The statement is defined",
389  pips_debug(8, "Store fix_point for control %p: %s\n",
390  c, statement_identification(stat));
391  ifdebug(8) {
392  print_transformer(fptf);
393  }
394 
395  pips_assert("The fix_point to insert is consistent",
397 
398  pips_assert("The fix_point is not defined yet",
399  hash_get((hash_table) control_fix_point_map, (void *) c)
401  hash_put((hash_table) (control_fix_point_map),
402  (void *)c, (void *) fptf);
403 }
#define statement_undefined_p(x)
Definition: ri.h:2420

References control_statement, hash_get(), hash_put(), HASH_UNDEFINED_VALUE, ifdebug, meaningless_control_p(), pips_assert, pips_debug, print_transformer, statement_identification(), statement_undefined_p, and transformer_consistency_p().

Referenced by dag_or_cycle_to_flow_sensitive_postconditions_or_transformers().

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

◆ store_control_postcondition()

static void store_control_postcondition ( control  c,
transformer  post,
control_mapping  control_postcondition_map 
)
static

Definition at line 245 of file unstructured.c.

247 {
248  statement stat = control_statement(c);
249 
250  pips_assert("The statement is defined",
252  pips_debug(6, "Store postcondition for control %p: %s\n",
253  c, statement_identification(stat));
254  ifdebug(6) {
255  print_transformer(post);
256  }
257 
258  pips_assert("The postcondition to insert is consistent",
260 
261  pips_assert("The postcondition is not defined yet",
262  hash_get((hash_table) control_postcondition_map, (void *) c)
264  hash_put((hash_table) (control_postcondition_map),
265  (void *) c, (void *) post);
266 }

References control_statement, hash_get(), hash_put(), HASH_UNDEFINED_VALUE, ifdebug, meaningless_control_p(), pips_assert, pips_debug, print_transformer, statement_identification(), statement_undefined_p, and transformer_consistency_p().

Referenced by dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(), process_ready_node(), process_unreachable_node(), and ready_to_be_processed_p().

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

◆ unreachable_node_to_transformer()

static void unreachable_node_to_transformer ( control  c)
static

Definition at line 2158 of file unstructured.c.

2159 {
2161 
2162  pips_debug(9,"Statement %s", statement_identification(s));
2163 
2165  semantics_user_warning("Improper control restructuration, statement with no ordering:%s"
2166  "May result from an unreachable exit node\n",
2168  }
2169 
2171  semantics_user_warning("After restructuration, unexpected unreachable node:%s",
2174  }
2175 }

References control_statement, load_statement_transformer(), pips_debug, semantics_user_warning, statement_identification(), statement_ordering, STATEMENT_ORDERING_UNDEFINED, statement_to_transformer(), transformer_undefined, and transformer_undefined_p.

Referenced by unstructured_to_transformer().

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

◆ unstructured_to_effects()

static list unstructured_to_effects ( unstructured  scc,
hash_table  ancestor_map,
hash_table  scc_map 
)
static

In fact, non-deterministic unstructured to effects.

entry point

Definition at line 556 of file unstructured.c.

559 {
560  list el = NIL;
561  list nodes = NIL;
562  control e = unstructured_control(scc); /* entry point */
563 
564  pips_debug(6, "Effect list for unstructured %p with entry %p:begin\n",
565  scc, e);
566 
568  if(!meaningless_control_p(c)) {
571 
573 
574  if(cycle_head_p(c, ancestor_map, scc_map)) {
575  unstructured sub_scc = cycle_head_to_scc(c, ancestor_map, scc_map);
576  if(scc!=sub_scc) {
577  list sl = unstructured_to_effects(sub_scc, ancestor_map, scc_map);
578  list nl = list_undefined;
579  ifdebug(7) {
580  pips_debug(7, "Sub-effect list for unstructured %p with entry %p:\n",
581  sub_scc, unstructured_control(sub_scc));
582  print_effects(sl);
583  pips_debug(7, "Union with previous effects:\n");
584  print_effects(el);
585  }
587  el = nl;
588  ifdebug(7) {
589  pips_debug(7, "Resulting in:\n");
590  print_effects(el);
591  }
592  }
593  }
594  }
595  }, e, nodes);
596  gen_free_list(nodes);
597 
598  pips_debug(6, "Effect list for unstructured %p with entry %p:end\n",
599  scc, e);
600 
601  return el;
602 }
list load_cumulated_rw_effects_list(statement)
bool effects_same_action_p(effect, effect)
list EffectsMayUnion(list l1, list l2, bool(*union_combinable_p)(effect, effect))
list EffectsMayUnion(list l1, list l2, union_combinable_p) input : two lists of effects output : a li...
#define FORWARD_CONTROL_MAP(ctl, code, c, list)
Walk through all the controls forward-reachable from a given control node of an unstructured.
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535

References control_statement, cycle_head_p(), cycle_head_to_scc(), effects_same_action_p(), EffectsMayUnion(), FORWARD_CONTROL_MAP, gen_free_list(), gen_full_copy_list(), ifdebug, list_undefined, load_cumulated_rw_effects_list(), meaningless_control_p(), NIL, pips_debug, print_effects, and unstructured_control.

Referenced by non_deterministic_unstructured_to_effects().

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

◆ unstructured_to_flow_insensitive_transformer()

transformer unstructured_to_flow_insensitive_transformer ( unstructured  u)

This simple fix-point over-approximates the CFG by a fully connected graph.

Each vertex can be executed at any time any number of times.

The fix point is easy to compute because it is the fix point of the convex hull all each node transformers.

The result is sometimes surprising as users see the real paths and cannot understand why a variable is declared modified when it obviously is not. This mostly choses in node preconditions since the overall unstructured transformer is not displayed usually and since it is globally correct.

But it is a perfectly valid over-approximation usable by automatic analyses.

Using the effects of the unstructured to derive a fix point leads to the same surprise although it is as correct, using the same over approximation of the control flow graph but a cruder version of the transformers.

This function is also used when computing preconditions if the exit node is not reached (?). It assumes that transformers for all statements in the unstructured have already been computed.

Two modes are possible: the transitive closure of the convex hull of all elementary transformers, or the transitive closure of the transformer list.

Assume any reachable node is executed at each iteration. A fix-point of the result can be used to approximate the node preconditions. Some nodes can be discarded because they do not modify the store such as IF statements (always) and CONTINUE statements (if they do not link the entry and the exit nodes).

Entry node

transformer_convex_hull has side effects on its arguments:-(

Should be fixed now, 29 June 2000

transformer tf_st = copy_transformer(load_statement_transformer(st));

Any side effect?

test

continue

other

Definition at line 2206 of file unstructured.c.

2207 {
2208  /* Assume any reachable node is executed at each iteration. A fix-point
2209  of the result can be used to approximate the node preconditions. Some
2210  nodes can be discarded because they do not modify the store such as
2211  IF statements (always) and CONTINUE statements (if they do not link
2212  the entry and the exit nodes). */
2213 
2214  list nodes = NIL;
2215  /* Entry node */
2216  control entry_node = unstructured_control(u);
2217  control exit_node = unstructured_exit(u);
2218  transformer tf_u = transformer_empty();
2220  bool tfl_p = get_bool_property("SEMANTICS_USE_TRANSFORMER_LISTS");
2221  list tfl = NIL;
2222 
2223  pips_debug(8,"begin\n");
2224 
2225  FORWARD_CONTROL_MAP(c, {
2226  statement st = control_statement(c);
2227  /* transformer_convex_hull has side effects on its arguments:-( */
2228  /* Should be fixed now, 29 June 2000 */
2229  /* transformer tf_st = copy_transformer(load_statement_transformer(st)); */
2231  transformer tf_old = tf_u;
2232 
2233  if(statement_test_p(st)) {
2234  /* Any side effect? */
2235  if(!ENDP(transformer_arguments(tf_st))) {
2236  if(tfl_p) {
2237  tfl = CONS(TRANSFORMER, tf_st, tfl);
2238  }
2239  else {
2240  tf_u = transformer_convex_hull(tf_old, tf_st); /* test */
2241  free_transformer(tf_old);
2242  }
2243  }
2244  }
2245  else {
2246  if(continue_statement_p(st)) {
2248  && gen_find_eq(exit_node, control_successors(c))!=chunk_undefined) {
2249  if(tfl_p) {
2250  tfl = CONS(TRANSFORMER, tf_st, tfl);
2251  }
2252  else {
2253  tf_u = transformer_convex_hull(tf_old, tf_st); /* continue */
2254  free_transformer(tf_old);
2255  }
2256  }
2257  }
2258  else {
2259  if(tfl_p) {
2260  tfl = CONS(TRANSFORMER, tf_st, tfl);
2261  }
2262  else {
2263  tf_u = transformer_convex_hull(tf_old, tf_st); /* other */
2264  free_transformer(tf_old);
2265  }
2266  }
2267  }
2268 
2269  ifdebug(1) {
2270  pips_assert("tf_st is internally consistent",
2272  if(!tfl_p)
2273  pips_assert("tf_u is internally consistent",
2275  }
2276 
2277  }, entry_node, nodes) ;
2278 
2279  gen_free_list(nodes) ;
2280 
2281  if(tfl_p) {
2282  // FI: apparently, we need T* rather than T+
2283  fp_tf_u = transformer_list_transitive_closure(tfl);
2284  gen_free_list(tfl);
2285  }
2286  else
2287  fp_tf_u = (*transformer_fix_point_operator)(tf_u);
2288 
2289  ifdebug(8) {
2290  pips_debug(8,"Result for one step tf_u:\n");
2291  print_transformer(tf_u);
2292  pips_assert("tf_u is internally consistent",
2294  pips_debug(8,"Result for fix-point fp_tf_u:\n");
2295  print_transformer(fp_tf_u);
2296  pips_assert("fp_tf_u is internally consistent",
2298  }
2299 
2300  pips_debug(8,"end\n");
2301 
2302  return fp_tf_u;
2303 }
bool transformer_internal_consistency_p(transformer t)
Same as above but equivalenced variables should not appear in the argument list or in the predicate b...
Definition: basic.c:790
#define chunk_undefined
obsolete
Definition: genC.h:79
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
#define transformer_arguments(x)
Definition: ri.h:2871
#define unstructured_exit(x)
Definition: ri.h:3006
transformer transformer_list_transitive_closure(list)
Compute (U tfl)*.

References chunk_undefined, CONS, continue_statement_p(), control_predecessors, control_statement, control_successors, ENDP, FORWARD_CONTROL_MAP, free_transformer(), gen_find_eq(), gen_free_list(), get_bool_property(), ifdebug, load_statement_transformer(), NIL, pips_assert, pips_debug, print_transformer, statement_test_p(), TRANSFORMER, transformer_arguments, transformer_convex_hull(), transformer_empty(), transformer_internal_consistency_p(), transformer_list_transitive_closure(), transformer_undefined, unstructured_control, and unstructured_exit.

Referenced by unstructured_to_postcondition(), unstructured_to_total_precondition(), and unstructured_to_transformer().

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

◆ unstructured_to_flow_sensitive_postconditions()

transformer unstructured_to_flow_sensitive_postconditions ( transformer  pre_u,
transformer  pre,
unstructured  u 
)

compute pre- and post-conditions in an unstructured from the entry precondition pre and return the exit postcondition.

pre_u is pre filtered by the u's transformer and can be used for any node.

control tail = unstructured_exit(u);

Parameters
pre_ure_u
prere

Definition at line 2040 of file unstructured.c.

2042 {
2044  list succs = NIL;
2045  control head = unstructured_control(u);
2046  /* control tail = unstructured_exit(u); */
2047 
2048  forward_control_map_get_blocs(head, &succs);
2049 
2050  if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE1")) {
2051  semantics_user_warning("\nControl flow graph too large for an accurate analysis (%d nodes)\n"
2052  "Have you fully restructured your code?\n", gen_length(succs));
2053  post = unstructured_to_postconditions(pre, pre_u, u);
2054  }
2055  else if(!get_bool_property("SEMANTICS_ANALYZE_UNSTRUCTURED")) {
2056  semantics_user_warning("\nControl flow graph not analyzed accurately"
2057  " because property SEMANTICS_ANALYZE_UNSTRUCTURED is not set\n");
2058  post = unstructured_to_postconditions(pre_u, pre, u);
2059  }
2060  else if(!get_bool_property("SEMANTICS_FIX_POINT")) {
2061  post = unstructured_to_postconditions(pre_u, pre, u);
2062  }
2063  else {
2065  (pre_u, pre, u, true);
2066  }
2067  gen_free_list(succs);
2068 
2069  pips_assert("Postcondition for unstructured is consistent",
2071 
2072  return post;
2073 }
int get_int_property(const string)
static transformer unstructured_to_postconditions(transformer pre, transformer pre_first, unstructured u)
transformer unstructured_to_flow_sensitive_postconditions_or_transformers(transformer pre_u, transformer pre, unstructured u, bool postcondition_p)
compute either the postconditions in an unstructured or the transformer of this unstructured.

References forward_control_map_get_blocs(), gen_free_list(), gen_length(), get_bool_property(), get_int_property(), NIL, pips_assert, semantics_user_warning, transformer_consistency_p(), transformer_undefined, unstructured_control, unstructured_to_flow_sensitive_postconditions_or_transformers(), and unstructured_to_postconditions().

Referenced by unstructured_to_postcondition().

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

◆ unstructured_to_flow_sensitive_postconditions_or_transformers()

transformer unstructured_to_flow_sensitive_postconditions_or_transformers ( transformer  pre_u,
transformer  pre,
unstructured  u,
bool  postcondition_p 
)

compute either the postconditions in an unstructured or the transformer of this unstructured.

In both cases, transformers for all nodes used to be supposed to be available.

Do not go down into nested unstructured

Propagate the precondition in the DAG and recompute the cycle transformers or compute the path transformers and the cycle fix point transformers.

Compute the real precondition for each statement and propagate postconditions in it.

Take care of unreachable nodes

Get rid of the auxiliary data structures

Parameters
pre_ure_u
preprecondition at entry: e_pre
uprecondition true for every node: n_pre
postcondition_postcondition_p

Definition at line 1821 of file unstructured.c.

1826 {
1828  hash_table ancestor_map = hash_table_undefined;
1829  hash_table scc_map = hash_table_undefined;
1830  control_mapping fix_point_map = make_control_fix_point_map();
1832  list partition = bourdoncle_partition(u, &ndu, &ancestor_map, &scc_map);
1833  control_mapping control_postcondition_map = make_control_postcondition_map();
1834  transformer pre_u_r = transformer_range(pre_u);
1835  transformer pre_r = transformer_range(pre);
1836 
1837  recursive_context context = { postcondition_p, control_postcondition_map };
1838 
1839  recursive_context fcontext = { postcondition_p, fix_point_map };
1840 
1841  ifdebug(2) {
1842  pips_debug(2, "Begin for %s with nodes:\n",
1843  postcondition_p? "postconditions" : "transformer");
1844  /* Do not go down into nested unstructured */
1847  pips_debug(2, "With entry nodes\n");
1849  pips_debug(2, "And exit node\n");
1851  pips_debug(2, "And embedding graph:\n");
1854  }
1855 
1856  /* Propagate the precondition in the DAG and recompute the cycle
1857  transformers or compute the path transformers and the cycle fix point
1858  transformers. */
1860  (partition, ndu, ancestor_map, scc_map, fix_point_map,
1861  postcondition_p? pre_u : pre_u_r, postcondition_p? pre : pre_r,
1862  control_postcondition_map, postcondition_p);
1863 
1864  if(postcondition_p) {
1865  /* Compute the real precondition for each statement and propagate
1866  postconditions in it. */
1867 
1869  (partition, ndu, ancestor_map, scc_map, fix_point_map, pre_u, pre,
1870  control_postcondition_map);
1871  }
1872 
1873  /* Take care of unreachable nodes */
1875  ndu, (void *) & context,
1878  NULL);
1879 
1880  ifdebug(2) {
1881  pips_debug(2, "%s for unstructured\n",
1882  postcondition_p? "Postconditions": "Path transformer");
1884  ndu, (void *) & context,
1888  NULL);
1889  pips_debug(2, "End of map\n");
1890  if(hash_table_entry_count(fix_point_map)>0) {
1891  pips_debug(2, "Fix point map:\n");
1893  u, (void *) & fcontext,
1897  NULL);
1898  pips_debug(2, "End of fix point map\n");
1899  pips_debug(2, "Dump fix point map %p:\n", fix_point_map);
1900  HASH_MAP(k, v, {
1901  control c = (control) k;
1903  transformer fp_tf = (transformer) v;
1904 
1906  fprintf(stderr, "Statement %s", statement_identification(s));
1907  print_transformer(fp_tf);
1908  }, fix_point_map);
1909  pips_debug(2, "End of fix point map dump\n");
1910  }
1911  else {
1912  fprintf(stderr, "No fix point. Empty fix point map\n");
1913  }
1914  }
1915 
1916  post = copy_transformer
1918  control_postcondition_map));
1919  control_postcondition_map = free_control_postcondition_map(control_postcondition_map);
1920  fix_point_map = free_control_fix_point_map(fix_point_map);
1921 
1922  ifdebug(2) {
1923  pips_assert("The postcondition post is defined", !transformer_undefined_p(post));
1924  pips_debug(2, "End with unstructured postcondition:\n");
1925  print_transformer(post);
1926  }
1927 
1928  /* Get rid of the auxiliary data structures */
1929  bourdoncle_free(ndu, ancestor_map, scc_map);
1930 
1931  return post;
1932 }
void bourdoncle_free(unstructured ndu, hash_table ancestor_map, hash_table scc_map)
Definition: bourdoncle.c:2506
list bourdoncle_partition(unstructured u, unstructured *p_ndu, hash_table *p_ancestor_map, hash_table *p_scc_map)
Definition: bourdoncle.c:1902
void gen_multi_recurse(void *o,...)
Multi recursion visitor function.
Definition: genClib.c:3428
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
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
struct _newgen_struct_control_ * control
#define hash_table_undefined
Value of an undefined hash_table.
Definition: newgen_hash.h:49
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
static control_mapping free_control_postcondition_map(control_mapping control_postcondition_map)
Definition: unstructured.c:318
static control_mapping make_control_postcondition_map()
Definition: unstructured.c:311
static control_mapping free_control_fix_point_map(control_mapping control_fix_point_map)
Definition: unstructured.c:412
static control_mapping make_control_fix_point_map()
Definition: unstructured.c:405
static void local_process_unreachable_node(control c, recursive_context *pcontext)
static void dag_to_flow_sensitive_preconditions(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer pre_u, transformer pre, control_mapping control_postcondition_map)
transformer dag_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
Compute transformers or preconditions.
static void print_control_node_uns(control c)
semantical analysis
Definition: unstructured.c:122
static void print_cycle_head_to_fixpoint(control c, recursive_context *pcontext)
A debug function to prettyprint the fix points.
static void node_to_path_transformer_or_postcondition(control c, recursive_context *pcontext)
A debug function to prettyprint the result.
Definition: delay.c:253

References bourdoncle_free(), bourdoncle_partition(), control_domain, control_statement, copy_transformer(), dag_to_flow_sensitive_postconditions_or_transformers(), dag_to_flow_sensitive_preconditions(), fprintf(), free_control_fix_point_map(), free_control_postcondition_map(), gen_context_multi_recurse(), gen_false(), gen_multi_recurse(), gen_null(), gen_true(), HASH_MAP, hash_table_entry_count(), hash_table_undefined, ifdebug, load_control_postcondition(), local_process_unreachable_node(), make_control_fix_point_map(), make_control_postcondition_map(), node_to_path_transformer_or_postcondition(), pips_assert, pips_debug, print_control_node_uns(), print_cycle_head_to_fixpoint(), print_transformer, statement_domain, statement_identification(), transformer_range(), transformer_undefined, transformer_undefined_p, unstructured_control, unstructured_exit, and unstructured_undefined.

Referenced by unstructured_to_flow_sensitive_postconditions(), and unstructured_to_transformer().

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

◆ unstructured_to_flow_sensitive_total_preconditions()

transformer unstructured_to_flow_sensitive_total_preconditions ( transformer  t_post_u,
transformer  pre,
unstructured  u 
)

control tail = unstructured_exit(u);

Parameters
t_post_u_post_u
prere

Definition at line 2473 of file unstructured.c.

2475 {
2478  /* control tail = unstructured_exit(u); */
2479 
2480  pips_assert("Not implemented yet", false);
2481  pips_assert("Shut up the compiler", t_post_u==t_post_u && pre==pre && u==u);
2482 
2483  pips_assert("Total precondition for unstructured is consistent",
2484  transformer_consistency_p(t_pre));
2485 
2486  return post;
2487 }

References pips_assert, transformer_consistency_p(), and transformer_undefined.

Referenced by unstructured_to_total_precondition().

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

◆ unstructured_to_postcondition()

transformer unstructured_to_postcondition ( transformer  pre,
unstructured  u,
transformer  tf 
)

there is only one statement and no arcs in u; no need for a fix-point

FI: pre should not be duplicated because statement_to_postcondition() means that pre is not going to be changed, just post produced.

Do not try anything clever! God knows what may happen in unstructured code. Postcondition post is not computed recursively from its components but directly derived from u's transformer. Preconditions associated to its components are then computed independently, hence the name unstructured_to_postconditionS instead of unstructured_to_postcondition

propagate as precondition an invariant for the whole unstructured u assuming that all nodes in the CFG are fully connected, unless tf is not feasible because the unstructured is never exited or exited thru a call to STOP which invalidates the previous assumption.

FI: I do not know if I should duplicate pre or not.

FI: well, dumdum, you should have duplicated tf!

FI: euh... why? According to comments about transformer_apply() neither arguments are modified...

post = unstructured_to_postconditions(pre_n, pre, u);

Parameters
prere
tff

Definition at line 2075 of file unstructured.c.

2079 {
2080  transformer post;
2081  control c;
2082 
2083  pips_debug(8, "begin\n");
2084 
2085  pips_assert("unstructured u is defined", u!=unstructured_undefined);
2086 
2087  c = unstructured_control(u);
2088  if(control_predecessors(c) == NIL && control_successors(c) == NIL) {
2089  /* there is only one statement and no arcs in u; no need for a
2090  fix-point */
2091  pips_debug(8, "unique node\n");
2092  /* FI: pre should not be duplicated because
2093  * statement_to_postcondition() means that pre is not
2094  * going to be changed, just post produced.
2095  */
2097  control_statement(c));
2098  }
2099  else {
2100  /* Do not try anything clever! God knows what may happen in
2101  unstructured code. Postcondition post is not computed recursively
2102  from its components but directly derived from u's transformer.
2103  Preconditions associated to its components are then computed
2104  independently, hence the name unstructured_to_postconditionS
2105  instead of unstructured_to_postcondition */
2106  /* propagate as precondition an invariant for the whole
2107  unstructured u assuming that all nodes in the CFG are fully
2108  connected, unless tf is not feasible because the unstructured
2109  is never exited or exited thru a call to STOP which invalidates
2110  the previous assumption. */
2113 
2114  pips_debug(8, "complex: based on transformer\n");
2115  if(transformer_empty_p(tf)) {
2117  }
2118  else {
2119  tf_u = tf;
2120  }
2121  pre_n = invariant_wrt_transformer(pre, tf_u);
2122  ifdebug(8) {
2123  pips_debug(8, "filtered over approximated precondition holding for any node pre_n:\n");
2124  (void) print_transformer(pre_n) ;
2125  }
2126  /* FI: I do not know if I should duplicate pre or not. */
2127  /* FI: well, dumdum, you should have duplicated tf! */
2128  /* FI: euh... why? According to comments about transformer_apply()
2129  * neither arguments are modified...
2130  */
2131  /* post = unstructured_to_postconditions(pre_n, pre, u); */
2132  post = unstructured_to_flow_sensitive_postconditions(pre, pre_n, u);
2133  pips_assert("A valid postcondition is returned",
2134  !transformer_undefined_p(post));
2135  if(transformer_undefined_p(post)) {
2136  post = transformer_apply(transformer_dup(tf), pre);
2137  }
2138  transformer_free(pre_n);
2139  }
2140 
2141  pips_debug(8, "end\n");
2142 
2143  return post;
2144 }
void transformer_free(transformer t)
Definition: basic.c:68
transformer unstructured_to_flow_sensitive_postconditions(transformer pre_u, transformer pre, unstructured u)
compute pre- and post-conditions in an unstructured from the entry precondition pre and return the ex...
transformer unstructured_to_flow_insensitive_transformer(unstructured u)
This simple fix-point over-approximates the CFG by a fully connected graph.

References control_predecessors, control_statement, control_successors, ifdebug, invariant_wrt_transformer(), NIL, pips_assert, pips_debug, print_transformer, statement_to_postcondition(), transformer_apply(), transformer_dup(), transformer_empty_p(), transformer_free(), transformer_undefined, transformer_undefined_p, unstructured_control, unstructured_to_flow_insensitive_transformer(), unstructured_to_flow_sensitive_postconditions(), and unstructured_undefined.

Referenced by instruction_to_postcondition().

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

◆ unstructured_to_postconditions()

static transformer unstructured_to_postconditions ( transformer  pre,
transformer  pre_first,
unstructured  u 
)
static

SHARING! Every statement gets a pointer to the same precondition! I do not know if it's good or not but beware the bugs!!!

FI: changed to make free_transformer_mapping possible without testing sharing.

pre and pre_first can or not be used depending on the unstructured structure. They are always duplicated and the caller has to take care of their de-allocation.

special case for the first node if it has no predecessor

and if it is a test, as it always should, at least if

unspaghettify has been applied...

this is pretty useless and should be generalized to the DAG part of the CFG

refine the precondition if the node has only one predecessor and if this predecessor is a test and if the test can be exploited

the condition is true if c is the first successor of prev_c

Parameters
pre_firstprecondition holding for any node
uprecondition holding at entry

Definition at line 1952 of file unstructured.c.

1956 {
1957  list nodes = NIL ;
1958  control entry_node = unstructured_control(u) ;
1959  control exit_node = unstructured_exit(u) ;
1962  transformer exit_post = transformer_undefined;
1963 
1964  pips_debug(8, "begin\n");
1965 
1966  /* SHARING! Every statement gets a pointer to the same precondition!
1967  * I do not know if it's good or not but beware the bugs!!!
1968  */
1969  /* FI: changed to make free_transformer_mapping possible without
1970  * testing sharing.
1971  *
1972  * pre and pre_first can or not be used depending on the
1973  * unstructured structure. They are always duplicated and
1974  * the caller has to take care of their de-allocation.
1975  */
1976  CONTROL_MAP(c, {
1977  statement st = control_statement(c) ;
1978  if(c==entry_node && ENDP(control_predecessors(c)) && statement_test_p(st)) {
1979  /* special case for the first node if it has no predecessor */
1980  /* and if it is a test, as it always should, at least if */
1981  /* unspaghettify has been applied... */
1982  /* this is pretty useless and should be generalized to the
1983  DAG part of the CFG */
1984  c_pre = transformer_dup(pre_first);
1985  post = statement_to_postcondition(c_pre, st);
1986  transformer_free(post);
1987  }
1988  else {
1990 
1991  c_pre = transformer_dup(pre);
1992  c_pre_m = c_pre;
1993 
1994  /* refine the precondition if the node has only one
1995  predecessor and if this predecessor is a test and if the
1996  test can be exploited */
1997  if(gen_length(control_predecessors(c))==1 && c!=entry_node) {
1998  control prev_c = CONTROL(CAR(control_predecessors(c)));
1999  statement prev_st = control_statement(prev_c);
2000 
2001  if(statement_test_p(prev_st)) {
2002  /* the condition is true if c is the first successor of prev_c */
2003  bool true_false = (c==(CONTROL(CAR(control_successors(prev_c)))));
2006 
2007  c_pre_m = precondition_add_condition_information(c_pre, e, context, true_false);
2009  }
2010  }
2011 
2012  post = statement_to_postcondition(c_pre_m, st);
2013  if(c==exit_node) {
2014  exit_post = post;
2015  }
2016  else {
2017  transformer_free(post);
2018  }
2019  }
2020  }, entry_node, nodes);
2021 
2022  gen_free_list(nodes) ;
2023 
2024  if(transformer_undefined_p(exit_post)) {
2025  exit_post = transformer_empty();
2026  }
2027 
2028  ifdebug(8) {
2029  pips_debug(8, "exit postcondition:\n");
2030  (void) print_transformer(exit_post) ;
2031  }
2032  pips_debug(8, "end\n");
2033 
2034  return exit_post;
2035 }
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.

References CAR, CONTROL, CONTROL_MAP, control_predecessors, control_statement, control_successors, ENDP, free_transformer(), gen_free_list(), gen_length(), ifdebug, NIL, pips_debug, precondition_add_condition_information(), print_transformer, statement_test(), statement_test_p(), statement_to_postcondition(), test_condition, transformer_dup(), transformer_empty(), transformer_free(), transformer_range(), transformer_undefined, transformer_undefined_p, unstructured_control, and unstructured_exit.

Referenced by unstructured_to_flow_sensitive_postconditions().

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

◆ unstructured_to_transformer()

transformer unstructured_to_transformer ( unstructured  u,
transformer  e_pre,
list  e 
)

effects of u

approximate store condition for all control nodes: simple context for improved transformer derivation; it is not a precondition and should have no arguments.

Same as previous one for the store on entry in the unstructured. This the entry node usually has predecessors in the CFG, this is not the context for the entry node. It is not a precondition.

No information available on entrance

Cheapest fix point transformer. The flow insensitive fix point could be used instead.

pre is replaced by its range condition later when needed

Transformers should be computed precisely whether the unstructured is left by the exit node or by an explicit or implicit call to STOP.

computing the transformer for u is like computing the postcondition with no information on entry: no, the input context may be used to refine the transformer.

pre_u is restricted to its range later when needed.

These tests should be performed at the scc level

Not really linked to fix point issue, but a way to know we are using a FAST option.

Do something for nodes unreachable from the entry but linked to the exit

The control flow graph is never exited... by the exit node

The unstructured is never exited, but all nodes are supposed to have transformers. This would never occur if the control restructuration were clean unless an infinite loop is stopped within a called procedure. Control effects are not reported.

FI: pre should be used!

Might be useless because it's now performed just above and more generally by a gen_multi_recurse()

Parameters
e_pre_pre
eprecondition on entrance

Definition at line 2332 of file unstructured.c.

2335 {
2337  list succs = NIL;
2338  control head = unstructured_control(u);
2339  control tail = unstructured_exit(u);
2340  /* approximate store condition for all control nodes: simple context for
2341  improved transformer derivation; it is not a precondition and should have no
2342  arguments. */
2344  /* Same as previous one for the store on entry in the unstructured. This
2345  the entry node usually has predecessors in the CFG, this is not the
2346  context for the entry node. It is not a precondition. */
2348 
2349  if(transformer_undefined_p(e_pre)) {
2350  /* No information available on entrance */
2351  pre = transformer_identity();
2352  }
2353  else {
2354  /* Cheapest fix point transformer. The flow insensitive fix point
2355  could be used instead. */
2357 
2358  /* pre is replaced by its range condition later when needed*/
2359  pre = transformer_safe_apply(fpf, e_pre);
2360  free_transformer(fpf);
2361  }
2362 
2363  pips_debug(8,"begin\n");
2364 
2365  forward_control_map_get_blocs(head, &succs);
2366 
2367  /* Transformers should be computed precisely whether the unstructured is
2368  left by the exit node or by an explicit or implicit call to STOP. */
2369  if(true || gen_in_list_p(tail, succs)) {
2370  /* computing the transformer for u is like computing the postcondition
2371  with no information on entry: no, the input context may be used to
2372  refine the transformer. */
2373 
2374  if(transformer_undefined_p(e_pre)) {
2375  pre_u = transformer_identity();
2376  }
2377  else {
2378  /* pre_u is restricted to its range later when needed. */
2379  pre_u = transformer_dup(e_pre);
2380  }
2381 
2382  /* These tests should be performed at the scc level */
2383  if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE2")) {
2384  semantics_user_warning("\nControl flow graph too large for any analysis (%d nodes)\n"
2385  "Have you fully restructured your code?\n", gen_length(succs));
2387 
2388  if(!gen_in_list_p(tail, succs)) {
2389  tf = transformer_empty();
2390  }
2391  else {
2392  tf = effects_to_transformer(e);
2393  }
2394  }
2395  else if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE1")) {
2396  semantics_user_warning("\nControl flow graph too large for an accurate analysis (%d nodes)\n"
2397  "Have you fully restructured your code?\n", gen_length(succs));
2399 
2400  if(!gen_in_list_p(tail, succs)) {
2401  tf = transformer_empty();
2402  }
2403  else {
2405  }
2406  }
2407  else if(!get_bool_property("SEMANTICS_ANALYZE_UNSTRUCTURED")) {
2408  semantics_user_warning("\nControl flow graph not analyzed accurately"
2409  " because property SEMANTICS_ANALYZE_UNSTRUCTURED is not set\n");
2411 
2412  if(!gen_in_list_p(tail, succs)) {
2413  tf = transformer_empty();
2414  }
2415  else {
2417  }
2418  }
2419  else if(!get_bool_property("SEMANTICS_FIX_POINT")) {
2420  /* Not really linked to fix point issue, but a way to know we are
2421  using a FAST option. */
2423 
2424  if(!gen_in_list_p(tail, succs)) {
2425  tf = transformer_empty();
2426  }
2427  else {
2429  }
2430  }
2431  else {
2433  (pre_u, pre, u, false);
2434  }
2435  free_transformer(pre_u);
2436  }
2437 
2438  if(!gen_in_list_p(tail, succs)) {
2439  /* Do something for nodes unreachable from the entry but linked to the exit */
2440  /* The control flow graph is never exited... by the exit node */
2441  /* The unstructured is never exited, but all nodes are supposed to
2442  have transformers. This would never occur if the control
2443  restructuration were clean unless an infinite loop is stopped
2444  within a called procedure. Control effects are not reported. */
2445  /* FI: pre should be used! */
2447  u,
2450  NULL);
2451  }
2452 
2453  /* Might be useless because it's now performed just above and more
2454  generally by a gen_multi_recurse() */
2455  if(!gen_in_list_p(tail, succs)) {
2456  pips_assert("if exit is not reached, tf is empty", transformer_empty_p(tf));
2457  tf = transformer_empty();
2458  }
2459 
2460  gen_free_list(succs);
2461  free_transformer(pre);
2462 
2463  pips_debug(8,"end\n");
2464 
2465  return tf;
2466 }
static void unreachable_node_to_transformer(control c)
static void unstructured_to_transformers(unstructured u, transformer pre)
Computation of transformers associated to each node of u and to each of its sub-statements.
transformer transformer_safe_apply(transformer tf, transformer pre)
Definition: transformer.c:1627

References control_domain, effects_to_transformer(), forward_control_map_get_blocs(), free_transformer(), gen_false(), gen_free_list(), gen_in_list_p(), gen_length(), gen_multi_recurse(), gen_null(), gen_true(), get_bool_property(), get_int_property(), NIL, pips_assert, pips_debug, semantics_user_warning, statement_domain, transformer_dup(), transformer_empty(), transformer_empty_p(), transformer_identity(), transformer_safe_apply(), transformer_undefined, transformer_undefined_p, unreachable_node_to_transformer(), unstructured_control, unstructured_exit, unstructured_to_flow_insensitive_transformer(), unstructured_to_flow_sensitive_postconditions_or_transformers(), and unstructured_to_transformers().

Referenced by instruction_to_transformer().

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

◆ unstructured_to_transformers()

static void unstructured_to_transformers ( unstructured  u,
transformer  pre 
)
static

Computation of transformers associated to each node of u and to each of its sub-statements.

pre is valid for any node of u

There is no need to compute transformers for unreachable code, using CONTROL_MAP, but this may create storage and prettyprinter problems because of the data structure inconsistency.

Definition at line 2309 of file unstructured.c.

2312 {
2313  list blocs = NIL ;
2314  control ct = unstructured_control(u) ;
2315 
2316  pips_debug(5,"begin\n");
2317 
2318  /* There is no need to compute transformers for unreachable code,
2319  * using CONTROL_MAP, but this may create storage and prettyprinter
2320  * problems because of the data structure inconsistency.
2321  */
2322  CONTROL_MAP(c, {
2323  statement st = control_statement(c) ;
2324  (void) statement_to_transformer(st, pre) ;
2325  }, ct, blocs) ;
2326 
2327  gen_free_list(blocs) ;
2328 
2329  pips_debug(5,"end\n");
2330 }

References CONTROL_MAP, control_statement, gen_free_list(), NIL, pips_debug, statement_to_transformer(), and unstructured_control.

Referenced by unstructured_to_transformer().

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

◆ update_control_postcondition()

static void update_control_postcondition ( control  c,
transformer  post,
control_mapping  control_postcondition_map 
)
static

Definition at line 268 of file unstructured.c.

270 {
271  statement stat = control_statement(c);
272 
273  pips_assert("The statement is defined",
275  pips_assert("The postcondition is already defined",
276  hash_get((hash_table) control_postcondition_map, (void *) c)
278 
279  ifdebug(6) {
280  transformer old_post = hash_get((hash_table) control_postcondition_map,
281  (void *) c);
282  pips_debug(6, "Update postcondition for control %p and statement %s:\n",
283  c, statement_identification(stat));
284  pips_debug(6, "Old postcondition:\n");
285  print_transformer(old_post);
286  pips_debug(6, "New postcondition:\n");
287  print_transformer(post);
288  }
289 
290  hash_update((hash_table) (control_postcondition_map),
291  (void *)c, (void *) post);
292 }

References control_statement, hash_get(), HASH_UNDEFINED_VALUE, hash_update(), ifdebug, meaningless_control_p(), pips_assert, pips_debug, print_transformer, statement_identification(), and statement_undefined_p.

Referenced by cycle_to_flow_sensitive_preconditions().

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

◆ update_cycle_temporary_precondition()

void update_cycle_temporary_precondition ( control  c,
transformer  pre,
control_mapping  cycle_temporary_precondition_map 
)
Parameters
prere
cycle_temporary_precondition_mapycle_temporary_precondition_map

Definition at line 1021 of file unstructured.c.

1024 {
1026 
1027  pips_debug(2, "For control %p with statement %s:\n", c, statement_identification(s));
1029  ((void *) c, pre, (hash_table) cycle_temporary_precondition_map);
1030 
1031  ifdebug(6) {
1032  pips_debug(6, "Precondition %p for cycle %p:\n", pre, c);
1033  print_transformer(pre);
1034  }
1035 }
void update_temporary_precondition(void *k, transformer pre, hash_table precondition_map)
Definition: unstructured.c:975

References control_statement, ifdebug, pips_debug, print_transformer, statement_identification(), and update_temporary_precondition().

Referenced by cycle_to_flow_sensitive_preconditions(), and dag_to_flow_sensitive_preconditions().

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

◆ update_statement_temporary_precondition()

void update_statement_temporary_precondition ( statement  s,
transformer  pre,
statement_mapping  statement_temporary_precondition_map 
)
Parameters
prere
statement_temporary_precondition_maptatement_temporary_precondition_map

Definition at line 997 of file unstructured.c.

1000 {
1001  pips_debug(2, "For statement %s:\n", statement_identification(s));
1003  ((void *) s, pre, (hash_table) statement_temporary_precondition_map);
1004 }

References pips_debug, statement_identification(), and update_temporary_precondition().

Referenced by cycle_to_flow_sensitive_preconditions(), and dag_to_flow_sensitive_preconditions().

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

◆ update_temporary_precondition()

void update_temporary_precondition ( void *  k,
transformer  pre,
hash_table  precondition_map 
)
Parameters
prere
precondition_maprecondition_map

Definition at line 975 of file unstructured.c.

978 {
979  transformer t_pre = (transformer) hash_get(precondition_map, k);
980 
981  if(t_pre == (transformer) HASH_UNDEFINED_VALUE) {
982  pips_debug(2, "No previous precondition. Current one %p:\n", pre);
983  ifdebug(2) print_transformer(pre);
984  hash_put(precondition_map, k, (void *) transformer_dup(pre));
985  }
986  else {
987  transformer n_t_pre = transformer_convex_hull(pre, t_pre);
988  hash_update(precondition_map, k, (void *) n_t_pre);
989  pips_debug(2, "Previous precondition %p:\n", t_pre);
990  ifdebug(2) print_transformer(t_pre);
991  pips_debug(2, "New precondition %p:\n", n_t_pre);
992  ifdebug(2) print_transformer(n_t_pre);
993  free_transformer(t_pre);
994  }
995 }
#define New
else
Definition: set.c:239

References free_transformer(), hash_get(), hash_put(), HASH_UNDEFINED_VALUE, hash_update(), ifdebug, pips_debug, print_transformer, transformer_convex_hull(), and transformer_dup().

Referenced by update_cycle_temporary_precondition(), and update_statement_temporary_precondition().

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