PIPS
transformer_list.c File Reference
#include <stdio.h>
#include "boolean.h"
#include "vecteur.h"
#include "contrainte.h"
#include "sc.h"
#include "genC.h"
#include "linear.h"
#include "ri.h"
#include "ri-util.h"
#include "properties.h"
#include "misc.h"
#include "transformer.h"
+ Include dependency graph for transformer_list.c:

Go to the source code of this file.

Functions

list merge_transformer_lists (list tl1, list tl2)
 Functions to deal with transformer lists. More...
 
bool check_transformer_list (list tl)
 What do we want to impose? More...
 
list combine_transformer_lists (list tl1, list tl2)
 each transformer of tl1 must be combined with a transformer of tl2, including the identity transformer. More...
 
list apply_transformer_lists_generic (list tl1, list tl2, bool exclude_p)
 each transformer of tl1 must be applied to each precondition of tl2, including the identity transformer. More...
 
list apply_transformer_lists (list tl1, list tl2)
 
list apply_transformer_lists_with_exclusion (list tl1, list tl2)
 
list clean_up_transformer_list (list tfl)
 Eliminate empty transformers and keep at most one identity transformer, placed as first list element. More...
 
list two_transformers_to_list (transformer t1, transformer t2)
 Transformer two transformers into a correct transformer list. More...
 
transformer generic_transformer_list_to_transformer (list ltl, bool active_p)
 Reduce the transformer list with the convex hull operator. More...
 
transformer transformer_list_to_transformer (list ltl)
 Reduce the transformer list ltl to one transformer using the convex hull operator. More...
 
transformer active_transformer_list_to_transformer (list ltl)
 Reduce the sublist of active transformers in the transformer list ltl to one transformer using the convex hull operator. More...
 
list transformer_list_to_active_transformer_list (list tl)
 
static transformer transformer_list_closure_to_precondition_depth_two (list tl, transformer c_t, transformer p_0)
 Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose condition is modelized by transformer c_t. More...
 
static transformer transformer_list_closure_to_precondition_max_depth (list tl, transformer c_t, transformer p_0)
 Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose condition is modelized by transformer c_t. More...
 
transformer transformer_list_closure_to_precondition (list tl, transformer c_t, transformer p_0)
 Relay to select a heuristic. More...
 
list transformer_list_safe_variables_projection (list tl, list proj)
 Returns a new list of newly allocated projected transformers. More...
 
list transformer_list_to_argument (list tl)
 Returns the list of variables modified by at least one transformer in tl. More...
 
list transformer_list_with_effect (list tl, entity v)
 build a sublist sl of the transformer list tl with transformers that modify the value of variable v More...
 
list transformer_list_preserved_variables (list vl, list tl, list tl_v)
 returns the list of variables in vl which are not modified by transformers belonging to tl-tl_v. More...
 
transformer transformer_list_multiple_closure_to_precondition (list tl, transformer c_t, transformer p_0)
 When some variables are not modified by some transformers, use projections on subsets to increase the number of identity transformers and to increase the accuracy of the loop precondition. More...
 
Psysteme transformer_derivative_constraints (transformer t)
 Allocate a new constraint system sc(dx) with dx=x'-x and t(x,x') More...
 
transformer transformer_list_generic_transitive_closure (list tfl, bool star_p)
 Computation of an upper approximation of a transitive closure using constraints on the discrete derivative for a list of transformers. More...
 
transformer transformer_list_transitive_closure (list tfl)
 Compute (U tfl)*. More...
 
transformer transformer_list_transitive_closure_plus (list tfl)
 Compute (U tfl)+. More...
 
static list transformer_list_add_combination (int tn, transformer ta[tn], int n, transformer ct, int past)
 Internal recursive function. More...
 
static list __attribute__ ((unused))
 compute all combinations of n different transformers t from transformer list tl. More...
 

Function Documentation

◆ __attribute__()

static list __attribute__ ( (unused)  )
static

compute all combinations of n different transformers t from transformer list tl.

No check is performed on the content of list tl. Empty transformers and identity transformers should have been removed before this call.

Parameters
tla non-empty list of transformers

int n: a strictly positive integer, smaller than the length of tl

Definition at line 1226 of file transformer_list.c.

1227 {
1228  list cl = NIL;
1229  int tn = gen_length(tl);
1230 
1231  pips_assert("n is smaller than the number of transformers",
1232  n <= tn && n>=1 && n<=31);
1233 
1234  transformer ta[tn]; // build a transformer array
1235  int r = 0;
1236 
1237  FOREACH(TRANSFORMER, t, tl) {
1238  ta[r++] = t;
1239  }
1240 
1241  // Initialize recurrence
1243  cl = transformer_list_add_combination(tn, ta, n, ct, -1);
1244  free_transformer(ct);
1245 
1246  return cl;
1247 }
void free_transformer(transformer p)
Definition: ri.c:2616
transformer transformer_identity()
Allocate an identity transformer.
Definition: basic.c:110
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define 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 pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define TRANSFORMER(x)
TRANSFORMER.
Definition: ri.h:2841
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
static list transformer_list_add_combination(int tn, transformer ta[tn], int n, transformer ct, int past)
Internal recursive function.

References FOREACH, free_transformer(), gen_length(), NIL, pips_assert, TRANSFORMER, transformer_identity(), and transformer_list_add_combination().

+ Here is the call graph for this function:

◆ active_transformer_list_to_transformer()

transformer active_transformer_list_to_transformer ( list  ltl)

Reduce the sublist of active transformers in the transformer list ltl to one transformer using the convex hull operator.

An active transformer is a transformer with argument(s): at least one value is changed.

Note: a hidden identity transformer such as T(i) {i==i::init} is not detected.

Parameters
ltltl

Definition at line 447 of file transformer_list.c.

448 {
449  return generic_transformer_list_to_transformer(ltl, true);
450 }
transformer generic_transformer_list_to_transformer(list ltl, bool active_p)
Reduce the transformer list with the convex hull operator.

References generic_transformer_list_to_transformer().

Referenced by transformer_list_closure_to_precondition_depth_two(), transformer_list_closure_to_precondition_max_depth(), and whileloop_to_postcondition().

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

◆ apply_transformer_lists()

list apply_transformer_lists ( list  tl1,
list  tl2 
)
Parameters
tl1l1
tl2l2

Definition at line 269 of file transformer_list.c.

270 {
271  return apply_transformer_lists_generic(tl1, tl2, false);
272 }
list apply_transformer_lists_generic(list tl1, list tl2, bool exclude_p)
each transformer of tl1 must be applied to each precondition of tl2, including the identity transform...

References apply_transformer_lists_generic().

+ Here is the call graph for this function:

◆ apply_transformer_lists_generic()

list apply_transformer_lists_generic ( list  tl1,
list  tl2,
bool  exclude_p 
)

each transformer of tl1 must be applied to each precondition of tl2, including the identity transformer.

If an identity transformer is generated and if identity transformers are always first in the list, it will again be first in the returned list. Empty preconditions are not preserved in the returned list. An empty list is unfeasible.

if exclude_p==false, return U_i1 U_i2 apply(t_i1, p_i2); else return U_i1 U_i2!=i1 apply(t_i1, p_i2);

Parameters
tl1l1
tl2l2
exclude_pxclude_p

Definition at line 223 of file transformer_list.c.

224 {
225  list ntl = NIL;
226  int n1 = gen_length(tl1);
227  int n2 = gen_length(tl2);
228  int en = 0; // number of empty preconditions generated
229  int sn = 0; // number of excluded/skipped preconditions
230  int nn = -1; // number of preconditions in the result
231  int i1 = 0;
232 
233  // FI: not true is option keep_p has been used to maintain
234  //|tl_1|==|tl_2| which is useful when exclude_p is TRUE
235  if(!exclude_p) {
236  pips_assert("tl1 is OK\n", check_transformer_list(tl1));
237  pips_assert("tl2 is OK\n", check_transformer_list(tl2));
238  }
239 
240  FOREACH(TRANSFORMER, t1, tl1) {
241  int i2 = 0;
242  i1++;
243  FOREACH(TRANSFORMER, t2, tl2) {
244  i2++;
245  if(i1!=i2 && exclude_p) {
246  transformer nt = transformer_apply(t1, t2);
247 
248  if(!transformer_empty_p(nt))
249  ntl = CONS(TRANSFORMER, nt, ntl);
250  else
251  en++;
252  }
253  else if(exclude_p)
254  sn++;
255  }
256  }
257  ntl = gen_nreverse(ntl);
258 
259  nn = gen_length(ntl);
260  pips_assert("nn is n1*n2-en", nn==n1*n2-en-sn);
261  //FI: there is no guarantee here that the identity transformer is
262  //not returned multiple times... although it would make sense if the
263  //input lists are properly sorted.
264  pips_assert("ntl is OK\n", check_transformer_list(ntl));
265 
266  return ntl;
267 }
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
bool transformer_empty_p(transformer t)
If true is returned, the transformer certainly is empty.
Definition: transformer.c:2455
transformer transformer_apply(transformer tf, transformer pre)
transformer transformer_apply(transformer tf, transformer pre): apply transformer tf on precondition ...
Definition: transformer.c:1559
bool check_transformer_list(list tl)
What do we want to impose?

References check_transformer_list(), CONS, FOREACH, gen_length(), gen_nreverse(), NIL, pips_assert, TRANSFORMER, transformer_apply(), and transformer_empty_p().

Referenced by apply_transformer_lists(), and apply_transformer_lists_with_exclusion().

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

◆ apply_transformer_lists_with_exclusion()

list apply_transformer_lists_with_exclusion ( list  tl1,
list  tl2 
)
Parameters
tl1l1
tl2l2

Definition at line 274 of file transformer_list.c.

275 {
276  return apply_transformer_lists_generic(tl1, tl2, true);
277 }

References apply_transformer_lists_generic().

Referenced by transformer_list_closure_to_precondition_depth_two(), and transformer_list_closure_to_precondition_max_depth().

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

◆ check_transformer_list()

bool check_transformer_list ( list  tl)

What do we want to impose?

  1. Only one identity transformer
  2. Common basis?
  3. No empty transformer

The empty transformer list is used to represent the empty transformer...

It must be the first one

Parameters
tll

Definition at line 140 of file transformer_list.c.

141 {
142  bool identity_p = false;
143  // unused: bool one_p = false; // useless for the time being
144 
145  if(ENDP(tl)) {
146  /* The empty transformer list is used to represent the empty
147  transformer... */
148  ;
149  }
150  else {
151  FOREACH(TRANSFORMER, tf, tl) {
152  if(transformer_identity_p(tf)) {
153  if(identity_p) {
154  pips_internal_error("Two identity transformers in one list.");
155  }
156  else {
157  identity_p = true;
158  }
159  }
160  }
161  if(identity_p) {
162  /* It must be the first one */
164  pips_internal_error("The identity transformer is not the list header.");
165  }
166 
167  FOREACH(TRANSFORMER, tf, tl) {
168  if(transformer_empty_p(tf))
169  pips_internal_error("An empty transformer has been found.");
170  }
171  }
172 
173  return true;
174 }
bool transformer_identity_p(transformer t)
Check that t is an identity function.
Definition: basic.c:154
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
#define pips_internal_error
Definition: misc-local.h:149

References CAR, ENDP, FOREACH, pips_internal_error, TRANSFORMER, transformer_empty_p(), and transformer_identity_p().

Referenced by apply_transformer_lists_generic(), combine_transformer_lists(), and merge_transformer_lists().

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

◆ clean_up_transformer_list()

list clean_up_transformer_list ( list  tfl)

Eliminate empty transformers and keep at most one identity transformer, placed as first list element.

check_transformer_list(ntfl) should be TRUE.

tfl is fully destroyed (to avoid memory leaks and nightmares); to be more efficient, the transformers moved from the input list into the output list should be detached from the input list and then the input list could be fully destroyed without having to copy any transformers; but FOREACH operates at too high a level for this.

Parameters
tflfl

Definition at line 290 of file transformer_list.c.

291 {
292  list ntfl = NIL;
293  bool identity_p = false;
294 
295  FOREACH(TRANSFORMER, tf, tfl) {
296  bool tf_identity_p = transformer_identity_p(tf);
297  if(!tf_identity_p && !transformer_empty_p(tf))
298  ntfl = CONS(TRANSFORMER, copy_transformer(tf), ntfl);
299  identity_p = identity_p || tf_identity_p;
300  }
301  gen_full_free_list(tfl);
302  ntfl = gen_nreverse(ntfl);
303  if(identity_p)
304  ntfl = CONS(TRANSFORMER, transformer_identity(), ntfl);
305  return ntfl;
306 }
transformer copy_transformer(transformer p)
TRANSFORMER.
Definition: ri.c:2613
void gen_full_free_list(list l)
Definition: genClib.c:1023

References CONS, copy_transformer(), FOREACH, gen_full_free_list(), gen_nreverse(), NIL, TRANSFORMER, transformer_empty_p(), transformer_identity(), and transformer_identity_p().

Referenced by block_to_transformer_list().

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

◆ combine_transformer_lists()

list combine_transformer_lists ( list  tl1,
list  tl2 
)

each transformer of tl1 must be combined with a transformer of tl2, including the identity transformer.

If an identity transformer is generated and if identity transformers are always first in the list, it will again be first in the returned list.

Parameters
tl1l1
tl2l2

Definition at line 180 of file transformer_list.c.

181 {
182  list ntl = NIL;
183  int n1 = gen_length(tl1);
184  int n2 = gen_length(tl2);
185  int en = 0;
186  int nn = -1;
187 
188  pips_assert("tl1 is OK\n", check_transformer_list(tl1));
189  pips_assert("tl2 is OK\n", check_transformer_list(tl2));
190 
191  FOREACH(TRANSFORMER, t1, tl1) {
192  FOREACH(TRANSFORMER, t2, tl2) {
194 
195  // transformer_empty_p() is not strong enough currently
196  // It does not detect that k<= 2 && k>=3 is empty...
197  nt = transformer_normalize(nt, 2);
198  if(!transformer_empty_p(nt))
199  ntl = CONS(TRANSFORMER, nt, ntl);
200  else
201  en++;
202  }
203  }
204  ntl = gen_nreverse(ntl);
205 
206  nn = gen_length(ntl);
207  pips_assert("ntl is OK\n", check_transformer_list(ntl));
208  pips_assert("nn is n1*n2-en", nn==n1*n2-en);
209 
210  return ntl;
211 }
transformer transformer_normalize(transformer t, int level)
Eliminate (some) rational or integer redundancy.
Definition: transformer.c:932
transformer transformer_combine(volatile transformer t1, transformer t2)
transformer transformer_combine(transformer t1, transformer t2): compute the composition of transform...
Definition: transformer.c:238

References check_transformer_list(), CONS, copy_transformer(), FOREACH, gen_length(), gen_nreverse(), NIL, pips_assert, TRANSFORMER, transformer_combine(), transformer_empty_p(), and transformer_normalize().

Referenced by transformer_list_closure_to_precondition_depth_two(), and transformer_list_closure_to_precondition_max_depth().

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

◆ generic_transformer_list_to_transformer()

transformer generic_transformer_list_to_transformer ( list  ltl,
bool  active_p 
)

Reduce the transformer list with the convex hull operator.

If active_p is true, skip transformers that do not update the state. Beyond the identity transformer, any transformer without arguments does not really update the state, although it may restrict it.

A new transformer is always allocated. The transformers in the transformer list ltl are freed.

Look for the first useful transformer in the list

Only range conditions have been found: the store is restricted but not changed.

Take care of the following useful transformers

Look for the next useful transformer in the list

Parameters
ltltl
active_pctive_p

Definition at line 384 of file transformer_list.c.

385 {
386  transformer ltf = transformer_undefined; // list transformer
387 
388  if(ENDP(ltl))
389  ltf = transformer_empty();
390  else {
391  list ctl = ltl;
392  /* Look for the first useful transformer in the list */
393  FOREACH(TRANSFORMER, tf, ltl) {
394  if(!active_p || !ENDP(transformer_arguments(tf))) {
395  ltf = copy_transformer(tf);
396  free_transformer(tf);
397  POP(ctl);
398  break;
399  }
400  POP(ctl);
401  }
402  if(ENDP(ctl)) {
403  if(transformer_undefined_p(ltf))
404  /* Only range conditions have been found: the store is
405  restricted but not changed. */
406  ltf = transformer_identity();
407  }
408  else {
409  /* Take care of the following useful transformers */
410  while(!ENDP(ctl)) {
411  /* Look for the next useful transformer in the list */
412  FOREACH(TRANSFORMER, tf, ctl) {
413  if(!active_p || !ENDP(transformer_arguments(tf))) {
414  transformer ntf = copy_transformer(tf);
415  transformer ptf = ltf;
416  ltf = transformer_convex_hull(ptf, ntf);
417  free_transformer(ntf);
418  free_transformer(ptf);
419  POP(ctl);
420  break;
421  }
422  POP(ctl);
423  }
424  }
425  }
426  }
427 
428  return ltf;
429 }
transformer transformer_empty()
Allocate an empty transformer.
Definition: basic.c:120
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
#define transformer_undefined
Definition: ri.h:2847
#define transformer_undefined_p(x)
Definition: ri.h:2848
#define transformer_arguments(x)
Definition: ri.h:2871
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

References copy_transformer(), ENDP, FOREACH, free_transformer(), POP, TRANSFORMER, transformer_arguments, transformer_convex_hull(), transformer_empty(), transformer_identity(), transformer_undefined, and transformer_undefined_p.

Referenced by active_transformer_list_to_transformer(), and transformer_list_to_transformer().

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

◆ merge_transformer_lists()

list merge_transformer_lists ( list  tl1,
list  tl2 
)

Functions to deal with transformer lists.

transformer_list.c

Tansformer lists are used to delay convex hulls and to refine the precondition computation of loops by putting aside the identity transformer.

If there is an identity transformer in the list, it is supposed to be the first one in the list.

However, some control paths are almost identity transformers because the store is apparently unchanged. However, they contain predicates on the possible values. Although they have no arguments, and hence, the store is left unchanged, they are different from the identity transformer bebcause the relation is smaller.

So it should be up to the function using the transformer list to decide how to cope with transformers that restrict the identity transition. Must not be used, beware of library cycles: include "semantics.h" Union of two lists

If the list includes the identity transformer, it must be the first in the list and be nowehere else

It is not clear if transformer lists will be stored in hash tables... Hence I do not know if the input list should be freed, reused or left unshared. To be conservative, no alias is created.

Do we have to worry about different bases in transformers?

Too much information is sometimes lost with this simplification

Parameters
tl1l1
tl2l2

Definition at line 74 of file transformer_list.c.

75 {
76  list ntl = NIL;
77  list ntl1 = NIL;
78  list ntl2 = NIL;
79 
80  if(ENDP(tl1))
81  ntl = gen_full_copy_list(tl2);
82  else if(ENDP(tl2))
83  ntl = gen_full_copy_list(tl1);
84  else {
85  /* Do we have to worry about different bases in transformers? */
86  transformer t1 = TRANSFORMER(CAR(tl1));
87  transformer t2 = TRANSFORMER(CAR(tl2));
88 
89  /* Too much information is sometimes lost with this
90  simplification */
91  /*
92  if(ENDP(transformer_arguments(t1))) {
93  free_transformer(t1);
94  t1 = transformer_identity();
95  }
96 
97  if(ENDP(transformer_arguments(t2))) {
98  free_transformer(t2);
99  t2 = transformer_identity();
100  }
101  */
102 
105  }
106  if(transformer_identity_p(t1))
107  ntl1 = gen_full_copy_list(CDR(tl1));
108  else
109  ntl1 = gen_full_copy_list(tl1);
110  if(transformer_identity_p(t2))
111  ntl2 = gen_full_copy_list(CDR(tl2));
112  else
113  ntl2 = gen_full_copy_list(tl2);
114  ntl1 = gen_nconc(ntl1, ntl2);
115  ntl = gen_nconc(ntl, ntl1);
116  }
117 
118  ifdebug(1) {
119  int ntll = gen_length(ntl);
120  int tl1l = gen_length(tl1);
121  int tl2l = gen_length(tl2);
122  pips_assert("The new list is about the sum of the input lists.\n",
123  ntll>=tl1l+tl2l-1 && ntll<=tl1l+tl2l);
124  pips_assert("The new transformer list is legal",
126  }
127  return ntl;
128 }
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
#define ifdebug(n)
Definition: sg.c:47

References CAR, CDR, check_transformer_list(), CONS, ENDP, gen_full_copy_list(), gen_length(), gen_nconc(), ifdebug, NIL, pips_assert, TRANSFORMER, transformer_identity(), and transformer_identity_p().

Referenced by test_to_transformer_list().

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

◆ transformer_derivative_constraints()

Psysteme transformer_derivative_constraints ( transformer  t)

Allocate a new constraint system sc(dx) with dx=x'-x and t(x,x')

FI: this function should/might be located in fix_point.c

sc is going to be modified and returned

Do not handle variable which do not appear explicitly in constraints!

basis vector

Compute constraints with difference equations

Only generate difference equations if the old value is used

Project all variables but differences to get T'

Definition at line 891 of file transformer_list.c.

892 {
894  /* sc is going to be modified and returned */
895  /* Do not handle variable which do not appear explicitly in constraints! */
896  Pbase b = sc_to_minimal_basis(sc);
897  Pbase bv = BASE_NULLE; /* basis vector */
898 
899  /* Compute constraints with difference equations */
900 
901  for(bv = b; !BASE_NULLE_P(bv); bv = bv->succ) {
902  entity oldv = (entity) vecteur_var(bv);
903 
904  /* Only generate difference equations if the old value is used */
905  if(old_value_entity_p(oldv)) {
906  entity var = value_to_variable(oldv);
907  entity newv = entity_to_new_value(var);
909  Pvecteur diff = VECTEUR_NUL;
911 
912  diff = vect_make(diff,
913  (Variable) diffv, VALUE_ONE,
914  (Variable) newv, VALUE_MONE,
915  (Variable) oldv, VALUE_ONE,
916  TCST, VALUE_ZERO);
917 
918  eq = contrainte_make(diff);
919  sc = sc_equation_add(sc, eq);
920  }
921  }
922 
923  ifdebug(8) {
924  pips_debug(8, "with difference equations=\n");
925  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
926  }
927 
928  /* Project all variables but differences to get T' */
929 
930  sc = sc_projection_ofl_along_variables(sc, b);
931 
932  ifdebug(8) {
933  pips_debug(8, "Non-homogeneous constraints on derivatives=\n");
934  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
935  }
936 
937  return sc;
938 }
struct _newgen_struct_entity_ * entity
Definition: abc_private.h:14
#define VALUE_ZERO
#define VALUE_MONE
#define VALUE_ONE
#define CONTRAINTE_UNDEFINED
Pcontrainte contrainte_make(Pvecteur pv)
Pcontrainte contrainte_make(Pvecteur pv): allocation et initialisation d'une contrainte avec un vecte...
Definition: alloc.c:73
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define transformer_relation(x)
Definition: ri.h:2873
#define predicate_system(x)
Definition: ri.h:2069
Pbase sc_to_minimal_basis(Psysteme ps)
creation d'une base contenant toutes les variables apparaissant avec des coefficients non-nuls dans l...
Definition: sc_alloc.c:76
Psysteme sc_copy(Psysteme ps)
Psysteme sc_copy(Psysteme ps): duplication d'un systeme (allocation et copie complete des champs sans...
Definition: sc_alloc.c:230
Pcontrainte eq
element du vecteur colonne du systeme donne par l'analyse
Definition: sc_gram.c:108
Psysteme sc_equation_add(Psysteme sc, Pcontrainte c)
The basis of the constraint system is updated.
Definition: sc_insert_eq.c:101
void sc_fprint(FILE *fp, Psysteme ps, get_variable_name_t nom_var)
void sc_fprint(FILE * f, Psysteme ps, char * (*nom_var)()): cette fonction imprime dans le fichier po...
Definition: sc_io.c:220
le type des coefficients dans les vecteurs: Value est defini dans le package arithmetique
Definition: vecteur-local.h:89
struct Svecteur * succ
Definition: vecteur-local.h:92
const char * external_value_name(entity)
Definition: value.c:753
bool old_value_entity_p(entity)
Definition: value.c:936
entity entity_to_intermediate_value(entity)
Definition: value.c:879
entity entity_to_new_value(entity)
Definition: value.c:859
entity value_to_variable(entity)
Get the primitive variable associated to any value involved in a transformer.
Definition: value.c:1624
#define TCST
VARIABLE REPRESENTANT LE TERME CONSTANT.
#define vecteur_var(v)
#define VECTEUR_NUL
DEFINITION DU VECTEUR NUL.
void * Variable
arithmetique is a requirement for vecteur, but I do not want to inforce it in all pips files....
Definition: vecteur-local.h:60
#define BASE_NULLE
MACROS SUR LES BASES.
#define BASE_NULLE_P(b)
Pvecteur vect_make(Pvecteur v, Variable var, Value val,...)
Pvecteur vect_make(v, [var, val,]* 0, val) Pvecteur v; // may be NULL, use assigne anyway Variable va...
Definition: alloc.c:165

References BASE_NULLE, BASE_NULLE_P, contrainte_make(), CONTRAINTE_UNDEFINED, entity_to_intermediate_value(), entity_to_new_value(), eq, external_value_name(), ifdebug, old_value_entity_p(), pips_debug, predicate_system, sc_copy(), sc_equation_add(), sc_fprint(), sc_to_minimal_basis(), Svecteur::succ, TCST, transformer_relation, VALUE_MONE, VALUE_ONE, value_to_variable(), VALUE_ZERO, vect_make(), VECTEUR_NUL, and vecteur_var.

Referenced by transformer_list_generic_transitive_closure().

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

◆ transformer_list_add_combination()

static list transformer_list_add_combination ( int  tn,
transformer  ta[tn],
int  n,
transformer  ct,
int  past 
)
static

Internal recursive function.

Should be used as transformer_list_combination(). As long as n is not zero, choose all unused transformation numbers in past and call yourself recursively after updating past and ct. past is a bit field. Each bit of past is set to 1 initially because no transformer has been used yet. It is reset to 0 when the transformation has been used. The selected transformer is combined to ct.

Parameters
tnis the number of transformers that can be chosen to be combined
ta[tn]is an array containing the tn transformers to combine
nis the number of combinations to perform. It is less than tn.
ctis the current combination of past transformers
pastis a bit field used to keep track of transformers alreasy used to build ct
Returns
the list of all non-empty combinations of n transformers

Definition at line 1175 of file transformer_list.c.

1180 {
1181  list cl = NIL;
1182 
1183  if(n>0) {
1184  int k = 1; // to select a non-zero bit in past
1185  int ti; // transformation index
1186  bool found_p = false;
1187  for(ti=0; ti<n;ti++) {
1188  if(k&past) {
1189  // this transformation is selectable, because it has not been
1190  // selected yet
1191  int npast = past ^ k; // mark it as selected
1192  transformer t = ta[ti]; // to ease debugging
1194  // Necessary before checking emptiness
1195  nct = transformer_normalize(nct, 2);
1196  // Check the sequence feasability
1197  if(!transformer_empty_p(nct)) {
1198  list nl = transformer_list_add_combination(tn, ta, n-1, nct, npast);
1199  cl = gen_nconc(cl, nl);
1200  }
1201  found_p = true;
1202  free_transformer(nct);
1203  }
1204  k <<= 1;
1205  }
1206  pips_assert("At least one transformation has been found", found_p);
1207  }
1208  else {
1209  // The recursion is over, ct contains the right number of
1210  // transformer combinations
1211  cl = CONS(TRANSFORMER, ct, NIL);
1212  }
1213  return cl;
1214 }

References CONS, copy_transformer(), free_transformer(), gen_nconc(), NIL, pips_assert, TRANSFORMER, transformer_combine(), transformer_empty_p(), and transformer_normalize().

Referenced by __attribute__().

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

◆ transformer_list_closure_to_precondition()

transformer transformer_list_closure_to_precondition ( list  tl,
transformer  c_t,
transformer  p_0 
)

Relay to select a heuristic.

Parameters
tll
c_t_t
p_0_0

Definition at line 705 of file transformer_list.c.

708 {
710  const char* h = get_string_property("SEMANTICS_LIST_FIX_POINT_OPERATOR");
711 
712  if(strcmp(h, "depth_two")) {
714  }
715  else if(strcmp(h, "max_depth")) {
717  }
718  else
719  pips_user_error("Unknown value \"%s\" for property "
720  "\"SEMANTICS_LIST_FIX_POINT_OPERATOR\"", h);
721  pips_assert("prec is consistent", transformer_consistency_p(p_star));
722  return p_star;
723 }
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
char * get_string_property(const char *)
#define pips_user_error
Definition: misc-local.h:147
static transformer transformer_list_closure_to_precondition_max_depth(list tl, transformer c_t, transformer p_0)
Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose c...
static transformer transformer_list_closure_to_precondition_depth_two(list tl, transformer c_t, transformer p_0)
Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose c...

References get_string_property(), pips_assert, pips_user_error, transformer_consistency_p(), transformer_list_closure_to_precondition_depth_two(), transformer_list_closure_to_precondition_max_depth(), and transformer_undefined.

Referenced by transformer_list_multiple_closure_to_precondition().

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

◆ transformer_list_closure_to_precondition_depth_two()

static transformer transformer_list_closure_to_precondition_depth_two ( list  tl,
transformer  c_t,
transformer  p_0 
)
static

Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose condition is modelized by transformer c_t.

The precondition of iteration 0 is p_0.

We need a developped formulae for P*=(U_i T_i)^*P_0... to postpone the convex hulls as much as possible

For instance, and this is a heuristics:

P_0 is known as pre_init

P_1 = U_i T_i(P_0)

P_2 = U_i U_j T_i(T_j(P_0))

P_3^s = U_i T_i^+(P_0) — only one path is used

P_3^+ = U_i U_j!=i T^+_i(T_j(T^*(P_1))) — at least two paths are used

which would make more sense when i and j are in [0..1]. Note that in P_3, T_j and T^+_i could be recomputed wrt P_1 instead of pre_fuzzy... which is not provided

Maybe T^*=(U_i T_i)^* could/should be computed as (U_i T_i*)* but it is not clear how all the useful conditions could be taken into account.

A more accurate approach would use several developped formulae for P* and an intersection of their results.

Definition at line 501 of file transformer_list.c.

504 {
506 
507  list p_1_l = transformers_apply(ntl, p_0);
509 
510  list t_2_l = combine_transformer_lists(ntl, ntl);
511  list p_2_l = transformers_apply(t_2_l, p_0);
513 
514  list itcl = transformers_derivative_fix_point(ntl); // individual
515  // transformer closures
516  itcl = transformers_combine(itcl, c_t);
517  list itcl_plus = gen_full_copy_list(itcl); // to preserve ictl
518  itcl_plus = one_to_one_transformers_combine(itcl_plus, ntl);
519  list p_3_l = transformers_apply(itcl_plus, p_0);
521 
523  if(!get_bool_property("SEMANTICS_USE_DERIVATIVE_LIST")) {
524  // Not satisfying: works only for the whole space, not for subpaces
525  // left untouched
527  }
528  else
530  transformer p_4_1 = transformer_apply(t_star, p_1); // one + * iteration
531  list p_4_2_l = transformers_apply_and_keep_all(ntl, p_4_1); // another iteration
532  pips_assert("itcl_plus and p_4_2_l have the same numer of elements",
533  gen_length(itcl_plus)==gen_length(p_4_2_l));
534  list p_4_3_l = apply_transformer_lists_with_exclusion(itcl_plus, p_4_2_l);
536 
538 
539  ifdebug(8) {
540  pips_debug(8, "p_0:\n");
541  print_transformer(p_0);
542  pips_debug(8, "p_1:\n");
543  print_transformer(p_1);
544  pips_debug(8, "p_2:\n");
545  print_transformer(p_2);
546  pips_debug(8, "p_3:\n");
547  print_transformer(p_3);
548  pips_debug(8, "p_4:\n");
549  print_transformer(p_4);
550  }
551 
552  // reduce p_0, p_1, p_2, p_3 and p_4 to p_star
553  transformer p_01 = transformer_convex_hull(p_0, p_1);
554  transformer p_012 = transformer_convex_hull(p_01, p_2);
555  transformer p_0123 = transformer_convex_hull(p_012, p_3);
556  p_star = transformer_convex_hull(p_0123, p_4);
557 
558  ifdebug(8) {
559  pips_debug(8, "p_star:\n");
560  print_transformer(p_star);
561  }
562 
563  // Clean up all intermediate variables
564  gen_full_free_list(ntl);
565  //gen_full_free_list(p_1_l);
566  free_transformer(p_1);
567  //gen_full_free_list(t_2_l);
568  //gen_full_free_list(p_2_l);
569  free_transformer(p_2);
570  //gen_full_free_list(itcl);
571  gen_full_free_list(itcl_plus);
572  //gen_full_free_list(p_3_l);
573  free_transformer(p_3);
574  free_transformer(t_star);
575  free_transformer(p_4_1);
576  gen_full_free_list(p_4_2_l);
577  //gen_full_free_list(p_4_3_l);
578  free_transformer(p_4);
579  free_transformer(p_01);
580  free_transformer(p_012);
581  free_transformer(p_0123);
582  pips_assert("p_star is consistent", transformer_consistency_p(p_star));
583  return p_star;
584 }
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
list transformers_derivative_fix_point(list tl)
Definition: fix_point.c:1262
#define print_transformer(t)
Definition: print.c:357
list one_to_one_transformers_combine(list tl1, list tl2)
Combine each transformer of transformer list tl1 with the corresponding transformer in transformer li...
Definition: transformer.c:476
list transformers_combine(list tl1, transformer t2)
Combine each transformer of transformer list tl1 with t2.
Definition: transformer.c:454
list transformers_apply(list tl, transformer pre)
Same as previous one, but with a more normalized name.
Definition: transformer.c:1616
list transformers_apply_and_keep_all(list tl, transformer pre)
Same as previous one, but with a more normalized name.
Definition: transformer.c:1622
transformer transformer_list_to_transformer(list ltl)
Reduce the transformer list ltl to one transformer using the convex hull operator.
transformer transformer_list_transitive_closure(list tfl)
Compute (U tfl)*.
list apply_transformer_lists_with_exclusion(list tl1, list tl2)
list combine_transformer_lists(list tl1, list tl2)
each transformer of tl1 must be combined with a transformer of tl2, including the identity transforme...
transformer active_transformer_list_to_transformer(list ltl)
Reduce the sublist of active transformers in the transformer list ltl to one transformer using the co...

References active_transformer_list_to_transformer(), apply_transformer_lists_with_exclusion(), combine_transformer_lists(), free_transformer(), gen_full_copy_list(), gen_full_free_list(), gen_length(), get_bool_property(), ifdebug, one_to_one_transformers_combine(), pips_assert, pips_debug, print_transformer, transformer_apply(), transformer_consistency_p(), transformer_convex_hull(), transformer_list_to_transformer(), transformer_list_transitive_closure(), transformer_undefined, transformers_apply(), transformers_apply_and_keep_all(), transformers_combine(), and transformers_derivative_fix_point().

Referenced by transformer_list_closure_to_precondition().

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

◆ transformer_list_closure_to_precondition_max_depth()

static transformer transformer_list_closure_to_precondition_max_depth ( list  tl,
transformer  c_t,
transformer  p_0 
)
static

Compute the precondition of a loop whose body transformers T_i are in transformer list tl and whose condition is modelized by transformer c_t.

The precondition of iteration 0 is p_0.

We need a developped formulae for P*=(U_i T_i)^*P_0... to postpone the convex hulls as much as possible

For instance, and this is a heuristics:

P_0 is known as pre_init

P_l = U_i T_i(P_0)

P_2 = U_i U_j T_i(T_j(P_0))

P_3^s = U_i T_i^+(P_0) — only one path is used

P_3^+ = U_i U_j!=i T^+_i(T_j(T^*(P_1))) — at least two paths are used

which would make more sense when i and j are in [0..1]. Note that in P_3, T_j and T^+_i could be recomputed wrt P_1 instead of pre_fuzzy... which is not provided

Maybe T^*=(U_i T_i)^* could/should be computed as (U_i T_i*)* but it is not clear how all the useful conditions could be taken into account.

A more accurate approach would use several developped formulae for P* and an intersection of their results.

Definition at line 618 of file transformer_list.c.

621 {
623  //pips_assert("ntl is OK", check_transformer_list(ntl));
624 
625  list p_1_l = transformers_apply(ntl, p_0);
627 
628  list t_2_l = combine_transformer_lists(ntl, ntl);
629  list p_2_l = transformers_apply(t_2_l, p_0);
631 
632  list itcl = transformers_derivative_fix_point(ntl); // individual
633  // transformer closures
634  itcl = transformers_combine(itcl, c_t);
635  list itcl_plus = gen_full_copy_list(itcl); // to preserve ictl
636  itcl_plus = one_to_one_transformers_combine(itcl_plus, ntl);
637  list p_3_l = transformers_apply(itcl_plus, p_0);
639 
641  if(!get_bool_property("SEMANTICS_USE_DERIVATIVE_LIST")) {
642  // Not satisfying: works only for the whole space, not for subpaces
643  // left untouched
645  }
646  else
648  transformer p_4_1 = transformer_apply(t_star, p_1); // one + * iteration
649  list p_4_2_l = transformers_apply_and_keep_all(ntl, p_4_1); // another iteration
650  pips_assert("itcl_plus and p_4_2_l have the same numer of elements",
651  gen_length(itcl_plus)==gen_length(p_4_2_l));
652  list p_4_3_l = apply_transformer_lists_with_exclusion(itcl_plus, p_4_2_l);
654 
656 
657  ifdebug(8) {
658  pips_debug(8, "p_0:\n");
659  print_transformer(p_0);
660  pips_debug(8, "p_1:\n");
661  print_transformer(p_1);
662  pips_debug(8, "p_2:\n");
663  print_transformer(p_2);
664  pips_debug(8, "p_3:\n");
665  print_transformer(p_3);
666  pips_debug(8, "p_4:\n");
667  print_transformer(p_4);
668  }
669 
670  // reduce p_0, p_1, p_2, p_3 and p_4 to p_star
671  transformer p_01 = transformer_convex_hull(p_0, p_1);
672  transformer p_012 = transformer_convex_hull(p_01, p_2);
673  transformer p_0123 = transformer_convex_hull(p_012, p_3);
674  p_star = transformer_convex_hull(p_0123, p_4);
675 
676  ifdebug(8) {
677  pips_debug(8, "p_star:\n");
678  print_transformer(p_star);
679  }
680 
681  // Clean up all intermediate variables
682  gen_full_free_list(ntl);
683  //gen_full_free_list(p_1_l);
684  free_transformer(p_1);
685  //gen_full_free_list(t_2_l);
686  //gen_full_free_list(p_2_l);
687  free_transformer(p_2);
688  //gen_full_free_list(itcl);
689  gen_full_free_list(itcl_plus);
690  //gen_full_free_list(p_3_l);
691  free_transformer(p_3);
692  free_transformer(t_star);
693  free_transformer(p_4_1);
694  gen_full_free_list(p_4_2_l);
695  //gen_full_free_list(p_4_3_l);
696  free_transformer(p_4);
697  free_transformer(p_01);
698  free_transformer(p_012);
699  free_transformer(p_0123);
700 
701  return p_star;
702 }

References active_transformer_list_to_transformer(), apply_transformer_lists_with_exclusion(), combine_transformer_lists(), free_transformer(), gen_full_copy_list(), gen_full_free_list(), gen_length(), get_bool_property(), ifdebug, one_to_one_transformers_combine(), pips_assert, pips_debug, print_transformer, transformer_apply(), transformer_convex_hull(), transformer_list_to_transformer(), transformer_list_transitive_closure(), transformer_undefined, transformers_apply(), transformers_apply_and_keep_all(), transformers_combine(), and transformers_derivative_fix_point().

Referenced by transformer_list_closure_to_precondition().

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

◆ transformer_list_generic_transitive_closure()

transformer transformer_list_generic_transitive_closure ( list  tfl,
bool  star_p 
)

Computation of an upper approximation of a transitive closure using constraints on the discrete derivative for a list of transformers.

Each transformer is used to compute its derivative and the derivatives are unioned by convex hull.

The reason for doing this is D(T1) U D(T2) == D(T1 U T2) but the complexity is lower

See http://www.cri.ensmp.fr/classement/doc/A-429.pdf

Implicit equations, n::new - n::old = 0, are added because they are necessary for the convex hull.

Intermediate values are used to encode the differences. For instance, i::int = i::new - i::old This code was cut-and-pasted from transformer_derivative_fix_point() but is more general and subsume it transformer transformer_derivative_fix_point(transformer tf)

Since we compute the * transitive closure and not the + transitive closure, the fix point is the identity.

basis of difference vectors

Compute the global argument list and the global base b

Cannot use arguments_union() because a new list is allocated

For each transformer t in list tl

compute its derivative constraint system

add the equations for the unchanged variables

compute its convex hull with the current value of sc if sc is already defined

Add corresponding equation

This could be optimized by using the convex hull of a Psystemes list and by keeping the dual representation of the result instead of converting it several time back and forth.

Multiply the constant terms by the iteration number ik and add a positivity constraint for the iteration number ik and then eliminate the iteration number ik to get T*(dx).

Difference variables must substituted back to differences between old and new values.

Only generate difference equations if the old value is used

Project all difference variables

The full basis must be used again

Plug sc back into tc_tf

That's all!

Parameters
tflfl
star_ptar_p

Definition at line 960 of file transformer_list.c.

961 {
963 
964  ifdebug(8) {
965  pips_debug(8, "Begin for transformer list %p:\n", tfl);
966  print_transformers(tfl);
967  }
968 
969  if(ENDP(tfl)) {
970  if(star_p) {
971  /* Since we compute the * transitive closure and not the +
972  transitive closure, the fix point is the identity. */
973  tc_tf = transformer_identity();
974  }
975  else {
976  tc_tf = transformer_empty();
977  }
978  }
979  else {
980  // Pbase ib = base_dup(sc_base(sc)); /* initial and final basis */
981  Pbase ib = BASE_NULLE;
982  Pbase diffb = BASE_NULLE; /* basis of difference vectors */
983  Pbase bv = BASE_NULLE;
984  Pbase b = BASE_NULLE;
985 
986  /* Compute the global argument list and the global base b */
987  list gal = NIL;
988  FOREACH(TRANSFORMER, t, tfl) {
989  list al = transformer_arguments(t);
990  /* Cannot use arguments_union() because a new list is allocated */
991  FOREACH(ENTITY, e, al)
992  gal = arguments_add_entity(gal, e);
993 
994  // FI: this copy is almost entirely memory leaked
996  // redundant with call to transformer_derivative_constraints(t)
997  Pbase tb = sc_to_minimal_basis(sc);
998  Pbase nb = base_union(b, tb);
999  base_rm(b); // base_union() allocates a new base
1000  b = nb;
1001  }
1002 
1003  /* For each transformer t in list tl
1004  *
1005  * compute its derivative constraint system
1006  *
1007  * add the equations for the unchanged variables
1008  *
1009  * compute its convex hull with the current value of sc if sc is
1010  * already defined
1011  */
1012  Psysteme sc = SC_UNDEFINED;
1013  FOREACH(TRANSFORMER, t, tfl) {
1015  FOREACH(ENTITY,e,gal) {
1017  /* Add corresponding equation */
1019  Pvecteur diff = VECTEUR_NUL;
1021 
1022  diff = vect_make(diff,
1023  (Variable) diffv, VALUE_ONE,
1024  TCST, VALUE_ZERO);
1025 
1026  eq = contrainte_make(diff);
1027  tsc = sc_equation_add(tsc, eq);
1028  }
1029  }
1030  if(SC_UNDEFINED_P(sc))
1031  sc = tsc;
1032  else {
1033  /* This could be optimized by using the convex hull of a
1034  Psystemes list and by keeping the dual representation of
1035  the result instead of converting it several time back
1036  and forth. */
1037  Psysteme nsc = cute_convex_union(sc, tsc);
1038  sc_free(sc);
1039  sc = nsc;
1040  }
1041  }
1042 
1043  /* Multiply the constant terms by the iteration number ik and add a
1044  positivity constraint for the iteration number ik and then
1045  eliminate the iteration number ik to get T*(dx). */
1047  //Psysteme sc_t_prime_k = sc_dup(sc);
1048  //sc_t_prime_k = sc_multiply_constant_terms(sc_t_prime_k, (Variable) ik);
1049  sc = sc_multiply_constant_terms(sc, (Variable) ik, star_p);
1050  //Psysteme sc_t_prime_star = sc_projection_ofl(sc_t_prime_k, (Variable) ik);
1051  sc = sc_projection_ofl(sc, (Variable) ik);
1052  if(SC_EMPTY_P(sc)) {
1053  sc = sc_empty(BASE_NULLE);
1054  }
1055  else {
1056  sc->base = base_remove_variable(sc->base, (Variable) ik);
1057  sc->dimension--;
1058  // FI: I do not remember nor find how to get rid of local values...
1059  //sc_rm(sc);
1060  //sc = sc_t_prime_star;
1061  }
1062 
1063  ifdebug(8) {
1064  pips_debug(8, "All invariants on derivatives=\n");
1065  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
1066  }
1067 
1068  /* Difference variables must substituted back to differences
1069  * between old and new values.
1070  */
1071 
1072  for(bv = b; !BASE_NULLE_P(bv); bv = bv->succ) {
1073  entity oldv = (entity) vecteur_var(bv);
1074 
1075  /* Only generate difference equations if the old value is used */
1076  if(old_value_entity_p(oldv)) {
1077  entity var = value_to_variable(oldv);
1078  entity newv = entity_to_new_value(var);
1079  entity diffv = entity_to_intermediate_value(var);
1080  Pvecteur diff = VECTEUR_NUL;
1082 
1083  diff = vect_make(diff,
1084  (Variable) diffv, VALUE_ONE,
1085  (Variable) newv, VALUE_MONE,
1086  (Variable) oldv, VALUE_ONE,
1087  TCST, VALUE_ZERO);
1088 
1089  eq = contrainte_make(diff);
1090  sc = sc_equation_add(sc, eq);
1091  diffb = base_add_variable(diffb, (Variable) diffv);
1092  ib = base_add_variable(ib, (Variable) oldv);
1093  ib = base_add_variable(ib, (Variable) newv);
1094  }
1095  }
1096 
1097  ifdebug(8) {
1098  pips_debug(8,
1099  "All invariants on derivatives with difference variables=\n");
1100  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
1101  }
1102 
1103  /* Project all difference variables */
1104 
1105  sc = sc_projection_ofl_along_variables(sc, diffb);
1106 
1107  ifdebug(8) {
1108  pips_debug(8, "All invariants on differences=\n");
1109  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
1110  }
1111 
1112  /* The full basis must be used again */
1113  base_rm(sc_base(sc)), sc_base(sc) = BASE_NULLE;
1114  sc_base(sc) = ib;
1115  sc_dimension(sc) = vect_size(ib);
1116  base_rm(b), b = BASE_NULLE;
1117 
1118  ifdebug(8) {
1119  pips_debug(8, "All invariants with proper basis =\n");
1120  sc_fprint(stderr, sc, (char * (*)(Variable)) external_value_name);
1121  }
1122 
1123  /* Plug sc back into tc_tf */
1125  transformer_arguments(tc_tf) = gal;
1126 
1127  }
1128  /* That's all! */
1129 
1130  ifdebug(8) {
1131  pips_debug(8, "Transitive closure tc_tf=\n");
1134  pips_debug(8, "end\n");
1135  }
1136 
1137  return tc_tf;
1138 }
bool entity_is_argument_p(entity e, cons *args)
Definition: arguments.c:150
cons * arguments_add_entity(cons *a, entity e)
Definition: arguments.c:85
Pbase base_add_variable(Pbase b, Variable var)
Pbase base_add_variable(Pbase b, Variable v): add variable v as a new dimension to basis b at the end...
Definition: base.c:88
Pbase base_remove_variable(Pbase b, Variable v)
Pbase base_remove_variable(b, v): remove basis vector relative to v from b; abort if v is not in b;.
Definition: base.c:122
Pbase base_union(Pbase b1, Pbase b2)
Pbase base_union(Pbase b1, Pbase b2): compute a new basis containing all elements of b1 and all eleme...
Definition: base.c:428
Psysteme sc_multiply_constant_terms(Psysteme sc, Variable ik, bool star_p)
Specific for the derivative fix point: each constant term in the constraints is multiplied by ik whic...
Definition: fix_point.c:1013
int vect_size(Pvecteur v)
package vecteur - reductions
Definition: reductions.c:47
transformer fprint_transformer(FILE *fd, transformer tf, get_variable_name_t value_name)
Definition: io.c:69
list print_transformers(list tl)
Definition: io.c:62
Psysteme cute_convex_union(Psysteme s1, Psysteme s2)
debug messages before calling the version in polyedre.
Definition: convex_hull.c:41
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
Psysteme sc_empty(Pbase b)
Psysteme sc_empty(Pbase b): build a Psysteme with one unfeasible constraint to define the empty subsp...
Definition: sc_alloc.c:319
Psysteme sc_free(Psysteme in_ps)
Psysteme sc_free( in_ps ) AL 30/05/94 Free of in_ps.
Definition: sc_list.c:112
Pbase base
Definition: sc-local.h:75
int dimension
Definition: sc-local.h:74
entity make_local_temporary_integer_value_entity(void)
Definition: value.c:629
Psysteme transformer_derivative_constraints(transformer t)
Allocate a new constraint system sc(dx) with dx=x'-x and t(x,x')
char *(* get_variable_name_t)(Variable)
Definition: vecteur-local.h:62
#define base_rm(b)

References arguments_add_entity(), Ssysteme::base, base_add_variable(), BASE_NULLE, BASE_NULLE_P, base_remove_variable(), base_rm, base_union(), contrainte_make(), CONTRAINTE_UNDEFINED, cute_convex_union(), Ssysteme::dimension, ENDP, ENTITY, entity_is_argument_p(), entity_to_intermediate_value(), entity_to_new_value(), eq, external_value_name(), FOREACH, fprint_transformer(), ifdebug, make_local_temporary_integer_value_entity(), NIL, old_value_entity_p(), pips_debug, predicate_system, print_transformers(), sc_copy(), sc_empty(), sc_equation_add(), sc_fprint(), sc_free(), sc_multiply_constant_terms(), sc_to_minimal_basis(), Svecteur::succ, TCST, TRANSFORMER, transformer_arguments, transformer_consistency_p(), transformer_derivative_constraints(), transformer_empty(), transformer_identity(), transformer_relation, VALUE_MONE, VALUE_ONE, value_to_variable(), VALUE_ZERO, vect_make(), vect_size(), VECTEUR_NUL, and vecteur_var.

Referenced by transformer_list_transitive_closure(), and transformer_list_transitive_closure_plus().

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

◆ transformer_list_multiple_closure_to_precondition()

transformer transformer_list_multiple_closure_to_precondition ( list  tl,
transformer  c_t,
transformer  p_0 
)

When some variables are not modified by some transformers, use projections on subsets to increase the number of identity transformers and to increase the accuracy of the loop precondition.

The preconditions obtained with the different projections are intersected.

FI: this may be useless when derivatives are computed before the convex union. No. This was due to a bug in the computation of list of derivatives.

FI: this should be mathematically useless but it useful when a heuristic is used to compute the invariant. The number of transitions is reduced and hence a limited number of combinations is more likely to end up with a precise result.

Parameters
tll
c_t_t
p_0_0

Definition at line 826 of file transformer_list.c.

829 {
831 
832  if(get_bool_property("SEMANTICS_USE_LIST_PROJECTION")) {
833  list al = transformer_arguments(prec);
834  list vl = transformer_list_to_argument(tl); // list of modified
835  // variables
836  // FI: this is too strong vl must only be included in transformer_arguments(prec)
837  //pips_assert("all modified variables are argument of the global precondition",
838  //arguments_equal_p(vl, transformer_arguments(prec)));
839  FOREACH(ENTITY, v, vl) {
840  // FI: the same projection could be obtained for different
841  // variables v and the computation should not be performed again
842  // but I choose not to memoize past lists tl_v
843  list tl_v = transformer_list_with_effect(tl, v);
844 
845  if(gen_length(tl_v)<gen_length(tl)) {
846  list keep_v = transformer_list_preserved_variables(vl, tl, tl_v);
847  list proj_v = arguments_difference(vl, keep_v);
848  list ptl_v = transformer_list_safe_variables_projection(tl_v, proj_v);
849  transformer p_0_v
851  transformer c_t_v
853  transformer prec_v
854  = transformer_list_closure_to_precondition(ptl_v, c_t_v, p_0_v);
855  if(arguments_subset_p(transformer_arguments(prec_v), al)) {
856  // FI: this generates an inconsistent transformer if
857  // transformer_arguments(prec_v) is not a subset of al...
858  transformer_arguments(prec_v) = gen_copy_seq(al); // memory leak
859  }
860  else {
861  transformer n_prec_v = transformer_range(prec_v);
862  free_transformer(prec_v);
863  prec_v = n_prec_v;
864  transformer_arguments(prec_v) = gen_copy_seq(al);
865  }
866  prec = transformer_intersection(prec, prec_v); // memory leak
867  // transformer_intersection() returns an inconsistent transformer
868  // The argument list is empty but an old value is used in the conditions
869  // prec = transformer_range(prec); // memory leak
870  pips_assert("prec is consistent", transformer_consistent_p(prec));
871 
872  free_transformer(prec_v);
873  free_transformer(c_t_v);
874  free_transformer(p_0_v);
875  gen_full_free_list(ptl_v);
876  gen_free_list(keep_v);
877  }
878  gen_free_list(tl_v);
879  }
880 
881  gen_free_list(vl);
882  }
883  pips_assert("prec is consistent", transformer_consistency_p(prec));
884  return prec;
885 }
bool transformer_consistent_p(transformer p)
Definition: ri.c:2622
bool arguments_subset_p(list a1, list a2)
Check if a1 is a subset of a2.
Definition: arguments.c:204
cons * arguments_difference(cons *a1, cons *a2)
set difference: a1 - a2 ; similar to set intersection
Definition: arguments.c:233
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
transformer safe_transformer_projection(transformer t, list args)
t may be undefined, args may contain values unrelated to t
Definition: transformer.c:1187
transformer transformer_range(transformer tf)
Return the range of relation tf in a newly allocated transformer.
Definition: transformer.c:714
transformer transformer_intersection(transformer t1, transformer t2)
tf is a new transformer that receives the constraints in t1 and t2.
Definition: transformer.c:600
list transformer_list_with_effect(list tl, entity v)
build a sublist sl of the transformer list tl with transformers that modify the value of variable v
transformer transformer_list_closure_to_precondition(list tl, transformer c_t, transformer p_0)
Relay to select a heuristic.
list transformer_list_to_argument(list tl)
Returns the list of variables modified by at least one transformer in tl.
list transformer_list_preserved_variables(list vl, list tl, list tl_v)
returns the list of variables in vl which are not modified by transformers belonging to tl-tl_v.
list transformer_list_safe_variables_projection(list tl, list proj)
Returns a new list of newly allocated projected transformers.

References arguments_difference(), arguments_subset_p(), copy_transformer(), ENTITY, FOREACH, free_transformer(), gen_copy_seq(), gen_free_list(), gen_full_free_list(), gen_length(), get_bool_property(), pips_assert, safe_transformer_projection(), transformer_arguments, transformer_consistency_p(), transformer_consistent_p(), transformer_intersection(), transformer_list_closure_to_precondition(), transformer_list_preserved_variables(), transformer_list_safe_variables_projection(), transformer_list_to_argument(), transformer_list_with_effect(), and transformer_range().

Referenced by whileloop_to_postcondition().

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

◆ transformer_list_preserved_variables()

list transformer_list_preserved_variables ( list  vl,
list  tl,
list  tl_v 
)

returns the list of variables in vl which are not modified by transformers belonging to tl-tl_v.

tl_v is assumed to be a subset of tl.

Parameters
vll
tll
tl_vl_v

Definition at line 786 of file transformer_list.c.

787 {
788  list pvl = NIL;
789 
790  FOREACH(ENTITY, v, vl) {
791  bool found_p = false;
792  FOREACH(TRANSFORMER, t, tl) {
793  if(!gen_in_list_p(t, tl_v)) {
795  found_p = true;
796  break;
797  }
798  }
799  }
800  if(!found_p) {
801  pvl = CONS(ENTITY, v, pvl);
802  }
803  }
804 
805  pvl = gen_nreverse(pvl);
806 
807  return pvl;
808 }
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734

References CONS, ENTITY, entity_is_argument_p(), FOREACH, gen_in_list_p(), gen_nreverse(), NIL, TRANSFORMER, and transformer_arguments.

Referenced by transformer_list_multiple_closure_to_precondition().

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

◆ transformer_list_safe_variables_projection()

list transformer_list_safe_variables_projection ( list  tl,
list  proj 
)

Returns a new list of newly allocated projected transformers.

If a value of a variable in list proj appears in t of tl, it is projected. New transformers are allocated to build the projection list.

Parameters
tll
projroj

Definition at line 730 of file transformer_list.c.

731 {
732  list ptl = NIL;
733  FOREACH(TRANSFORMER, t, tl) {
734  list apl = NIL; // actual projection list
736  FOREACH(ENTITY, v, proj) {
738  entity ov = entity_to_old_value(v);
739  apl = CONS(ENTITY, ov, apl);
740  }
741  apl = CONS(ENTITY, v, apl);
742  }
743  nt = safe_transformer_projection(nt, apl);
744  ptl = CONS(TRANSFORMER, nt, ptl);
745  gen_free_list(apl);
746  }
747  ptl = gen_nreverse(ptl);
748  return ptl;
749 }
entity entity_to_old_value(entity)
Definition: value.c:869

References CONS, copy_transformer(), ENTITY, entity_is_argument_p(), entity_to_old_value(), FOREACH, gen_free_list(), gen_nreverse(), NIL, safe_transformer_projection(), TRANSFORMER, and transformer_arguments.

Referenced by transformer_list_multiple_closure_to_precondition().

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

◆ transformer_list_to_active_transformer_list()

list transformer_list_to_active_transformer_list ( list  tl)
Parameters
tll

Definition at line 454 of file transformer_list.c.

455 {
456  list atl = NIL;
457 
458  FOREACH(TRANSFORMER, tf, tl) {
459  if(!ENDP(transformer_arguments(tf)))
460  atl = CONS(TRANSFORMER, copy_transformer(tf), atl);
461  }
462 
463  atl = gen_nreverse(atl);
464 
465  return atl;
466 }

References CONS, copy_transformer(), ENDP, FOREACH, gen_nreverse(), NIL, TRANSFORMER, and transformer_arguments.

Referenced by whileloop_to_postcondition().

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

◆ transformer_list_to_argument()

list transformer_list_to_argument ( list  tl)

Returns the list of variables modified by at least one transformer in tl.

Parameters
tll

Definition at line 753 of file transformer_list.c.

754 {
755  list vl = NIL;
756 
757  FOREACH(TRANSFORMER, t, tl) {
759  if(!gen_in_list_p(v, vl))
760  vl = CONS(ENTITY, v, vl);
761  }
762  }
763 
764  vl = gen_nreverse(vl);
765 
766  return vl;
767 }

References CONS, ENTITY, FOREACH, gen_in_list_p(), gen_nreverse(), NIL, TRANSFORMER, and transformer_arguments.

Referenced by transformer_list_multiple_closure_to_precondition().

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

◆ transformer_list_to_transformer()

transformer transformer_list_to_transformer ( list  ltl)

Reduce the transformer list ltl to one transformer using the convex hull operator.

Parameters
ltltl

Definition at line 434 of file transformer_list.c.

435 {
436  return generic_transformer_list_to_transformer(ltl, false);
437 }

References generic_transformer_list_to_transformer().

Referenced by complete_any_loop_transformer(), complete_repeatloop_transformer(), new_complete_whileloop_transformer(), transformer_list_closure_to_precondition_depth_two(), and transformer_list_closure_to_precondition_max_depth().

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

◆ transformer_list_transitive_closure()

transformer transformer_list_transitive_closure ( list  tfl)

Compute (U tfl)*.

Parameters
tflfl

Definition at line 1141 of file transformer_list.c.

1142 {
1144 }
transformer transformer_list_generic_transitive_closure(list tfl, bool star_p)
Computation of an upper approximation of a transitive closure using constraints on the discrete deriv...

References transformer_list_generic_transitive_closure().

Referenced by transformer_list_closure_to_precondition_depth_two(), transformer_list_closure_to_precondition_max_depth(), and unstructured_to_flow_insensitive_transformer().

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

◆ transformer_list_transitive_closure_plus()

transformer transformer_list_transitive_closure_plus ( list  tfl)

Compute (U tfl)+.

Parameters
tflfl

Definition at line 1147 of file transformer_list.c.

1148 {
1150 }

References transformer_list_generic_transitive_closure().

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:

◆ transformer_list_with_effect()

list transformer_list_with_effect ( list  tl,
entity  v 
)

build a sublist sl of the transformer list tl with transformers that modify the value of variable v

Parameters
tll

Definition at line 771 of file transformer_list.c.

772 {
773  list sl = NIL;
774 
775  FOREACH(TRANSFORMER, t, tl){
777  sl = CONS(TRANSFORMER, t, sl);
778  }
779  sl = gen_nreverse(sl);
780  return sl;
781 }

References CONS, entity_is_argument_p(), FOREACH, gen_nreverse(), NIL, TRANSFORMER, and transformer_arguments.

Referenced by transformer_list_multiple_closure_to_precondition().

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

◆ two_transformers_to_list()

list two_transformers_to_list ( transformer  t1,
transformer  t2 
)

Transformer two transformers into a correct transformer list.

Could be generalized to any number of transformers using a varargs... and more thinking.

Two transformers are obtained for loops that may be skipped or entered and for tests whose condition is not statically decidable.

This is a very dangerous step that should not always be taken. It is useful to ease the detection of identity paths, but it looses a lot of information. So almost identity path might simply be better identified elsewhere

Parameters
t11
t22

Definition at line 316 of file transformer_list.c.

317 {
318  list tl = NIL;
319  if(transformer_empty_p(t1)) {
320  if(transformer_empty_p(t2)) {
321  tl = NIL;
322  }
323  else {
324  tl = CONS(TRANSFORMER, t2, NIL);
325  }
326  }
327  else {
328  if(transformer_empty_p(t2)) {
329  tl = CONS(TRANSFORMER, t1, NIL);
330  }
331  else {
332 
333  /* This is a very dangerous step that should not always be
334  taken. It is useful to ease the detection of identity
335  paths, but it looses a lot of information. So almost
336  identity path might simply be better identified elsewhere */
337  /*
338  if(ENDP(transformer_arguments(t1))) {
339  free_transformer(t1);
340  t1 = transformer_identity();
341  }
342 
343  if(ENDP(transformer_arguments(t2))) {
344  free_transformer(t2);
345  t2 = transformer_identity();
346  }
347  */
348 
349  if(transformer_identity_p(t1)) {
350  if(transformer_identity_p(t2)) {
351  tl = CONS(TRANSFORMER, t1, NIL);
352  free_transformer(t2);
353  }
354  else {
355  tl = CONS(TRANSFORMER, t1,
356  CONS(TRANSFORMER, t2, NIL));
357  }
358  }
359  else {
360  if(transformer_identity_p(t2)) {
361  tl = CONS(TRANSFORMER, t2,
362  CONS(TRANSFORMER, t1, NIL));
363  }
364  else {
365  tl = CONS(TRANSFORMER, t1,
366  CONS(TRANSFORMER, t2, NIL));
367  }
368  }
369  }
370  }
371  return tl;
372 }

References CONS, free_transformer(), NIL, TRANSFORMER, transformer_empty_p(), and transformer_identity_p().

Referenced by complete_any_loop_transformer_list(), and complete_repeatloop_transformer_list().

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